From c551a76cedd42492ffd9c0858be10347ad8f6391 Mon Sep 17 00:00:00 2001 From: API Changelog Bot Date: Mon, 16 Mar 2026 16:50:04 +0800 Subject: [PATCH] =?UTF-8?q?changelog:=20522a737=20-=20feat:=20Knife4j?= =?UTF-8?q?=E7=BD=91=E5=85=B3=E6=96=87=E6=A1=A3=E4=BF=AE=E5=A4=8D=20+=20AI?= =?UTF-8?q?=20Bridge=E5=A2=9E=E5=BC=BA=20+=20bootstrap=E9=BB=98=E8=AE=A4Na?= =?UTF-8?q?cos=E6=94=B9=E6=9C=AC=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-03-16_522a737_feat_Knife4j.md | 33230 ++++++++++++++++ 1 file changed, 33230 insertions(+) create mode 100644 changelogs/2026-03/2026-03-16_522a737_feat_Knife4j.md diff --git a/changelogs/2026-03/2026-03-16_522a737_feat_Knife4j.md b/changelogs/2026-03/2026-03-16_522a737_feat_Knife4j.md new file mode 100644 index 0000000..78ad9f6 --- /dev/null +++ b/changelogs/2026-03/2026-03-16_522a737_feat_Knife4j.md @@ -0,0 +1,33230 @@ +# 接口变更记录 + +## 提交信息 + +| 项目 | 内容 | +|------|------| +| **Hash** | `522a737928b06cb5114e815e08b7ee997075ce6d` | +| **作者** | wx | +| **时间** | 2026-03-16 16:50:04 +0800 | +| **说明** | feat: Knife4j网关文档修复 + AI Bridge增强 + bootstrap默认Nacos改本地 | + +## 变更文件总览 + +``` +A design-01-mengma-detail.jpg +A design-mengma-100pct.jpg +A design-mengma-detail.jpg +M docs/CLAUDE_WORKFLOW/CODE_STANDARDS.md +M docs/CLAUDE_WORKFLOW/architect/GUIDE.md +M docs/CLAUDE_WORKFLOW/qa/GUIDE.md +M docs/CLAUDE_WORKFLOW/reviewer/GUIDE.md +M docs/CLAUDE_WORKFLOW/senior-dev/GUIDE.md +M hl-callback-service/src/main/java/com/hulalv/callback/config/Knife4jConfig.java +M hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java +M hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java +M hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClient.java +M hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClientFallback.java +M hl-callback-service/src/main/java/com/hulalv/callback/handler/ApprovalEventHandler.java +M hl-callback-service/src/main/java/com/hulalv/callback/handler/ContactChangeHandler.java +M hl-callback-service/src/main/java/com/hulalv/callback/handler/ExternalContactHandler.java +M hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/InternalChatMessageController.java +M hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/MsgAuditController.java +M hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java +M hl-callback-service/src/main/resources/bootstrap.yml +M hl-common/src/main/java/com/hulalv/common/dto/AdminBasicDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/DepartmentDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/ExternalContactEventDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/FileBindRefsDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/FileUnbindRefsDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/OrderPayInfoDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/PaymentResultDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/RefundResultDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/ResourceDetailDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/TravelerValidationDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/WechatDeptSyncDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/WechatMessageDTO.java +M hl-common/src/main/java/com/hulalv/common/dto/WechatUserSyncDTO.java +M hl-common/src/main/java/com/hulalv/common/feign/MonitorFeignClient.java +M hl-common/src/main/java/com/hulalv/common/feign/MonitorFeignFallbackFactory.java +M hl-common/src/main/java/com/hulalv/common/feign/OrderRefundFeignClient.java +M hl-common/src/main/java/com/hulalv/common/feign/OrderRefundFeignFallbackFactory.java +M hl-common/src/main/java/com/hulalv/common/feign/ProductApprovalFeignClient.java +M hl-common/src/main/java/com/hulalv/common/feign/ProductApprovalFeignFallbackFactory.java +M hl-common/src/main/java/com/hulalv/common/feign/ResourceApprovalFeignClient.java +M hl-common/src/main/java/com/hulalv/common/feign/ResourceApprovalFeignFallbackFactory.java +M hl-common/src/main/java/com/hulalv/common/weather/AmapWeatherClient.java +M hl-contract-service/src/main/java/com/hulalv/contract/config/Knife4jConfig.java +M hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java +M hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java +M hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java +M hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java +M hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java +M hl-contract-service/src/main/resources/bootstrap.yml +M hl-file-service/src/main/java/com/hulalv/file/config/Knife4jConfig.java +M hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java +M hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java +M hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java +M hl-file-service/src/main/resources/bootstrap.yml +A hl-gateway/src/main/java/com/hulalv/gateway/config/WebResourceConfig.java +M hl-gateway/src/main/resources/bootstrap.yml +M hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java +M hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java +M hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java +M hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java +M hl-guide-service/src/main/resources/bootstrap.yml +M hl-insurance-service/src/main/java/com/hulalv/insurance/config/Knife4jConfig.java +M hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java +M hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java +M hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java +M hl-insurance-service/src/main/resources/bootstrap.yml +M hl-material-service/src/main/java/com/hulalv/material/config/Knife4jConfig.java +M hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java +M hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java +M hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java +M hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java +M hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java +M hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java +M hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java +M hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java +M hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java +M hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java +M hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java +M hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java +M hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java +M hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java +M hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java +M hl-material-service/src/main/resources/bootstrap.yml +M hl-monitor-service/src/main/java/com/hulalv/monitor/config/Knife4jConfig.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java +M hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java +M hl-monitor-service/src/main/resources/bootstrap.yml +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java +M hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java +M hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignClient.java +M hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignFallbackFactory.java +M hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignClient.java +M hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignFallbackFactory.java +M hl-mp-service/src/main/resources/bootstrap.yml +M hl-order-service/src/main/java/com/hulalv/order/config/Knife4jConfig.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java +M hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java +M hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java +M hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java +M hl-order-service/src/main/java/com/hulalv/order/service/WeatherService.java +M hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java +M hl-order-service/src/main/resources/bootstrap.yml +M hl-payment-service/src/main/java/com/hulalv/payment/config/Knife4jConfig.java +M hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java +M hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java +M hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java +M hl-payment-service/src/main/resources/bootstrap.yml +M hl-product-service/src/main/java/com/hulalv/product/config/Knife4jConfig.java +M hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java +M hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java +M hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java +M hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java +M hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java +M hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java +M hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java +M hl-product-service/src/main/resources/bootstrap.yml +M hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java +M hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java +M hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java +M hl-resource-service/src/main/java/com/hulalv/resource/config/Knife4jConfig.java +M hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java +M hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java +M hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java +M hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java +M hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java +M hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java +M hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java +M hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java +M hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java +M hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java +M hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java +M hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java +M hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java +M hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java +M hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java +M hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java +M hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java +M hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java +M hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java +M hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java +M hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java +M hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java +M hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java +M hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java +M hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java +M hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java +M hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java +M hl-resource-service/src/main/resources/bootstrap.yml +M hl-review-service/src/main/java/com/hulalv/review/config/Knife4jConfig.java +M hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java +M hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java +M hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java +M hl-review-service/src/main/resources/bootstrap.yml +M hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java +M hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java +M hl-task-service/src/main/resources/bootstrap.yml +M hl-user-service/src/main/java/com/hulalv/user/config/Knife4jConfig.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java +M hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java +M hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java +M hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java +M hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java +M hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java +M hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java +M hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java +M hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java +M hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java +M hl-user-service/src/main/java/com/hulalv/user/service/SysJobService.java +M hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java +M hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java +M hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java +A hl-user-service/src/main/java/com/hulalv/user/vo/SysJobLogVO.java +A hl-user-service/src/main/java/com/hulalv/user/vo/SysJobVO.java +M hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java +M hl-user-service/src/main/resources/bootstrap.yml +M hl-user-service/src/test/java/com/hulalv/user/service/SysJobServiceTest.java +A mastergo-overview.jpg +A scripts/ai-bridge/ai_bridge.py +A scripts/ai-bridge/ai_bridge.service +A scripts/ai-bridge/mg-mengma-detail.jpg +A scripts/ai-bridge/mg-preview.jpg +A scripts/ai-bridge/setup.sh +A scripts/ai-bridge/state.json +A scripts/api-changelog-sync.sh +A sql/add_customer_service_role.sql +M sql/dict_data_seed.sql +A sql/dict_fix_frontend.sql +``` + +## Controller 接口变更 + +### `hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java b/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java +index a9d6ea9..adf49be 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java +@@ -21,7 +21,7 @@ import java.util.concurrent.Executors; + * 路径: /callback/msg-audit + */ + @Slf4j +-@Api(tags = "【回调接口】会话内容存档") ++@Api(tags = "【回调接口】会话内容存档", hidden = true) + @RestController + @RequestMapping("/callback") + public class MsgAuditCallbackController { +@@ -59,7 +59,8 @@ public class MsgAuditCallbackController { + * URL 验证端点。 + * 企业微信配置回调 URL 时发送 GET 请求验证,需解密 echostr 并返回明文。 + */ +- @ApiOperation("会话内容存档回调URL验证") ++ @ApiOperation(value = "会话内容存档回调URL验证", ++ notes = "企业微信会话内容存档的回调URL验证端点。使用独立的Token/AESKey,在企微后台配置会话存档回调URL时进行验证。") + @GetMapping(value = "/msg-audit", produces = MediaType.TEXT_PLAIN_VALUE) + public String verifyUrl( + @RequestParam("msg_signature") String msgSignature, +@@ -89,7 +90,8 @@ public class MsgAuditCallbackController { + * 企业微信在有新的存档消息时 POST 加密 XML 事件通知。 + * 通知仅表示"有新消息可拉取",具体消息内容需通过 API 主动拉取。 + */ +- @ApiOperation("接收会话内容存档事件通知") ++ @ApiOperation(value = "接收会话内容存档事件通知", ++ notes = "企业微信在有新的存档消息时推送事件通知到此端点。通知仅表示'有新消息可拉取',收到后异步触发消息拉取任务(通过Finance SDK API主动拉取具体内容并存储)。必须5秒内返回'success'。") + @PostMapping(value = "/msg-audit", + consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE}, + produces = MediaType.TEXT_PLAIN_VALUE) +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java b/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java +index cad043a..0b1d68b 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java +@@ -27,7 +27,7 @@ import java.io.StringReader; + * No JWT auth required - uses WeChat's own signature verification. + */ + @Slf4j +-@Api(tags = "【回调接口】企业微信回调") ++@Api(tags = "【回调接口】企业微信回调", hidden = true) + @RestController + @RequestMapping("/wx/callback") + public class WxCallbackController { +@@ -88,7 +88,8 @@ public class WxCallbackController { + * WeChat sends GET request to verify the callback URL. + * Must decrypt echostr and return it as plain text. + */ +- @ApiOperation("Callback URL verification") ++ @ApiOperation(value = "回调URL验证", ++ notes = "企业微信自建应用的回调URL验证端点。企微在配置回调URL时发送GET请求,需解密echostr并返回明文以完成验证。无需JWT认证,使用企微自有的签名校验机制。") + @GetMapping(value = "/app", produces = MediaType.TEXT_PLAIN_VALUE) + public String verifyUrl( + @RequestParam("msg_signature") String msgSignature, +@@ -118,7 +119,8 @@ public class WxCallbackController { + * WeChat POSTs encrypted XML for all event types. + * We decrypt, parse, dispatch to handler, and return "success". + */ +- @ApiOperation("Receive callback events") ++ @ApiOperation(value = "接收回调事件", ++ notes = "企业微信自建应用的事件接收端点。接收加密XML格式的事件通知(审批变更、消息等),解密后按事件类型分发:change_contact→通讯录变更,change_external_contact→外部联系人变更,open_approval_change→审批状态变更。必须5秒内返回'success'。") + @PostMapping(value = "/app", + consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE}, + produces = MediaType.TEXT_PLAIN_VALUE) +@@ -162,7 +164,8 @@ public class WxCallbackController { + // Contact Sync Callback Endpoints + // ========================================== + +- @ApiOperation("Contact sync URL verification") ++ @ApiOperation(value = "联系人同步URL验证", ++ notes = "企业微信通讯录同步的回调URL验证端点。使用独立的Token/AESKey(与应用回调不同),用于接收通讯录变更事件的回调URL配置验证。") + @GetMapping(value = "/contacts", produces = MediaType.TEXT_PLAIN_VALUE) + public String verifyContactsUrl( + @RequestParam("msg_signature") String msgSignature, +@@ -187,7 +190,8 @@ public class WxCallbackController { + return result; + } + +- @ApiOperation("Receive contact sync events") ++ @ApiOperation(value = "接收联系人同步事件", ++ notes = "企业微信通讯录变更事件接收端点。接收员工创建/更新/删除、部门变更等事件,解密后转发给ContactChangeHandler处理,同步更新本地管理员数据。必须5秒内返回'success'。") + @PostMapping(value = "/contacts", + consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE}, + produces = MediaType.TEXT_PLAIN_VALUE) +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java +index f955c57..91ac6ed 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java +@@ -21,31 +21,33 @@ public class AdminClauseTemplateController { + + private final ClauseTemplateService clauseTemplateService; + +- @ApiOperation("获取启用的补充约定模板列表(创建合同用)") ++ @ApiOperation(value = "获取启用的补充约定模板列表(创建合同用)", ++ notes = "返回所有启用状态的补充约定模板,创建合同时选择需要附加的补充约定条款。\n\n**权限**:需管理员登录。") + @GetMapping("/list") + public Result> listActive() { + return Result.success(clauseTemplateService.listActive()); + } + +- @ApiOperation("获取全部补充约定模板(管理页用)") ++ @ApiOperation(value = "获取全部补充约定模板(管理页用)", notes = "**关联字典**:\n- common_status:通用状态(列表显示,ACTIVE=启用/INACTIVE=停用)") + @GetMapping("/list-all") + public Result> listAll() { + return Result.success(clauseTemplateService.listAll()); + } + +- @ApiOperation("切换模板启用/停用状态") ++ @ApiOperation(value = "切换模板启用/停用状态", notes = "**关联字典**:\n- common_status:通用状态(状态切换,ACTIVE=启用/INACTIVE=停用)") + @PutMapping("/{id}/toggle-status") + public Result toggleStatus(@ApiParam("模板ID") @PathVariable("id") Long templateId) { + return Result.success(clauseTemplateService.toggleStatus(templateId)); + } + +- @ApiOperation("创建补充约定模板") ++ @ApiOperation(value = "创建补充约定模板", notes = "创建合同补充约定的模板,支持变量占位符。创建后默认启用") + @PostMapping + public Result create(@Valid @RequestBody ClauseTemplateRequest request) { + return Result.success(clauseTemplateService.create(request)); + } + +- @ApiOperation("更新补充约定模板") ++ @ApiOperation(value = "更新补充约定模板", ++ notes = "更新模板的标题和内容。已被合同引用的模板更新不影响已创建的合同(合同记录的是快照内容)。\n\n**权限**:需管理员登录。") + @PutMapping("/{id}") + public Result update( + @ApiParam("模板ID") @PathVariable("id") Long templateId, +@@ -53,7 +55,7 @@ public class AdminClauseTemplateController { + return Result.success(clauseTemplateService.update(templateId, request)); + } + +- @ApiOperation("删除补充约定模板") ++ @ApiOperation(value = "删除补充约定模板", notes = "软删除模板。已被合同引用的模板仍可删除,不影响已创建的合同") + @DeleteMapping("/{id}") + public Result delete(@ApiParam("模板ID") @PathVariable("id") Long templateId) { + clauseTemplateService.delete(templateId); +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java +index a6a6dbe..437717e 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java +@@ -30,19 +30,20 @@ public class AdminContractController { + + private final ContractService contractService; + +- @ApiOperation("可用旅行社列表") ++ @ApiOperation(value = "可用旅行社列表", notes = "返回系统配置的旅行社列表,创建合同时选择签约旅行社") + @GetMapping("/agencies") + public Result> listAgencies() { + return Result.success(contractService.listAgencies()); + } + +- @ApiOperation("合同模板列表") ++ @ApiOperation(value = "合同模板列表", notes = "返回合同平台可用的合同模板列表,创建合同时选择模板") + @GetMapping("/templates") + public Result> listTemplates() { + return Result.success(contractService.listTemplates()); + } + +- @ApiOperation("创建合同(标准模式)") ++ @ApiOperation(value = "创建合同(标准模式)", notes = "标准电子签约流程:创建合同 → 平台生成合同PDF → 发送签署短信给出行人 → 出行人在线签署 → 回调更新状态。" ++ + "状态流转:CREATED → SIGNING → SIGNED") + @PostMapping("/create") + public Result createContract( + @ApiParam("创建合同请求") @Valid @RequestBody CreateContractRequest request, +@@ -51,7 +52,8 @@ public class AdminContractController { + return Result.success(contractService.createContract(request, adminId)); + } + +- @ApiOperation("报备合同(同步模式)") ++ @ApiOperation(value = "报备合同(同步模式)", notes = "线下签约模式:创建合同记录 → 管理员上传已签署的PDF → 同步到12301报备平台。" ++ + "状态流转:CREATED → UPLOADED → REPORTED") + @PostMapping("/report") + public Result reportContract( + @ApiParam("报备合同请求") @Valid @RequestBody ReportContractRequest request, +@@ -60,49 +62,51 @@ public class AdminContractController { + return Result.success(contractService.reportContract(request, adminId)); + } + +- @ApiOperation("合同列表") ++ @ApiOperation(value = "合同列表", notes = "分页查询合同记录,支持按订单号、合同状态、旅行社筛选\n\n**关联字典**:\n- contract_status:合同状态(列表筛选+显示)") + @GetMapping("/list") + public Result> listContracts(@ApiParam("合同查询条件") ContractQueryRequest request) { + return Result.success(contractService.listContracts(request)); + } + +- @ApiOperation("合同详情") ++ @ApiOperation(value = "合同详情", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/{id}") + public Result getContractDetail(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.getContractDetail(contractId)); + } + +- @ApiOperation("按订单查询合同") ++ @ApiOperation(value = "按订单查询合同", ++ notes = "查询指定订单下的所有合同记录(含已作废),按创建时间倒序排列。用于订单详情页展示合同历史。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- contract_status:合同状态(列表显示)") + @GetMapping("/by-order/{orderId}") + public Result> getByOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(contractService.getByOrderId(orderId)); + } + +- @ApiOperation("获取订单有效合同") ++ @ApiOperation(value = "获取订单有效合同", ++ notes = "返回订单当前有效的合同(非作废状态的最新合同),用于检查订单是否已有签署中或已签署的合同。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/active-by-order/{orderId}") + public Result getActiveByOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(contractService.getActiveContractByOrderId(orderId)); + } + +- @ApiOperation("刷新合同状态(从平台同步)") ++ @ApiOperation(value = "刷新合同状态(从平台同步)", notes = "主动查询合同平台的最新签署状态并同步到本地,适用于回调未到达的场景") + @GetMapping("/{id}/status") + public Result refreshStatus(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.refreshStatus(contractId)); + } + +- @ApiOperation("作废合同") ++ @ApiOperation(value = "作废合同", notes = "将合同标记为作废状态(不可恢复)。作废后该合同不再有效,可重新为订单创建新合同") + @PostMapping("/{id}/invalidate") + public Result invalidateContract(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.invalidateContract(contractId)); + } + +- @ApiOperation("重发签署短信") ++ @ApiOperation(value = "重发签署短信", notes = "重新发送签署短信给出行人,用于签署短信过期或未收到的场景。仅SIGNING状态的合同可操作") + @PostMapping("/{id}/resend-sms") + public Result resendSms(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.resendSms(contractId)); + } + +- @ApiOperation("上传已签署PDF(同步模式)") ++ @ApiOperation(value = "上传已签署PDF(同步模式)", notes = "同步模式专用:上传线下签署完成的合同PDF文件,上传后合同状态变为UPLOADED,可进一步报备") + @PostMapping("/{id}/upload-pdf") + public Result uploadPdf( + @ApiParam("合同ID") @PathVariable("id") Long contractId, +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java +index 8415d27..bad13a5 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + + import javax.validation.Valid; + +-@Api(tags = "【回调接口】合同回调") ++@Api(tags = "【回调接口】合同回调", hidden = true) + @Slf4j + @RestController + @RequestMapping("/contract/callback") +@@ -20,7 +20,7 @@ public class ContractCallbackController { + + private final ContractCallbackService callbackService; + +- @ApiOperation("12301合同状态回调") ++ @ApiOperation(value = "12301合同状态回调", notes = "接收12301全国旅游监管平台的合同签署状态回调。出行人签署完成后平台推送状态变更到此接口,自动更新本地合同状态") + @PostMapping("/12301") + public ResponseEntity handle12301Callback(@Valid @RequestBody ContractCallbackPayload payload) { + log.info("Received 12301 callback: contractNumber={}, state={}", +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java +index 8929f18..3c25a33 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】合同(Feign调用)") ++@Api(tags = "【内部接口】合同(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/contract") + @RequiredArgsConstructor +@@ -19,19 +19,19 @@ public class InternalContractController { + + private final ContractService contractService; + +- @ApiOperation("按订单查询合同(内部调用)") ++ @ApiOperation(value = "按订单查询合同(内部调用)", notes = "**关联字典**:\n- contract_status:合同状态(返回字段)") + @GetMapping("/by-order/{orderId}") + public Result> getByOrder(@PathVariable Long orderId) { + return Result.success(contractService.getByOrderId(orderId)); + } + +- @ApiOperation("按订单批量查询合同(内部调用)") ++ @ApiOperation(value = "按订单批量查询合同(内部调用)", notes = "**关联字典**:\n- contract_status:合同状态(返回字段)") + @PostMapping("/by-orders") + public Result>> getByOrders(@RequestBody List orderIds) { + return Result.success(contractService.getByOrderIds(orderIds)); + } + +- @ApiOperation("检查订单是否有已签署合同(内部调用)") ++ @ApiOperation(value = "检查订单是否有已签署合同(内部调用)", notes = "检查订单是否存在有效签署的合同(SIGNED/REPORTED/UPLOADED状态),用于订单流程中的合同校验") + @GetMapping("/has-signed/{orderId}") + public Result hasSigned(@PathVariable Long orderId) { + List contracts = contractService.getByOrderId(orderId); +@@ -41,7 +41,7 @@ public class InternalContractController { + return Result.success(signed); + } + +- @ApiOperation("按订单作废所有有效合同(级联调用)") ++ @ApiOperation(value = "按订单作废所有有效合同(级联调用)", notes = "订单取消或退款时级联作废该订单下所有有效合同,reason参数记录作废原因") + @PostMapping("/invalidate/{orderId}") + public Result invalidateByOrder(@PathVariable Long orderId, + @RequestParam(value = "reason", required = false) String reason) { +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java +index 90d323c..bbb5883 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java +@@ -16,7 +16,7 @@ import java.util.Map; + * C端合同内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序合同(Feign调用)") ++@Api(tags = "【内部接口】小程序合同(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/contract") + @RequiredArgsConstructor +@@ -24,7 +24,7 @@ public class InternalMpContractController { + + private final ContractService contractService; + +- @ApiOperation("用户合同列表") ++ @ApiOperation(value = "用户合同列表", notes = "**关联字典**:\n- contract_status:合同状态(列表筛选+显示)") + @GetMapping("/list") + public Result> listContracts( + @RequestParam Long userId, +@@ -34,7 +34,7 @@ public class InternalMpContractController { + return Result.success(contractService.listUserContracts(userId, status, page, pageSize)); + } + +- @ApiOperation("用户合同详情") ++ @ApiOperation(value = "用户合同详情", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/{id}") + public Result getContractDetail( + @PathVariable("id") Long contractId, +@@ -42,7 +42,7 @@ public class InternalMpContractController { + return Result.success(contractService.getUserContractDetail(contractId, userId)); + } + +- @ApiOperation("按订单查合同(返回最新有效合同)") ++ @ApiOperation(value = "按订单查合同(返回最新有效合同)", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}") + public Result getContractByOrder( + @PathVariable Long orderId, +@@ -50,7 +50,7 @@ public class InternalMpContractController { + return Result.success(contractService.getUserContractByOrderId(orderId, userId)); + } + +- @ApiOperation("按订单查所有有效合同(TOUR+INSURANCE各一条)") ++ @ApiOperation(value = "按订单查所有有效合同(TOUR+INSURANCE各一条)", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}/all") + public Result> getContractsByOrder( + @PathVariable Long orderId, +@@ -58,7 +58,8 @@ public class InternalMpContractController { + return Result.success(contractService.getUserContractsByOrderId(orderId, userId)); + } + +- @ApiOperation("重新发送合同签署短信") ++ @ApiOperation(value = "重新发送合同签署短信", ++ notes = "内部服务间调用。小程序端用户请求重发签署短信,用于签署链接过期或短信未收到的场景。仅SIGNING状态的合同可操作。\n\n**关联字典**:\n- contract_status:合同状态(仅SIGNING可操作)") + @PostMapping("/{contractId}/resend-sms") + public Result resendContractSms( + @PathVariable("contractId") Long contractId, +``` + +### `hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java b/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java +index 5b04b02..c78b2d2 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java +@@ -33,7 +33,7 @@ public class FileController { + private final FileService fileService; + private final FileRefService fileRefService; + +- @ApiOperation("请求上传凭证") ++ @ApiOperation(value = "请求上传凭证", notes = "上传流程第一步:前端请求上传凭证 → 获取OSS预签名URL和临时凭证 → 前端直传OSS → 调用确认上传接口。凭证有效期有限,过期需重新请求") + @OperationLog(value = "请求上传凭证", module = "文件管理") + @PostMapping("/upload/token") + public Result requestUploadToken( +@@ -44,7 +44,7 @@ public class FileController { + return Result.success(vo); + } + +- @ApiOperation("确认上传完成") ++ @ApiOperation(value = "确认上传完成", notes = "上传流程第二步:前端直传OSS完成后调用此接口,系统验证文件存在性并创建文件记录。支持MD5去重,相同文件不会重复存储") + @OperationLog(value = "确认上传", module = "文件管理") + @PostMapping("/upload/confirm") + public Result confirmUpload( +@@ -55,21 +55,21 @@ public class FileController { + return Result.success(vo); + } + +- @ApiOperation("文件列表(分页)") ++ @ApiOperation(value = "文件列表(分页)", notes = "支持按文件类型、分组、上传者等条件筛选,按上传时间倒序分页返回\n\n**关联字典**:\n- file_type:文件类型(列表筛选+显示)\n- file_status:文件状态(显示)") + @GetMapping("/list") + public Result> listFiles(@ApiParam("文件查询条件") @Valid FileQueryRequest request) { + IPage page = fileService.listFiles(request); + return Result.success(page); + } + +- @ApiOperation("文件详情") ++ @ApiOperation(value = "文件详情", notes = "**关联字典**:\n- file_type:文件类型(显示)\n- file_status:文件状态(显示)") + @GetMapping("/{fileId}") + public Result getFileDetail(@ApiParam("文件ID") @PathVariable Long fileId) { + FileVO vo = fileService.getFileDetail(fileId); + return Result.success(vo); + } + +- @ApiOperation("删除文件") ++ @ApiOperation(value = "删除文件", notes = "软删除文件记录,如果文件存在引用关系则不允许删除。OSS上的物理文件由定时任务清理") + @OperationLog(value = "删除文件", module = "文件管理") + @DeleteMapping("/{fileId}") + public Result deleteFile(@ApiParam("文件ID") @PathVariable Long fileId) { +@@ -77,21 +77,21 @@ public class FileController { + return Result.success(null); + } + +- @ApiOperation("文件引用列表") ++ @ApiOperation(value = "文件引用列表", notes = "查看文件被哪些业务实体引用(如景区封面、酒店图片等),用于判断文件是否可安全删除") + @GetMapping("/{fileId}/refs") + public Result> getFileRefs(@ApiParam("文件ID") @PathVariable Long fileId) { + List refs = fileRefService.getRefsByFileId(fileId); + return Result.success(refs); + } + +- @ApiOperation("存储统计") ++ @ApiOperation(value = "存储统计", notes = "返回文件总数、总存储空间、各类型文件占比等统计信息") + @GetMapping("/stats") + public Result getStats() { + FileStatsVO stats = fileService.getStats(); + return Result.success(stats); + } + +- @ApiOperation("文件内容流式预览") ++ @ApiOperation(value = "文件内容流式预览", notes = "流式输出文件内容,设置正确的Content-Type头,支持浏览器直接预览图片和PDF等文件") + @GetMapping("/{fileId}/preview") + public void previewContent(@ApiParam("文件ID") @PathVariable Long fileId, HttpServletResponse response) throws IOException { + fileService.streamContent(fileId, response); +``` + +### `hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java b/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java +index cf46b6b..3690ff3 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java +@@ -30,7 +30,7 @@ import org.springframework.web.multipart.MultipartFile; + import javax.validation.Valid; + import java.util.List; + +-@Api(tags = "【内部接口】文件(Feign调用)") ++@Api(tags = "【内部接口】文件(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/file") + @RequiredArgsConstructor +@@ -40,28 +40,30 @@ public class InternalFileController { + private final FileRefService fileRefService; + private final ChunkUploadService chunkUploadService; + +- @ApiOperation("绑定文件到业务实体") ++ @ApiOperation(value = "绑定文件到业务实体", notes = "将文件与业务实体建立引用关系(如景区ID+封面图),同一文件可被多个业务实体引用") + @PostMapping("/bindRefs") + public Result bindRefs(@Valid @RequestBody BindRefsRequest request) { + fileRefService.bindRefs(request.getBizType(), request.getBizId(), request.getFileIds()); + return Result.success(null); + } + +- @ApiOperation("解绑业务实体的所有文件") ++ @ApiOperation(value = "解绑业务实体的所有文件", notes = "删除指定业务类型+业务ID下的所有文件引用关系,常用于业务实体删除时的级联清理") + @PostMapping("/unbindRefs") + public Result unbindRefs(@Valid @RequestBody UnbindRefsRequest request) { + fileRefService.unbindRefs(request.getBizType(), request.getBizId()); + return Result.success(null); + } + +- @ApiOperation("批量获取文件信息") ++ @ApiOperation(value = "批量获取文件信息", ++ notes = "内部服务间调用。根据文件ID列表批量查询文件信息(含OSS URL、文件名、类型等),用于其他服务获取关联文件的详细数据。") + @PostMapping("/byIds") + public Result> getFilesByIds(@Valid @RequestBody BatchFileRequest request) { + List files = fileService.getFilesByIds(request.getFileIds()); + return Result.success(files); + } + +- @ApiOperation("内部上传凭证(素材服务调用)") ++ @ApiOperation(value = "内部上传凭证(素材服务调用)", ++ notes = "内部服务间调用。素材服务代理调用,为指定管理员生成OSS上传预签名URL和临时凭证,用于素材库的文件上传流程。") + @PostMapping("/upload/token") + public Result requestUploadTokenInternal( + @Valid @RequestBody UploadTokenRequest request, +@@ -69,7 +71,7 @@ public class InternalFileController { + return Result.success(fileService.requestUploadToken(request, adminId)); + } + +- @ApiOperation("内部直接上传文件(服务间调用)") ++ @ApiOperation(value = "内部直接上传文件(服务间调用)", notes = "服务间直接上传文件到OSS,跳过预签名流程。返回OSS公开访问URL,适用于后端生成的文件(如路线地图截图)") + @PostMapping("/upload/direct") + public Result uploadDirect( + @RequestParam("file") MultipartFile file, +@@ -78,7 +80,8 @@ public class InternalFileController { + return Result.success(vo.getOssUrl()); + } + +- @ApiOperation("内部确认上传(素材服务调用)") ++ @ApiOperation(value = "内部确认上传(素材服务调用)", ++ notes = "内部服务间调用。素材服务代理调用,确认文件已上传至OSS并创建文件记录。支持MD5去重。") + @PostMapping("/upload/confirm") + public Result confirmUploadInternal( + @Valid @RequestBody UploadConfirmRequest request, +@@ -88,7 +91,7 @@ public class InternalFileController { + + // ==================== 分片上传 ==================== + +- @ApiOperation("分片上传-初始化") ++ @ApiOperation(value = "分片上传-初始化", notes = "大文件上传第一步:初始化分片上传任务,返回uploadId和每个分片的预签名URL。前端按分片并发上传后调用complete接口合并") + @PostMapping("/upload/chunk/init") + public Result chunkUploadInit( + @Valid @RequestBody ChunkUploadInitRequest request, +@@ -96,7 +99,7 @@ public class InternalFileController { + return Result.success(chunkUploadService.initChunkUpload(request, adminId)); + } + +- @ApiOperation("分片上传-上传分片") ++ @ApiOperation(value = "分片上传-上传分片", notes = "大文件上传第二步:逐个上传分片,返回分片的ETag用于后续合并校验。支持断点续传,已上传的分片无需重传") + @PostMapping("/upload/chunk") + public Result chunkUploadPart( + @RequestParam("uploadId") String uploadId, +@@ -105,14 +108,14 @@ public class InternalFileController { + return Result.success(chunkUploadService.uploadChunk(uploadId, chunkIndex, chunk)); + } + +- @ApiOperation("分片上传-完成合并") ++ @ApiOperation(value = "分片上传-完成合并", notes = "大文件上传第三步:所有分片上传完成后调用,OSS端合并分片为完整文件并创建文件记录") + @PostMapping("/upload/chunk/complete") + public Result chunkUploadComplete( + @Valid @RequestBody ChunkUploadCompleteRequest request) { + return Result.success(chunkUploadService.completeChunkUpload(request.getUploadId())); + } + +- @ApiOperation("分片上传-取消") ++ @ApiOperation(value = "分片上传-取消", notes = "取消分片上传任务,清理已上传的分片数据和OSS临时文件") + @PostMapping("/upload/chunk/cancel") + public Result chunkUploadCancel( + @Valid @RequestBody ChunkUploadCancelRequest request) { +``` + +### `hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java b/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java +index b78e094..73b8a70 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java +@@ -23,7 +23,7 @@ public class MpFileController { + + private final FileService fileService; + +- @ApiOperation("上传文件(C端用户)") ++ @ApiOperation(value = "上传文件(C端用户)", notes = "小程序端直接上传文件,支持头像、评价图片等场景。groupKey决定存储路径和文件策略,默认为avatar") + @PostMapping("/upload") + public Result upload( + @ApiParam("上传文件") @RequestParam("file") MultipartFile file, +@@ -34,7 +34,8 @@ public class MpFileController { + return Result.success(vo); + } + +- @ApiOperation("文件内容流式预览") ++ @ApiOperation(value = "文件内容流式预览", ++ notes = "流式输出文件内容,设置正确的Content-Type头。用于小程序端通过web-view直接预览图片和PDF等文件。") + @GetMapping("/{fileId}/preview") + public void previewContent(@ApiParam("文件ID") @PathVariable Long fileId, HttpServletResponse response) throws IOException { + fileService.streamContent(fileId, response); +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java +index a96b208..10fe073 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java +@@ -22,19 +22,20 @@ public class AdminGuideArticleController { + + private final GuideArticleService articleService; + +- @ApiOperation("文章列表") ++ @ApiOperation(value = "文章列表", notes = "分页查询攻略文章,支持按分类、状态、关键词筛选\n\n**关联字典**:\n- wiki_status:文章状态(列表筛选+显示)") + @GetMapping("/list") + public Result> listArticles(@Valid ArticleQueryRequest query) { + return Result.success(articleService.listArticles(query)); + } + +- @ApiOperation("文章详情") ++ @ApiOperation(value = "文章详情", notes = "**关联字典**:\n- wiki_status:文章状态(显示)") + @GetMapping("/{articleId}") + public Result getArticle(@PathVariable Long articleId) { + return Result.success(articleService.getArticle(articleId)); + } + +- @ApiOperation("创建文章") ++ @ApiOperation(value = "创建文章", ++ notes = "创建攻略文章,需指定分类。创建后默认为草稿状态,需手动发布后小程序端才可见。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- wiki_status:文章状态(创建后默认DRAFT)") + @PostMapping + public Result createArticle( + @Valid @RequestBody ArticleCreateRequest request, +@@ -43,7 +44,8 @@ public class AdminGuideArticleController { + return Result.success(articleService.createArticle(request, adminId)); + } + +- @ApiOperation("更新文章") ++ @ApiOperation(value = "更新文章", ++ notes = "更新攻略文章的标题、内容、封面图、分类等信息。已发布的文章更新后立即生效。\n\n**权限**:需管理员登录。") + @PutMapping("/{articleId}") + public Result updateArticle( + @PathVariable Long articleId, +@@ -51,14 +53,15 @@ public class AdminGuideArticleController { + return Result.success(articleService.updateArticle(articleId, request)); + } + +- @ApiOperation("删除文章") ++ @ApiOperation(value = "删除文章", ++ notes = "软删除攻略文章,同时清除文章的标签关联。\n\n**权限**:需管理员登录。") + @DeleteMapping("/{articleId}") + public Result deleteArticle(@PathVariable Long articleId) { + articleService.deleteArticle(articleId); + return Result.success(); + } + +- @ApiOperation("发布/下架") ++ @ApiOperation(value = "发布/下架", notes = "切换文章发布状态。发布后小程序端可见,下架后小程序端不再展示但管理端仍可查看\n\n**关联字典**:\n- wiki_status:文章状态(状态切换)") + @PutMapping("/{articleId}/status") + public Result updateStatus( + @PathVariable Long articleId, +@@ -67,7 +70,7 @@ public class AdminGuideArticleController { + return Result.success(); + } + +- @ApiOperation("设置推荐") ++ @ApiOperation(value = "设置推荐", notes = "设置/取消文章推荐。推荐文章会在小程序首页和推荐列表中优先展示") + @PutMapping("/{articleId}/recommend") + public Result updateRecommend( + @PathVariable Long articleId, +@@ -76,7 +79,7 @@ public class AdminGuideArticleController { + return Result.success(); + } + +- @ApiOperation("设置置顶") ++ @ApiOperation(value = "设置置顶", notes = "设置/取消文章置顶。置顶文章在分类列表中始终排在最前面") + @PutMapping("/{articleId}/top") + public Result updateTop( + @PathVariable Long articleId, +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java +index 8b849da..0eddd64 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java +@@ -24,19 +24,20 @@ public class AdminGuideCategoryController { + + private final GuideCategoryService categoryService; + +- @ApiOperation("分类列表") ++ @ApiOperation(value = "分类列表", notes = "返回全部攻略分类(含启用和停用),按排序值升序排列\n\n**关联字典**:\n- common_status:通用状态(列表显示,ACTIVE=启用/INACTIVE=停用)") + @GetMapping("/list") + public Result> listCategories() { + return Result.success(categoryService.listCategories()); + } + +- @ApiOperation("启用的分类列表") ++ @ApiOperation(value = "启用的分类列表", notes = "仅返回状态为启用的分类,创建文章时用于选择分类") + @GetMapping("/enabled") + public Result> listEnabledCategories() { + return Result.success(categoryService.listEnabledCategories()); + } + +- @ApiOperation("创建分类") ++ @ApiOperation(value = "创建分类", ++ notes = "创建攻略分类,分类名称不可重复。创建后默认启用,排序值越小越靠前。\n\n**权限**:需管理员登录。") + @PostMapping + public Result createCategory( + @Valid @RequestBody CategoryCreateRequest request, +@@ -45,7 +46,8 @@ public class AdminGuideCategoryController { + return Result.success(categoryService.createCategory(request, adminId)); + } + +- @ApiOperation("更新分类") ++ @ApiOperation(value = "更新分类", ++ notes = "更新攻略分类的名称、图标、描述等信息。\n\n**权限**:需管理员登录。") + @PutMapping("/{categoryId}") + public Result updateCategory( + @PathVariable Long categoryId, +@@ -53,14 +55,14 @@ public class AdminGuideCategoryController { + return Result.success(categoryService.updateCategory(categoryId, request)); + } + +- @ApiOperation("删除分类") ++ @ApiOperation(value = "删除分类", notes = "删除分类前需确保分类下无文章,否则删除失败") + @DeleteMapping("/{categoryId}") + public Result deleteCategory(@PathVariable Long categoryId) { + categoryService.deleteCategory(categoryId); + return Result.success(); + } + +- @ApiOperation("更新分类状态") ++ @ApiOperation(value = "更新分类状态", notes = "启用或停用分类。停用后该分类下的文章不会在小程序端展示,但不影响已有文章\n\n**关联字典**:\n- common_status:通用状态(状态切换,ACTIVE=启用/INACTIVE=停用)") + @PutMapping("/{categoryId}/status") + public Result updateStatus( + @PathVariable Long categoryId, +@@ -69,7 +71,8 @@ public class AdminGuideCategoryController { + return Result.success(); + } + +- @ApiOperation("更新分类排序") ++ @ApiOperation(value = "更新分类排序", ++ notes = "更新分类的排序值,排序值越小越靠前。影响小程序端分类导航的展示顺序。\n\n**权限**:需管理员登录。") + @PutMapping("/{categoryId}/sort") + public Result updateSort( + @PathVariable Long categoryId, +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java +index acd32b1..d747ae4 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java +@@ -23,19 +23,20 @@ public class AdminGuideTagController { + + private final GuideTagService tagService; + +- @ApiOperation("系统标签列表") ++ @ApiOperation(value = "系统标签列表", notes = "返回管理员创建的系统标签(不含用户自定义标签),用于标签管理页") + @GetMapping("/managed") + public Result> listManagedTags() { + return Result.success(tagService.listManagedTags()); + } + +- @ApiOperation("所有标签列表") ++ @ApiOperation(value = "所有标签列表", notes = "返回全部标签(含系统标签和用户自定义标签),用于文章编辑时的标签选择器") + @GetMapping("/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", ++ notes = "创建攻略系统标签,标签名称不可重复。创建后可用于文章分类和筛选。\n\n**权限**:需管理员登录。") + @PostMapping + public Result createTag( + @Valid @RequestBody TagCreateRequest request, +@@ -44,7 +45,8 @@ public class AdminGuideTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", ++ notes = "更新标签名称。标签名称不可与其他已有标签重复。\n\n**权限**:需管理员登录。") + @PutMapping("/{tagId}") + public Result updateTag( + @PathVariable Long tagId, +@@ -52,14 +54,15 @@ public class AdminGuideTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", ++ notes = "删除标签并自动解除与所有文章的关联关系。\n\n**权限**:需管理员登录。") + @DeleteMapping("/{tagId}") + public Result deleteTag(@PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新文章标签") ++ @ApiOperation(value = "更新文章标签", notes = "全量替换文章的标签关联,传入新的标签ID列表(空数组表示清除所有标签)") + @PutMapping("/article/{articleId}") + public Result updateArticleTags( + @PathVariable Long articleId, +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java +index 42c16dd..62838a6 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java +@@ -16,7 +16,7 @@ import java.util.Map; + /** + * 内部接口 - 供 mp-service Feign 调用 + */ +-@Api(tags = "【内部接口】攻略百科(Feign调用)") ++@Api(tags = "【内部接口】攻略百科(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/wiki") + @RequiredArgsConstructor +@@ -25,13 +25,14 @@ public class InternalWikiController { + private final GuideCategoryService categoryService; + private final GuideArticleService articleService; + +- @ApiOperation("查询已启用的攻略分类列表") ++ @ApiOperation(value = "查询已启用的攻略分类列表", ++ notes = "内部服务间调用。返回所有状态为启用的攻略分类,供小程序端展示分类导航。\n\n**关联字典**:\n- common_status:通用状态(仅返回ACTIVE状态的分类)") + @GetMapping("/categories") + public Result> listEnabledCategories() { + return Result.success(categoryService.listEnabledCategories()); + } + +- @ApiOperation("分页查询指定分类下的已发布文章") ++ @ApiOperation(value = "分页查询指定分类下的已发布文章", notes = "**关联字典**:\n- wiki_status:文章状态(返回字段)") + @GetMapping("/category/{categoryId}/articles") + public Result>> listCategoryArticles( + @PathVariable Long categoryId, +@@ -40,13 +41,14 @@ public class InternalWikiController { + return Result.success(articleService.listPublishedArticlesByCategory(categoryId, page, pageSize)); + } + +- @ApiOperation("查询已发布文章详情") ++ @ApiOperation(value = "查询已发布文章详情", notes = "**关联字典**:\n- wiki_status:文章状态(返回字段)") + @GetMapping("/article/{articleId}") + public Result> getArticle(@PathVariable Long articleId) { + return Result.success(articleService.getPublishedArticle(articleId)); + } + +- @ApiOperation("查询推荐文章列表") ++ @ApiOperation(value = "查询推荐文章列表", ++ notes = "内部服务间调用。返回已发布且标记为推荐的文章列表,用于小程序首页推荐位展示。默认返回5条。") + @GetMapping("/recommend-articles") + public Result>> listRecommendArticles( + @RequestParam(defaultValue = "5") Integer limit) { +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java +index 852da1c..1505c2c 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java +@@ -48,7 +48,8 @@ public class AdminInsuranceController { + private final InsuranceEntityProperties entityProperties; + private final PolicyShareService policyShareService; + +- @ApiOperation("保险产品列表") ++ @ApiOperation(value = "保险产品列表", ++ notes = "分页查询已同步的保险产品,支持按是否境外筛选。产品数据来源于保游网同步。\n\n**权限**:需管理员登录。") + @GetMapping("/products") + public Result> listProducts( + @ApiParam("页码") @RequestParam(defaultValue = "1") Integer page, +@@ -57,26 +58,30 @@ public class AdminInsuranceController { + return Result.success(orderService.listProducts(page, pageSize, isOverseas)); + } + +- @ApiOperation("保险产品详情") ++ @ApiOperation(value = "保险产品详情", ++ notes = "返回保险产品完整信息,包含产品名称、保险公司、保障范围、适用地区等。\n\n**权限**:需管理员登录。") + @GetMapping("/products/{id}") + public Result getProduct(@ApiParam("保险产品ID") @PathVariable("id") Long productId) { + return Result.success(orderService.getProductDetail(productId)); + } + +- @ApiOperation("保险产品计划及费率") ++ @ApiOperation(value = "保险产品计划及费率", ++ notes = "返回指定保险产品的所有投保计划及对应费率表,包含不同天数区间的保费价格。投保下单前需选择具体计划。\n\n**权限**:需管理员登录。") + @GetMapping("/products/{id}/plans") + public Result> getProductPlans(@ApiParam("保险产品ID") @PathVariable("id") Long productId) { + return Result.success(orderService.getProductPlans(productId)); + } + +- @ApiOperation("从保游网同步产品数据") ++ @ApiOperation(value = "从保游网同步产品数据", ++ notes = "手动触发从保游网API拉取最新保险产品数据(含计划和费率),同步到本地数据库。返回同步的产品数量。\n\n**权限**:需管理员登录。") + @PostMapping("/sync-products") + public Result syncProducts() { + int count = syncService.syncAll(); + return Result.success(count); + } + +- @ApiOperation("投保公司主体列表") ++ @ApiOperation(value = "投保公司主体列表", ++ notes = "返回系统配置的投保公司主体列表(来自Nacos配置),投保下单时选择以哪个公司主体投保。每个主体包含编码、公司名称和商户ID。\n\n**权限**:需管理员登录。") + @GetMapping("/entities") + public Result>> listEntities() { + List> list = entityProperties.getList().stream().map(e -> { +@@ -91,7 +96,7 @@ public class AdminInsuranceController { + return Result.success(list); + } + +- @ApiOperation("投保下单(每人独立保单)") ++ @ApiOperation(value = "投保下单(每人独立保单)", notes = "**关联字典**:\n- gender:性别(被保人信息)\n- id_card_type:证件类型(被保人信息)") + @PostMapping("/purchase") + public Result> purchase( + @ApiParam("投保请求") @Valid @RequestBody PurchaseInsuranceRequest request, +@@ -100,43 +105,48 @@ public class AdminInsuranceController { + return Result.success(orderService.purchase(request, adminId)); + } + +- @ApiOperation("退保") ++ @ApiOperation(value = "退保", ++ notes = "对单个保险订单发起退保,调用保游网退保API。退保成功后保险状态变为CANCELLED。\n\n**权限**:需管理员登录。\n**注意**:已生效的保单退保可能产生手续费。\n\n**关联字典**:\n- insurance_status:保险状态(状态流转)") + @PostMapping("/cancel/{id}") + public Result cancel(@ApiParam("保险订单ID") @PathVariable("id") Long insuranceOrderId) { + return Result.success(orderService.cancel(insuranceOrderId)); + } + +- @ApiOperation("保险订单列表") ++ @ApiOperation(value = "保险订单列表", notes = "**关联字典**:\n- insurance_status:保险状态(列表筛选+显示)") + @GetMapping("/orders") + public Result> listOrders(@ApiParam("查询条件") InsuranceQueryRequest request) { + return Result.success(orderService.listOrders(request)); + } + +- @ApiOperation("保险订单详情(含被保人)") ++ @ApiOperation(value = "保险订单详情(含被保人)", notes = "**关联字典**:\n- insurance_status:保险状态(显示)\n- gender:性别(被保人信息显示)\n- id_card_type:证件类型(被保人信息显示)") + @GetMapping("/orders/{id}") + public Result getOrderDetail(@ApiParam("保险订单ID") @PathVariable("id") Long insuranceOrderId) { + return Result.success(orderService.getOrderDetail(insuranceOrderId)); + } + +- @ApiOperation("按旅行订单查询保险单") ++ @ApiOperation(value = "按旅行订单查询保险单", ++ notes = "根据旅行订单ID查询关联的所有保险订单列表。在订单详情页展示保险购买情况。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- insurance_status:保险状态(列表显示)") + @GetMapping("/orders/by-order/{orderId}") + public Result> getByOrder(@ApiParam("旅行订单ID") @PathVariable Long orderId) { + return Result.success(orderService.getByOrderId(orderId)); + } + +- @ApiOperation("查询订单保险保障(含被保人详情)") ++ @ApiOperation(value = "查询订单保险保障(含被保人详情)", ++ notes = "返回订单维度的保险保障汇总信息,包含覆盖人数、保障期间、每位被保人的保单明细。用于订单详情页的保险保障展示。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- insurance_status:保险状态(显示)\n- gender:性别(被保人信息显示)\n- id_card_type:证件类型(被保人信息显示)") + @GetMapping("/coverage/{orderId}") + public Result getCoverage(@ApiParam("旅行订单ID") @PathVariable Long orderId) { + return Result.success(orderService.getCoverageByOrderId(orderId)); + } + +- @ApiOperation("保费试算(本地费率)") ++ @ApiOperation(value = "保费试算(本地费率)", ++ notes = "根据保险计划、投保天数和人数,使用本地同步的费率表试算保费。不调用保游网API,用于投保前的费用预估。\n\n**权限**:需管理员登录。") + @PostMapping("/trial-price") + public Result> trialPrice(@ApiParam("试算请求") @Valid @RequestBody TrialPriceRequest request) { + return Result.success(orderService.trialPrice(request)); + } + +- @ApiOperation("查询保游网账户余额") ++ @ApiOperation(value = "查询保游网账户余额", ++ notes = "查询保游网平台的账户余额,用于管理端展示当前可用投保额度。查询失败时返回null(非关键信息,不影响业务)。\n\n**权限**:需管理员登录。") + @GetMapping("/balance") + public Result getBalance() { + try { +@@ -152,13 +162,15 @@ public class AdminInsuranceController { + return Result.success(null); + } + +- @ApiOperation("下载保单PDF(Base64)") ++ @ApiOperation(value = "下载保单PDF(Base64)", ++ notes = "从保游网下载指定保险订单的电子保单PDF,以Base64编码返回。前端可解码后展示或提供下载。\n\n**权限**:需管理员登录。") + @GetMapping("/policy/{id}/download") + public Result downloadPolicy(@ApiParam("保险订单ID") @PathVariable("id") Long insuranceOrderId) { + return Result.success(orderService.downloadPolicy(insuranceOrderId)); + } + +- @ApiOperation("获取保游网充值链接(旧接口,保留兼容)") ++ @ApiOperation(value = "获取保游网充值链接(旧接口,保留兼容)", ++ notes = "返回保游网平台的充值页面URL。此为旧版接口,保留用于向后兼容,推荐使用在线充值接口。\n\n**权限**:需管理员登录。") + @GetMapping("/recharge-url") + public Result getRechargeUrl() { + String url = baoyouProperties.getRechargeUrl(); +@@ -168,13 +180,15 @@ public class AdminInsuranceController { + return Result.success(url); + } + +- @ApiOperation("在线充值(调用保游网支付API)") ++ @ApiOperation(value = "在线充值(调用保游网支付API)", ++ notes = "调用保游网在线充值API,生成充值支付链接。支持选择支付方式(支付宝/微信),充值完成后账户余额自动更新。\n\n**权限**:需管理员登录。") + @PostMapping("/recharge") + public Result> recharge(@ApiParam("充值请求") @Valid @RequestBody RechargeRequest request) { + return Result.success(orderService.recharge(request.getMoney(), request.getPayType(), request.getBackUrl())); + } + +- @ApiOperation("分享保单(合并某出行人所有有效保单PDF,上传OSS返回链接)") ++ @ApiOperation(value = "分享保单(合并某出行人所有有效保单PDF,上传OSS返回链接)", ++ notes = "合并指定出行人的所有有效保单PDF为一个文件,上传至OSS后返回公开访问链接。用于管理端分享保单给出行人。\n\n**权限**:需管理员登录。") + @PostMapping("/share-policy") + public Result sharePolicy( + @ApiParam("分享保单请求") @Valid @RequestBody SharePolicyRequest request) { +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java +index 9497720..04db6d6 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java +@@ -24,26 +24,30 @@ public class AdminInsuranceSchemeController { + + private final InsuranceSchemeService schemeService; + +- @ApiOperation("活跃方案列表(下拉选择用)") ++ @ApiOperation(value = "活跃方案列表(下拉选择用)", ++ notes = "返回所有状态为启用的保险方案模板,用于投保下单时的方案下拉选择。\n\n**权限**:需管理员登录。") + @GetMapping("/list") + public Result> listActiveSchemes() { + return Result.success(schemeService.listActiveSchemes()); + } + +- @ApiOperation("全部方案列表(管理用)") ++ @ApiOperation(value = "全部方案列表(管理用)", ++ notes = "返回所有保险方案模板(含启用和停用),用于方案管理页面展示和编辑。\n\n**权限**:需管理员登录。") + @GetMapping("/list-all") + public Result> listAllSchemes() { + return Result.success(schemeService.listAllSchemes()); + } + +- @ApiOperation("方案详情") ++ @ApiOperation(value = "方案详情", ++ notes = "返回单个保险方案模板的完整信息,包含方案名称、保险产品关联、天数规则、费率配置等。\n\n**权限**:需管理员登录。") + @GetMapping("/{id}") + public Result getSchemeDetail( + @ApiParam("方案ID") @PathVariable("id") Long schemeId) { + return Result.success(schemeService.getSchemeDetail(schemeId)); + } + +- @ApiOperation("创建方案") ++ @ApiOperation(value = "创建方案", ++ notes = "创建保险方案模板,配置关联保险产品、投保天数规则和费率。创建后默认启用。\n\n**权限**:需管理员登录。") + @PostMapping + public Result createScheme( + @ApiParam("方案请求") @Valid @RequestBody InsuranceSchemeRequest request, +@@ -52,7 +56,8 @@ public class AdminInsuranceSchemeController { + return Result.success(schemeService.createScheme(request, adminId)); + } + +- @ApiOperation("更新方案") ++ @ApiOperation(value = "更新方案", ++ notes = "更新保险方案模板的配置信息,包括方案名称、关联产品、天数规则、费率等。\n\n**权限**:需管理员登录。") + @PutMapping("/{id}") + public Result updateScheme( + @ApiParam("方案ID") @PathVariable("id") Long schemeId, +@@ -62,14 +67,16 @@ public class AdminInsuranceSchemeController { + return Result.success(schemeService.updateScheme(schemeId, request, adminId)); + } + +- @ApiOperation("切换方案状态(启用/停用)") ++ @ApiOperation(value = "切换方案状态(启用/停用)", ++ notes = "切换保险方案模板的启用/停用状态。停用后不会出现在投保下单的方案选择列表中。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- common_status:通用状态(ACTIVE=启用/INACTIVE=停用)") + @PutMapping("/{id}/toggle-status") + public Result toggleStatus( + @ApiParam("方案ID") @PathVariable("id") Long schemeId) { + return Result.success(schemeService.toggleStatus(schemeId)); + } + +- @ApiOperation("删除方案(软删除)") ++ @ApiOperation(value = "删除方案(软删除)", ++ notes = "软删除保险方案模板。已使用该方案创建的保险订单不受影响。\n\n**权限**:需管理员登录。") + @DeleteMapping("/{id}") + public Result deleteScheme( + @ApiParam("方案ID") @PathVariable("id") Long schemeId) { +@@ -77,7 +84,8 @@ public class AdminInsuranceSchemeController { + return Result.success(null); + } + +- @ApiOperation("预览应用方案(解析日期+估算保费)") ++ @ApiOperation(value = "预览应用方案(解析日期+估算保费)", ++ notes = "根据方案模板和行程日期预览投保效果:解析实际投保起止日期、计算每人保费和总保费。用于投保前确认费用。\n\n**权限**:需管理员登录。") + @PostMapping("/preview-apply") + public Result previewApply( + @ApiParam("预览请求") @Valid @RequestBody ApplySchemeRequest request) { +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java +index 828cc04..d77d99e 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java +@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】保险(Feign调用)") ++@Api(tags = "【内部接口】保险(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/insurance") + @RequiredArgsConstructor +@@ -26,19 +26,22 @@ public class InternalInsuranceController { + private final InsuranceProductSyncService syncService; + private final PolicyShareService policyShareService; + +- @ApiOperation("按旅行订单查询保险单(内部调用)") ++ @ApiOperation(value = "按旅行订单查询保险单(内部调用)", ++ notes = "内部服务间调用。根据旅行订单ID查询关联的所有保险订单,返回保险状态、保费、保障期间等信息。\n\n**关联字典**:\n- insurance_status:保险状态(返回字段)") + @GetMapping("/by-order/{orderId}") + public Result> getByOrder(@ApiParam("旅行订单ID") @PathVariable Long orderId) { + return Result.success(orderService.getByOrderId(orderId)); + } + +- @ApiOperation("按订单批量查询保险单(内部调用)") ++ @ApiOperation(value = "按订单批量查询保险单(内部调用)", ++ notes = "内部服务间调用。批量查询多个旅行订单的保险订单,返回Map结构(key=订单ID,value=保险单列表),用于订单列表页展示保险状态。") + @PostMapping("/by-orders") + public Result>> getByOrders(@RequestBody List orderIds) { + return Result.success(orderService.getByOrderIds(orderIds)); + } + +- @ApiOperation("检查保险是否全覆盖(内部调用)") ++ @ApiOperation(value = "检查保险是否全覆盖(内部调用)", ++ notes = "内部服务间调用。根据出行人数和行程天数计算所需的人日数,与已投保的有效保单覆盖人日数对比,判断保险是否已全覆盖。") + @GetMapping("/coverage-complete/{orderId}") + public Result isCoverageComplete( + @ApiParam("旅行订单ID") @PathVariable Long orderId, +@@ -57,7 +60,8 @@ public class InternalInsuranceController { + return Result.success(coveredPersonDays >= requiredPersonDays); + } + +- @ApiOperation("按订单批量退保(级联失效调用)") ++ @ApiOperation(value = "按订单批量退保(级联失效调用)", ++ notes = "内部服务间调用。旅行订单取消或退款时级联调用,将该订单下所有有效保险单批量退保(调用保游网退保API),记录退保原因。") + @PostMapping("/invalidate/{orderId}") + public Result invalidateInsurance( + @ApiParam("旅行订单ID") @PathVariable Long orderId, +@@ -66,19 +70,22 @@ public class InternalInsuranceController { + return Result.success(null); + } + +- @ApiOperation("分享保单PDF(内部调用,返回base64)") ++ @ApiOperation(value = "分享保单PDF(内部调用,返回base64)", ++ notes = "内部服务间调用。合并指定出行人的所有有效保单PDF为一个文件,上传至OSS后返回下载链接和Base64内容,用于小程序端分享保单。") + @PostMapping("/share-policy") + public Result sharePolicy(@RequestBody SharePolicyRequest request) { + return Result.success(policyShareService.sharePolicy(request)); + } + +- @ApiOperation("按订单获取所有保单PDF(内部调用,合并所有出行人)") ++ @ApiOperation(value = "按订单获取所有保单PDF(内部调用,合并所有出行人)", ++ notes = "内部服务间调用。将指定订单下所有出行人的有效保单PDF合并为一个文件,上传至OSS后返回下载链接,用于订单维度的保单查看。") + @GetMapping("/share-policy-by-order/{orderId}") + public Result sharePolicyByOrder(@PathVariable Long orderId) { + return Result.success(policyShareService.sharePolicyByOrder(orderId)); + } + +- @ApiOperation("触发保险产品同步(内部调用/定时任务)") ++ @ApiOperation(value = "触发保险产品同步(内部调用/定时任务)", ++ notes = "内部服务间调用。从保游网API拉取最新保险产品数据(含计划和费率),同步到本地数据库。返回同步的产品数量。") + @PostMapping("/sync-products") + public Result syncProducts() { + int count = syncService.syncAll(); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java +index 08122a4..686a577 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java +@@ -22,7 +22,7 @@ import java.util.List; + * Internal endpoints for Feign calls from other services (scenic, hotel, etc.). + * Not exposed through gateway. + */ +-@Api(tags = "素材内部接口(Feign调用)") ++@Api(tags = "素材内部接口(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/material") + @RequiredArgsConstructor +@@ -31,7 +31,7 @@ public class InternalMaterialController { + private final MaterialRefService refService; + private final MaterialService materialService; + +- @ApiOperation("绑定引用") ++ @ApiOperation(value = "绑定引用", notes = "将素材与业务实体建立引用关系(如景区ID+封面图),记录引用类型(COVER/GALLERY/DETAIL等)") + @PostMapping("/ref/bind") + public Result bindRef( + @Valid @RequestBody RefBindRequest request, +@@ -40,7 +40,7 @@ public class InternalMaterialController { + return Result.success(); + } + +- @ApiOperation("批量绑定引用") ++ @ApiOperation(value = "批量绑定引用", notes = "批量建立素材与业务实体的引用关系,常用于保存包含多张图片的业务数据") + @PostMapping("/ref/batch-bind") + public Result batchBindRefs( + @Valid @RequestBody RefBatchBindRequest request, +@@ -49,7 +49,7 @@ public class InternalMaterialController { + return Result.success(); + } + +- @ApiOperation("解绑引用") ++ @ApiOperation(value = "解绑引用", notes = "删除单个素材与业务实体的引用关系") + @DeleteMapping("/ref/unbind") + public Result unbindRef(@Valid @RequestBody RefUnbindRequest request) { + refService.unbindRef(request.getMaterialId(), request.getBizType(), +@@ -57,14 +57,15 @@ public class InternalMaterialController { + return Result.success(); + } + +- @ApiOperation("批量解绑引用") ++ @ApiOperation(value = "批量解绑引用", notes = "批量删除素材引用关系,常用于业务实体更新时先清除旧引用再绑定新引用") + @DeleteMapping("/ref/batch-unbind") + public Result batchUnbindRefs(@Valid @RequestBody RefBatchUnbindRequest request) { + refService.batchUnbindRefs(request.getRefs()); + return Result.success(); + } + +- @ApiOperation("批量查询素材信息") ++ @ApiOperation(value = "批量查询素材信息", ++ notes = "内部服务间调用。根据素材ID列表批量查询素材信息,用于其他服务获取素材详情(如产品、景区等关联的素材数据)。") + @PostMapping("/by-ids") + public Result> getMaterialsByIds(@Valid @RequestBody BatchMaterialIdsRequest request) { + return Result.success(materialService.getMaterialsByIds(request.getMaterialIds())); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java +index 03566eb..77fa5a6 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java +@@ -23,7 +23,7 @@ public class MaterialCategoryPermissionController { + + private final MaterialCategoryPermissionService permissionService; + +- @ApiOperation("获取角色的分类权限") ++ @ApiOperation(value = "获取角色的分类权限", notes = "仅超级管理员可操作。返回指定角色可访问的素材分类编码列表") + @GetMapping("/{roleCode}") + public Result> getPermissions( + @ApiParam("角色编码") @PathVariable String roleCode, +@@ -32,7 +32,7 @@ public class MaterialCategoryPermissionController { + return Result.success(permissionService.getPermissionsByRoleCode(roleCode)); + } + +- @ApiOperation("更新角色的分类权限") ++ @ApiOperation(value = "更新角色的分类权限", notes = "仅超级管理员可操作。全量替换指定角色的素材分类访问权限,传入允许访问的分类编码列表") + @PutMapping("/{roleCode}") + public Result updatePermissions( + @ApiParam("角色编码") @PathVariable String roleCode, +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java +index 0fa7c7e..d79def9 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java +@@ -47,7 +47,7 @@ public class MaterialController { + + // ==================== Upload ==================== + +- @ApiOperation("获取上传凭证") ++ @ApiOperation(value = "获取上传凭证", notes = "上传素材第一步:获取OSS预签名URL和凭证。前端使用凭证直传OSS后调用确认上传。支持基于角色的分类权限校验") + @PostMapping("/upload/token") + public Result requestUploadToken( + @ApiParam("上传凭证请求") @Valid @RequestBody MaterialUploadTokenRequest request, +@@ -57,7 +57,7 @@ public class MaterialController { + return Result.success(materialService.requestUploadToken(request, adminId, role)); + } + +- @ApiOperation("确认上传完成") ++ @ApiOperation(value = "确认上传完成", notes = "上传素材第二步:前端直传OSS完成后调用此接口创建素材记录,支持MD5去重\n\n**关联字典**:\n- material_tag:素材标签(上传时可选标签)") + @PostMapping("/upload/confirm") + public Result confirmUpload( + @ApiParam("确认上传请求") @Valid @RequestBody MaterialUploadConfirmRequest request, +@@ -66,7 +66,7 @@ public class MaterialController { + return Result.success(materialService.confirmUpload(request, adminId)); + } + +- @ApiOperation("文件夹上传初始化(创建分类+批量获取凭证)") ++ @ApiOperation(value = "文件夹上传初始化(创建分类+批量获取凭证)", notes = "支持整个文件夹上传:自动根据文件夹名创建子分类,为每个文件批量获取上传凭证,前端逐一上传后批量确认") + @PostMapping("/upload/folder") + public Result folderUploadInit( + @ApiParam("文件夹上传初始化请求") @Valid @RequestBody FolderUploadInitRequest request, +@@ -79,7 +79,8 @@ public class MaterialController { + + // ==================== Chunk Upload (分片上传) ==================== + +- @ApiOperation("分片上传-初始化") ++ @ApiOperation(value = "分片上传-初始化", ++ notes = "大文件上传第一步:初始化分片上传任务,返回uploadId和每个分片的预签名URL。前端按分片并发上传后调用完成合并接口。\n\n**权限**:需管理员登录,受角色分类权限限制。") + @PostMapping("/upload/chunk/init") + public Result chunkUploadInit( + @ApiParam("分片上传初始化请求") @Valid @RequestBody ChunkUploadInitRequest request, +@@ -89,7 +90,8 @@ public class MaterialController { + return Result.success(chunkUploadService.initChunkUpload(request, adminId, role)); + } + +- @ApiOperation("分片上传-上传分片") ++ @ApiOperation(value = "分片上传-上传分片", ++ notes = "大文件上传第二步:逐个上传分片数据,分片索引从0开始。支持断点续传,已上传的分片无需重传。") + @PostMapping("/upload/chunk") + public Result chunkUploadPart( + @ApiParam("上传ID") @RequestParam("uploadId") String uploadId, +@@ -99,7 +101,8 @@ public class MaterialController { + return Result.success(chunkUploadService.uploadChunk(uploadId, chunkIndex, chunk)); + } + +- @ApiOperation("分片上传-完成合并") ++ @ApiOperation(value = "分片上传-完成合并", ++ notes = "大文件上传第三步:所有分片上传完成后调用,OSS端合并分片为完整文件并创建素材记录。") + @PostMapping("/upload/chunk/complete") + public Result chunkUploadComplete( + @ApiParam("分片上传完成请求") @Valid @RequestBody ChunkUploadCompleteRequest request, +@@ -108,7 +111,8 @@ public class MaterialController { + return Result.success(chunkUploadService.completeChunkUpload(request.getUploadId(), adminId)); + } + +- @ApiOperation("分片上传-取消") ++ @ApiOperation(value = "分片上传-取消", ++ notes = "取消分片上传任务,清理已上传的分片数据和OSS临时文件。仅上传发起者可取消。") + @PostMapping("/upload/chunk/cancel") + public Result chunkUploadCancel( + @ApiParam("分片上传取消请求") @Valid @RequestBody ChunkUploadCancelRequest request, +@@ -120,7 +124,7 @@ public class MaterialController { + + // ==================== CRUD ==================== + +- @ApiOperation("素材列表") ++ @ApiOperation(value = "素材列表", notes = "分页查询素材,支持按分类、标签、文件类型、关键词筛选。返回结果受角色分类权限限制\n\n**关联字典**:\n- file_type:文件类型(列表筛选+显示)") + @GetMapping("/list") + public Result> listMaterials( + @ApiParam("素材查询条件") @Valid MaterialQueryRequest query, +@@ -131,7 +135,8 @@ public class MaterialController { + return Result.success(materialService.listMaterials(query, adminId, role, categoryMap)); + } + +- @ApiOperation("素材详情") ++ @ApiOperation(value = "素材详情", ++ notes = "返回素材完整信息,包含文件名、URL、分类、标签、文件大小、上传者等。受角色分类权限限制。\n\n**关联字典**:\n- file_type:文件类型(显示)") + @GetMapping("/{materialId}") + public Result getMaterial( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -141,7 +146,7 @@ public class MaterialController { + return Result.success(materialService.getMaterial(materialId, role, categoryMap)); + } + +- @ApiOperation("更新素材信息") ++ @ApiOperation(value = "更新素材信息", notes = "**关联字典**:\n- material_tag:素材标签(编辑时选择标签)") + @PutMapping("/{materialId}") + public Result updateMaterial( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -153,7 +158,7 @@ public class MaterialController { + return Result.success(materialService.updateMaterial(materialId, request, adminId, role, categoryMap)); + } + +- @ApiOperation("删除素材") ++ @ApiOperation(value = "删除素材", notes = "删除素材记录。如果素材存在引用关系(被景区、酒店等使用),则不允许删除") + @DeleteMapping("/{materialId}") + public Result deleteMaterial( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -164,7 +169,7 @@ public class MaterialController { + return Result.success(); + } + +- @ApiOperation("批量删除素材") ++ @ApiOperation(value = "批量删除素材", notes = "批量删除素材,返回删除结果(成功数/失败数/失败原因)。有引用关系的素材会跳过并记录失败原因") + @DeleteMapping("/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +@@ -179,7 +184,7 @@ public class MaterialController { + + // ==================== Tags on Materials ==================== + +- @ApiOperation("更新素材标签") ++ @ApiOperation(value = "更新素材标签", notes = "全量替换单个素材的标签,传入新的标签ID列表") + @PutMapping("/{materialId}/tags") + public Result updateMaterialTags( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -192,7 +197,7 @@ public class MaterialController { + return Result.success(); + } + +- @ApiOperation("批量更新标签") ++ @ApiOperation(value = "批量更新标签", notes = "对多个素材同时添加和/或移除标签,支持增量操作(addTagIds新增,removeTagIds移除)") + @PutMapping("/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签更新请求") @Valid @RequestBody BatchTagRequest request, +@@ -212,7 +217,7 @@ public class MaterialController { + + // ==================== References ==================== + +- @ApiOperation("查看素材引用记录") ++ @ApiOperation(value = "查看素材引用记录", notes = "查看素材被哪些业务实体引用(如景区封面、酒店轮播图等),用于判断素材是否可安全删除") + @GetMapping("/{materialId}/refs") + public Result> getMaterialRefs(@ApiParam("素材ID") @PathVariable Long materialId) { + return Result.success(refService.getRefsByMaterialId(materialId)); +@@ -220,7 +225,7 @@ public class MaterialController { + + // ==================== Categories ==================== + +- @ApiOperation("获取有权限的分类列表(含素材数量)") ++ @ApiOperation(value = "获取有权限的分类列表(含素材数量)", notes = "返回当前角色有权限查看的素材分类树,每个分类包含素材数量统计。超级管理员可见全部分类") + @GetMapping("/categories") + public Result> getCategories(HttpServletRequest httpRequest) { + String role = getRole(httpRequest); +@@ -230,7 +235,7 @@ public class MaterialController { + + // ==================== Sub-categories ==================== + +- @ApiOperation("创建子分类") ++ @ApiOperation(value = "创建子分类", notes = "在一级分类下创建子分类,分类编码自动生成。子分类用于更细粒度的素材归档") + @PostMapping("/category/sub") + public Result createSubCategory( + @ApiParam("子分类创建请求") @Valid @RequestBody SubCategoryCreateRequest request, +@@ -241,7 +246,8 @@ public class MaterialController { + return Result.success(categoryService.createSubCategory(request, adminId, role, categoryMap)); + } + +- @ApiOperation("更新子分类") ++ @ApiOperation(value = "更新子分类", ++ notes = "更新子分类的名称或排序值。仅有该分类权限的管理员可操作。") + @PutMapping("/category/sub/{categoryId}") + public Result updateSubCategory( + @ApiParam("子分类ID") @PathVariable Long categoryId, +@@ -252,7 +258,7 @@ public class MaterialController { + return Result.success(categoryService.updateSubCategory(categoryId, request, adminId, role)); + } + +- @ApiOperation("删除子分类") ++ @ApiOperation(value = "删除子分类", notes = "删除子分类前需确保分类下无素材,否则删除失败") + @DeleteMapping("/category/sub/{categoryId}") + public Result deleteSubCategory( + @ApiParam("子分类ID") @PathVariable Long categoryId, +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java +index a90884f..31d53b5 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java +@@ -23,19 +23,22 @@ public class MaterialTagController { + + private final MaterialTagService tagService; + +- @ApiOperation("获取管理标签(标签管理用)") ++ @ApiOperation(value = "获取管理标签(标签管理用)", ++ notes = "返回管理员创建的系统标签列表(不含用户自定义标签),用于标签管理页的CRUD操作。") + @GetMapping("/tags") + public Result> listManagedTags() { + return Result.success(tagService.listManagedTags()); + } + +- @ApiOperation("获取全部标签(选择器用,含自定义标签)") ++ @ApiOperation(value = "获取全部标签(选择器用,含自定义标签)", ++ notes = "返回所有标签(含系统标签和用户自定义标签),用于素材上传/编辑时的标签选择器。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", ++ notes = "创建系统级素材标签,标签名称不可重复。创建后可用于素材分类和筛选。\n\n**权限**:需管理员登录。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("创建标签请求") @Valid @RequestBody TagCreateRequest request, +@@ -44,7 +47,8 @@ public class MaterialTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签(按名称查找或创建)") ++ @ApiOperation(value = "解析自定义标签(按名称查找或创建)", ++ notes = "按标签名称查找已有标签,不存在则自动创建为用户自定义标签。用于素材上传时输入自由标签文本的场景。\n\n**权限**:需管理员登录。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("自定义标签请求") @RequestBody TagCreateRequest request, +@@ -53,7 +57,8 @@ public class MaterialTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", ++ notes = "更新标签名称。标签名称不可与其他已有标签重复。\n\n**权限**:需管理员登录。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -61,7 +66,8 @@ public class MaterialTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", ++ notes = "删除标签并自动解除与所有素材的关联关系。\n\n**权限**:需管理员登录。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java +index a595577..17f64ac 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java +@@ -20,7 +20,7 @@ public class MpMaterialController { + + private final MaterialService materialService; + +- @ApiOperation("获取小程序分类下的全部素材") ++ @ApiOperation(value = "获取小程序分类下的全部素材", notes = "返回miniprogram分类下的所有素材,用于小程序端展示公共素材资源(如引导页图片、默认头像等)") + @GetMapping("/miniprogram") + public Result> listMiniprogramMaterials() { + return Result.success(materialService.listMaterialsByCategoryCode("miniprogram")); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java +index 6c26fc1..04d1ebd 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java +@@ -19,7 +19,7 @@ public class ApprovalLogController { + + private final ApprovalLogService approvalLogService; + +- @ApiOperation("审批日志分页查询") ++ @ApiOperation(value = "审批日志分页查询", notes = "查询企微OA审批流程记录,支持按审批状态(1-审批中/2-已通过/3-已驳回/4-已撤销)、申请人、模板名称筛选\n\n**关联字典**:\n- approval_sp_status:审批状态(列表筛选+显示)") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,7 +32,7 @@ public class ApprovalLogController { + return Result.success(approvalLogService.queryPage(page, pageSize, spStatus, applyUserName, spName, startTime, endTime)); + } + +- @ApiOperation("审批日志详情") ++ @ApiOperation(value = "审批日志详情", notes = "**关联字典**:\n- approval_sp_status:审批状态(显示)") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + ApprovalLog approvalLog = approvalLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java +index 43d56d8..12117da 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java +@@ -19,7 +19,7 @@ public class DataRetentionController { + + private final DataRetentionService dataRetentionService; + +- @ApiOperation("手动触发数据清理") ++ @ApiOperation(value = "手动触发数据清理", notes = "仅超级管理员可操作。按数据保留策略清理过期日志(操作日志/错误日志/通知日志等),返回各类型清理的记录数") + @PostMapping("/cleanup") + public Result> cleanup(HttpServletRequest request) { + requireSuperAdmin(request); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java +index 77046be..06bbdf5 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java +@@ -19,7 +19,7 @@ public class ErrorLogController { + + private final ErrorLogService errorLogService; + +- @ApiOperation("错误日志分页查询") ++ @ApiOperation(value = "错误日志分页查询", notes = "查询各微服务的异常记录,支持按服务名称、异常类名、时间范围筛选。堆栈信息仅保留com.hulalv包内的调用帧") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -31,7 +31,8 @@ public class ErrorLogController { + return Result.success(errorLogService.queryPage(page, pageSize, serviceName, exceptionClass, startTime, endTime)); + } + +- @ApiOperation("错误日志详情") ++ @ApiOperation(value = "错误日志详情", ++ notes = "返回单条错误日志的完整信息,包含异常类名、错误消息、过滤后的堆栈信息(仅com.hulalv包内调用帧)、请求URL、请求参数等。") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + ErrorLog errorLog = errorLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java +index 51e3999..44d463e 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java +@@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.*; + * Internal endpoints for receiving logs from other services. + * NOT exposed via gateway. + */ +-@Api(tags = "【内部接口】日志接收(Feign调用)") ++@Api(tags = "【内部接口】日志接收(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/monitor") + @RequiredArgsConstructor +@@ -29,35 +29,35 @@ public class InternalLogController { + private final NotificationLogService notificationLogService; + private final ApprovalLogService approvalLogService; + +- @ApiOperation("Receive operation log") ++ @ApiOperation(value = "接收操作日志", notes = "各微服务通过AOP拦截@OperationLog注解的方法,异步发送操作日志到此接口存储") + @PostMapping("/operation-log") +- public Result receiveOperationLog(@RequestBody OperationLogDTO dto) { ++ public Result receiveOperationLog(@RequestBody OperationLogDTO dto) { + operationLogService.saveFromDTO(dto); + return Result.success(); + } + +- @ApiOperation("Receive error log") ++ @ApiOperation(value = "接收错误日志", notes = "各微服务的GlobalExceptionHandler捕获异常后,异步发送错误日志到此接口存储") + @PostMapping("/error-log") +- public Result receiveErrorLog(@RequestBody ErrorLogDTO dto) { ++ public Result receiveErrorLog(@RequestBody ErrorLogDTO dto) { + errorLogService.saveFromDTO(dto); + return Result.success(); + } + +- @ApiOperation("Receive notification log") ++ @ApiOperation(value = "接收通知日志", notes = "通知服务发送消息(短信/站内信/企微等)后,记录发送结果到此接口") + @PostMapping("/notification-log") +- public Result receiveNotificationLog(@RequestBody NotificationLogDTO dto) { ++ public Result receiveNotificationLog(@RequestBody NotificationLogDTO dto) { + notificationLogService.saveFromDTO(dto); + return Result.success(); + } + +- @ApiOperation("Receive approval log") ++ @ApiOperation(value = "接收审批日志", notes = "企微回调服务接收审批事件后,发送审批日志到此接口。同一审批单号会更新已有记录(按thirdNo去重)") + @PostMapping("/approval-log") +- public Result receiveApprovalLog(@RequestBody ApprovalLogDTO dto) { ++ public Result receiveApprovalLog(@RequestBody ApprovalLogDTO dto) { + approvalLogService.saveOrUpdateByThirdNo(dto); + return Result.success(); + } + +- @ApiOperation("Get customer stats for a user (add/loss counts)") ++ @ApiOperation(value = "获取用户客户统计", notes = "统计指定用户的客户增减数据(新增客户数/流失客户数),用于客户管理看板") + @GetMapping("/notification-log/customer-stats") + public Result> getCustomerStats( + @RequestParam("userId") String userId) { +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java +index 52c9e86..bc58580 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java +@@ -19,7 +19,7 @@ public class LoginLogController { + + private final UserServiceClient userServiceClient; + +- @ApiOperation("登录日志分页查询") ++ @ApiOperation(value = "登录日志分页查询", notes = "查询管理员登录记录(代理到user-service),包含登录IP、设备信息、登录方式和登录结果\n\n**关联字典**:\n- login_status:登录状态(列表筛选+显示)") + @GetMapping + public Result list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java +index 029e317..0d29b88 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java +@@ -21,20 +21,20 @@ public class MysqlMonitorController { + + private final MysqlMonitorService mysqlMonitorService; + +- @ApiOperation("MySQL实时监控数据") ++ @ApiOperation(value = "MySQL实时监控数据", notes = "返回MySQL实时状态:连接数、QPS、缓冲池命中率、线程状态、慢查询计数等核心指标") + @GetMapping + public Result> overview() { + return Result.success(mysqlMonitorService.getOverview()); + } + +- @ApiOperation("表空间列表") ++ @ApiOperation(value = "表空间列表", notes = "查询各数据库表的空间占用情况,包含数据大小、索引大小、行数等信息。可指定schema筛选,仅允许查询hl_前缀的数据库") + @GetMapping("/tables") + public Result>> tables( + @ApiParam("数据库名") @RequestParam(required = false) String schema) { + return Result.success(mysqlMonitorService.getTableSpaces(schema)); + } + +- @ApiOperation("慢SQL查询统计") ++ @ApiOperation(value = "慢SQL查询统计", notes = "仅超级管理员可操作。查询慢SQL统计信息,返回执行时间最长的SQL语句及其执行次数、平均耗时等") + @GetMapping("/slow-queries") + public Result>> slowQueries( + HttpServletRequest request, +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java +index 7e55cae..46d7b72 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java +@@ -19,7 +19,7 @@ public class NotificationLogController { + + private final NotificationLogService notificationLogService; + +- @ApiOperation("消息通知日志分页查询") ++ @ApiOperation(value = "消息通知日志分页查询", notes = "查询各渠道(短信/站内信/企微/公众号)的通知发送记录,支持按通知类型、用户、发送状态筛选\n\n**关联字典**:\n- notification_send_status:发送状态(列表筛选+显示,0=待发送/1=成功/2=失败)") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,7 +32,8 @@ public class NotificationLogController { + return Result.success(notificationLogService.queryPage(page, pageSize, notificationType, userName, sendStatus, startTime, endTime)); + } + +- @ApiOperation("消息通知日志详情") ++ @ApiOperation(value = "消息通知日志详情", ++ notes = "返回单条通知发送日志的完整信息,包含通知类型、接收用户、发送渠道、发送状态、失败原因(如有)、消息内容等。") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + NotificationLog notificationLog = notificationLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java +index 43516e4..f620a50 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java +@@ -19,7 +19,7 @@ public class OperationLogController { + + private final OperationLogService operationLogService; + +- @ApiOperation("操作日志分页查询") ++ @ApiOperation(value = "操作日志分页查询", notes = "查询管理员的操作记录,支持按模块、管理员、状态、时间范围筛选。记录包含请求参数、响应结果和耗时信息\n\n**关联字典**:\n- operation_log_status:操作状态(列表筛选+显示,0=成功/1=失败)") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,7 +32,8 @@ public class OperationLogController { + return Result.success(operationLogService.queryPage(page, pageSize, module, adminId, status, startTime, endTime)); + } + +- @ApiOperation("操作日志详情") ++ @ApiOperation(value = "操作日志详情", ++ notes = "返回单条操作日志的完整信息,包含操作模块、操作描述、请求参数、响应结果、操作耗时、操作人信息、IP地址等。") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + OperationLog log = operationLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java +index e70ae11..ffc059f 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java +@@ -17,7 +17,7 @@ public class RedisMonitorController { + + private final RedisMonitorService redisMonitorService; + +- @ApiOperation("Redis实时监控数据") ++ @ApiOperation(value = "Redis实时监控数据", notes = "返回Redis实时状态:内存使用量、连接数、Key数量、命中率、每秒命令数等核心指标") + @GetMapping + public Result> overview() { + return Result.success(redisMonitorService.getOverview()); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java +index 5d642cb..9f32297 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java +@@ -18,19 +18,19 @@ public class RocketMqMonitorController { + + private final RocketMqMonitorService rocketMqMonitorService; + +- @ApiOperation("RocketMQ概览") ++ @ApiOperation(value = "RocketMQ概览", notes = "返回RocketMQ集群状态:Broker状态、Topic数量、消息积压量、生产者/消费者连接数等核心指标") + @GetMapping + public Result> overview() { + return Result.success(rocketMqMonitorService.getOverview()); + } + +- @ApiOperation("Topic统计") ++ @ApiOperation(value = "Topic统计", notes = "返回各Topic的消息量、最新偏移量和消费进度等信息") + @GetMapping("/topics") + public Result>> topicStats() { + return Result.success(rocketMqMonitorService.getTopicStats()); + } + +- @ApiOperation("消费者组统计") ++ @ApiOperation(value = "消费者组统计", notes = "返回各消费者组的消费进度、积压量和在线消费者实例信息") + @GetMapping("/consumer-groups") + public Result>> consumerGroupStats() { + return Result.success(rocketMqMonitorService.getConsumerGroupStats()); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java +index 63d09ef..11e5509 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java +@@ -18,7 +18,7 @@ public class ServiceMonitorController { + + private final ServiceMonitorService serviceMonitorService; + +- @ApiOperation("微服务列表和健康状态") ++ @ApiOperation(value = "微服务列表和健康状态", notes = "从Nacos注册中心获取所有微服务的实例列表和健康状态,包含IP、端口、注册时间和健康检查结果") + @GetMapping + public Result>> list() { + return Result.success(serviceMonitorService.getServiceList()); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java +index f7f787c..da96036 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java +@@ -22,7 +22,8 @@ public class MpActivityController { + private final MpResourceFeignClient resourceFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("活动列表") ++ @ApiOperation(value = "活动列表", ++ notes = "分页查询已上架的活动列表,支持关键词和分类筛选。聚合层透传resource-service的活动数据给小程序前端。") + @GetMapping("/list") + public Result>> listActivities( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -37,7 +38,8 @@ public class MpActivityController { + return resourceFeignClient.listActivities(query); + } + +- @ApiOperation("活动详情") ++ @ApiOperation(value = "活动详情", ++ notes = "获取活动完整信息(含图文详情、价格等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{activityId}") + public Result> getActivityDetail(@ApiParam("活动ID") @PathVariable Long activityId) { + Result> result = resourceFeignClient.getActivityDetail(activityId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java +index 9023792..61ad359 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java +@@ -18,7 +18,7 @@ public class MpBadgeController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取徽章数据") ++ @ApiOperation(value = "获取徽章数据", notes = "返回用户的徽章统计(未读消息数、待办事项数等),用于「我的」页面角标展示") + @GetMapping + public Result> getBadges(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java +index 6089f32..df4d3dd 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java +@@ -23,7 +23,8 @@ public class MpBannerController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取当前生效的轮播图列表") ++ @ApiOperation(value = "获取当前生效的轮播图列表", ++ notes = "返回当前处于有效期内的轮播图,按排序值排列。用于小程序首页顶部轮播展示,透传自user-service。") + @GetMapping("/active") + public Result>> listActiveBanners() { + return userFeignClient.listActiveBanners(); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java +index be29a79..84ec777 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java +@@ -22,13 +22,15 @@ public class MpConfigController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取所有非敏感前端配置") ++ @ApiOperation(value = "获取所有非敏感前端配置", ++ notes = "返回所有非SECRET类型的前端配置项(如主题色、客服电话、版本号等)。不含敏感配置,可安全传输给小程序端。") + @GetMapping + public Result>> listPublicConfigs() { + return userFeignClient.listAllFrontendConfigs(); + } + +- @ApiOperation("按分组获取非敏感前端配置") ++ @ApiOperation(value = "按分组获取非敏感前端配置", ++ notes = "按配置分组获取前端配置项,如UI分组、功能开关分组等。用于小程序按需加载特定分组的配置。") + @GetMapping("/group/{group}") + public Result>> listPublicConfigsByGroup( + @ApiParam("配置分组") @PathVariable String group) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java +index 4e34f66..c5b60cb 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java +@@ -20,7 +20,7 @@ public class MpContractController { + + private final MpContractFeignClient contractFeignClient; + +- @ApiOperation("合同列表") ++ @ApiOperation(value = "合同列表", notes = "**关联字典(BFF透传)**:\n- contract_status:合同状态(列表筛选+显示)") + @GetMapping("/list") + public Result>> listContracts( + HttpServletRequest request, +@@ -31,7 +31,7 @@ public class MpContractController { + return contractFeignClient.listContracts(userId, status, page, pageSize); + } + +- @ApiOperation(value = "合同详情", notes = "返回合同基本信息、签署状态、出行人签署详情及合同文件下载链接") ++ @ApiOperation(value = "合同详情", notes = "返回合同基本信息、签署状态、出行人签署详情及合同文件下载链接\n\n**关联字典(BFF透传)**:\n- contract_status:合同状态(显示)") + @GetMapping("/{id}") + public Result> getContractDetail( + HttpServletRequest request, +@@ -40,7 +40,7 @@ public class MpContractController { + return contractFeignClient.getContractDetail(id, userId); + } + +- @ApiOperation(value = "按订单查合同", notes = "返回订单关联的最新有效合同(非作废)") ++ @ApiOperation(value = "按订单查合同", notes = "返回订单关联的最新有效合同(非作废)\n\n**关联字典(BFF透传)**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}") + public Result> getContractByOrder( + HttpServletRequest request, +@@ -49,7 +49,7 @@ public class MpContractController { + return contractFeignClient.getContractByOrder(orderId, userId); + } + +- @ApiOperation(value = "按订单查所有合同", notes = "返回订单关联的所有有效合同(TOUR+INSURANCE各一条)") ++ @ApiOperation(value = "按订单查所有合同", notes = "返回订单关联的所有有效合同(TOUR+INSURANCE各一条)\n\n**关联字典(BFF透传)**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}/all") + public Result>> getContractsByOrder( + HttpServletRequest request, +@@ -58,7 +58,8 @@ public class MpContractController { + return contractFeignClient.getContractsByOrder(orderId, userId); + } + +- @ApiOperation("重新发送合同签署短信") ++ @ApiOperation(value = "重新发送合同签署短信", ++ notes = "重新向出行人发送合同签署短信通知,适用于出行人未收到短信或短信过期的场景。\n\n**权限**:需登录。") + @PostMapping("/{contractId}/resend-sms") + public Result resendContractSms( + @ApiParam("合同ID") @PathVariable Long contractId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java +index ae62fb8..01d0115 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java +@@ -22,7 +22,8 @@ public class MpDesignerController { + private final MpUserFeignClient userFeignClient; + private final DesignerAggregationService designerAggregationService; + +- @ApiOperation("定制师列表(含真实产品数和评分,综合排序)") ++ @ApiOperation(value = "定制师列表(含真实产品数和评分,综合排序)", ++ notes = "获取定制师列表,聚合层会补充每个定制师的真实产品数量和评价评分。按综合排序(评分>路线数>咨询人数),用于小程序定制师推荐页。") + @SuppressWarnings("unchecked") + @GetMapping + public Result>> listDesigners( +@@ -37,7 +38,8 @@ public class MpDesignerController { + return result; + } + +- @ApiOperation("推荐定制师(综合排序第一名)") ++ @ApiOperation(value = "推荐定制师(综合排序第一名)", ++ notes = "获取综合排序排名第一的定制师信息(含产品数和评分),用于首页推荐定制师卡片展示。") + @GetMapping("/featured") + public Result> getFeaturedDesigner() { + // Fetch all designers, enrich and sort, return top one +@@ -74,7 +76,8 @@ public class MpDesignerController { + try { return Integer.parseInt(obj.toString()); } catch (NumberFormatException e) { return 0; } + } + +- @ApiOperation("定制师详情(含产品数量和评分)") ++ @ApiOperation(value = "定制师详情(含产品数量和评分)", ++ notes = "获取定制师完整个人信息,聚合层会补充该定制师的已发布产品数量和综合评分,用于定制师个人主页展示。") + @GetMapping("/{id}") + public Result> getDesignerDetail(@ApiParam("定制师ID") @PathVariable Long id) { + Map data = designerAggregationService.getDesignerDetailWithStats(id); +@@ -84,7 +87,7 @@ public class MpDesignerController { + return Result.success(data); + } + +- @ApiOperation("定制师已发布产品列表") ++ @ApiOperation(value = "定制师已发布产品列表", notes = "**关联字典(BFF透传)**:\n- product_type:产品类型(显示)") + @GetMapping("/{id}/products") + public Result>> getDesignerProducts( + @ApiParam("定制师ID") @PathVariable Long id, +@@ -93,7 +96,7 @@ public class MpDesignerController { + return designerAggregationService.getDesignerProducts(id, page, pageSize); + } + +- @ApiOperation("定制师产品评价列表") ++ @ApiOperation(value = "定制师产品评价列表", notes = "**关联字典(BFF透传)**:\n- rating_level:评价等级(显示)") + @GetMapping("/{id}/reviews") + public Result>> getDesignerReviews( + @ApiParam("定制师ID") @PathVariable Long id, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java +index b57cfd7..e689361 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java +@@ -23,7 +23,7 @@ public class MpDictController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取所有字典数据") ++ @ApiOperation(value = "获取所有字典数据", notes = "获取系统全部字典数据(按字典类型分组),用于小程序端的下拉选项、枚举映射等。建议前端缓存此数据") + @GetMapping("/all") + public Result>> getAllDict() { + return userFeignClient.getAllDict(); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java +index ba1fcaa..5aa4cfc 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java +@@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; + import org.springframework.web.bind.annotation.*; + + import javax.servlet.http.HttpServletRequest; ++import java.util.Map; + + @Api(tags = "C端 - 探索接口") + @RestController +@@ -18,9 +19,10 @@ public class MpExploreController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("探索列表") ++ @ApiOperation(value = "探索列表", ++ notes = "获取已启用的探索分类列表(图文攻略内容),支持综合/最新/最热排序,分页返回。用于小程序探索频道首页瀑布流展示。") + @GetMapping("/list") +- public Result list( ++ public Result> list( + @ApiParam("排序方式:comprehensive/newest/hottest") @RequestParam(defaultValue = "comprehensive") String sortType, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, + @ApiParam("每页条数") @RequestParam(defaultValue = "20") int pageSize) { +@@ -29,7 +31,7 @@ public class MpExploreController { + + @ApiOperation(value = "探索详情", notes = "自动增加浏览量,已登录时返回点赞/收藏状态") + @GetMapping("/{id}") +- public Result detail(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { ++ public Result> detail(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { + // optional auth: userId may be null if not logged in + Long userId = null; + String userIdHeader = request.getHeader("X-User-Id"); +@@ -42,22 +44,25 @@ public class MpExploreController { + return userFeignClient.getExploreCategoryDetail(id, userId); + } + +- @ApiOperation("浏览+1") ++ @ApiOperation(value = "浏览+1", ++ notes = "增加探索内容的浏览计数。前端进入探索详情页时调用,无需登录。") + @PostMapping("/{id}/view") +- public Result view(@ApiParam("探索分类ID") @PathVariable Long id) { ++ public Result view(@ApiParam("探索分类ID") @PathVariable Long id) { + return userFeignClient.incrementExploreViewCount(id); + } + +- @ApiOperation("切换点赞") ++ @ApiOperation(value = "切换点赞", ++ notes = "对探索内容点赞/取消点赞,返回当前点赞状态(true=已点赞)。\n\n**权限**:需登录。") + @PostMapping("/{id}/like") +- public Result toggleLike(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { ++ public Result toggleLike(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.toggleExploreLike(id, userId); + } + +- @ApiOperation("切换收藏") ++ @ApiOperation(value = "切换收藏", ++ notes = "对探索内容收藏/取消收藏,返回当前收藏状态(true=已收藏)。收藏后可在'我的收藏'中查看。\n\n**权限**:需登录。") + @PostMapping("/{id}/favorite") +- public Result toggleFavorite(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { ++ public Result toggleFavorite(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.toggleExploreFavorite(id, userId); + } +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java +index 94c53e4..d596692 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java +@@ -27,7 +27,7 @@ public class MpFavoriteController { + private final MpUserFeignClient userFeignClient; + private final FavoriteAggregationService favoriteAggregationService; + +- @ApiOperation("添加收藏") ++ @ApiOperation(value = "添加收藏", notes = "将产品/景区/餐厅/活动加入收藏。同一目标重复收藏会返回已有收藏记录") + @PostMapping + public Result> addFavorite(HttpServletRequest request, + @Valid @RequestBody MpFavoriteRequest body) { +@@ -38,7 +38,8 @@ public class MpFavoriteController { + return userFeignClient.addFavorite(userId, map); + } + +- @ApiOperation("收藏列表(含资源摘要)") ++ @ApiOperation(value = "收藏列表(含资源摘要)", ++ notes = "分页查询收藏列表,聚合层会补充每个收藏项对应资源的摘要信息(名称、封面图、价格等)。支持按目标类型筛选。\n\n**权限**:需登录。\n\n**关联字典**:\n- favorite_resource_type:收藏资源类型(PRODUCT/SCENIC/RESTAURANT/ACTIVITY)") + @GetMapping + public Result> listFavorites(HttpServletRequest request, + @ApiParam("目标类型筛选(字典:favorite_resource_type):PRODUCT/SCENIC/RESTAURANT/ACTIVITY") +@@ -49,7 +50,8 @@ public class MpFavoriteController { + return Result.success(favoriteAggregationService.listFavorites(userId, targetType, page, pageSize)); + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", ++ notes = "检查当前用户是否已收藏指定资源,用于详情页收藏按钮状态显示。\n\n**权限**:需登录。") + @GetMapping("/check") + public Result checkFavorite(HttpServletRequest request, + @ApiParam("目标类型(字典:favorite_resource_type)") @RequestParam String targetType, +@@ -58,7 +60,8 @@ public class MpFavoriteController { + return userFeignClient.checkFavorite(userId, targetType, targetId); + } + +- @ApiOperation("批量删除收藏") ++ @ApiOperation(value = "批量删除收藏", ++ notes = "批量删除多条收藏记录,传入收藏记录ID列表。用于收藏管理页面的批量操作。\n\n**权限**:需登录,仅能删除自己的收藏。") + @DeleteMapping("/batch") + public Result batchDeleteFavorites(HttpServletRequest request, + @ApiParam("收藏ID列表") @RequestBody List ids) { +@@ -66,7 +69,8 @@ public class MpFavoriteController { + return userFeignClient.batchDeleteFavorites(userId, ids); + } + +- @ApiOperation("按目标取消收藏") ++ @ApiOperation(value = "按目标取消收藏", ++ notes = "通过目标类型+目标ID取消收藏,适用于详情页点击取消收藏的场景(不需要知道收藏记录ID)。\n\n**权限**:需登录。") + @DeleteMapping("/by-target") + public Result deleteFavoriteByTarget(HttpServletRequest request, + @ApiParam("目标类型") @RequestParam String targetType, +@@ -75,7 +79,8 @@ public class MpFavoriteController { + return userFeignClient.deleteFavoriteByTarget(userId, targetType, targetId); + } + +- @ApiOperation("取消收藏") ++ @ApiOperation(value = "取消收藏", ++ notes = "通过收藏记录ID取消收藏,适用于收藏列表页的删除操作。\n\n**权限**:需登录,仅能删除自己的收藏。") + @DeleteMapping("/{id}") + public Result deleteFavorite(HttpServletRequest request, + @ApiParam("收藏记录ID") @PathVariable Long id) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java +index c25ed9b..ab02f01 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java +@@ -26,7 +26,7 @@ public class MpFootprintController { + private final MpUserFeignClient userFeignClient; + private final FootprintAggregationService footprintAggregationService; + +- @ApiOperation("记录足迹") ++ @ApiOperation(value = "记录足迹", notes = "记录用户浏览资源的足迹,同一资源重复浏览会更新浏览时间而非新增记录") + @PostMapping + public Result> addFootprint(HttpServletRequest request, + @RequestBody MpFootprintAddRequest body) { +@@ -37,7 +37,8 @@ public class MpFootprintController { + return userFeignClient.addFootprint(userId, map); + } + +- @ApiOperation("足迹列表(含资源摘要)") ++ @ApiOperation(value = "足迹列表(含资源摘要)", ++ notes = "分页查询浏览足迹列表,聚合层会补充每条足迹对应资源的摘要信息(名称、封面图等)。支持按资源类型筛选,按浏览时间倒序。\n\n**权限**:需登录。") + @GetMapping + public Result> listFootprints(HttpServletRequest request, + @ApiParam("资源类型筛选:PRODUCT/SCENIC/RESTAURANT/ACTIVITY") @RequestParam(required = false) String resourceType, +@@ -47,14 +48,16 @@ public class MpFootprintController { + return Result.success(footprintAggregationService.listFootprints(userId, resourceType, page, pageSize)); + } + +- @ApiOperation("删除足迹") ++ @ApiOperation(value = "删除足迹", ++ notes = "删除单条浏览足迹记录。\n\n**权限**:需登录,仅能删除自己的足迹。") + @DeleteMapping("/{id}") + public Result deleteFootprint(HttpServletRequest request, @ApiParam("足迹ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.deleteFootprint(userId, id); + } + +- @ApiOperation("批量删除足迹") ++ @ApiOperation(value = "批量删除足迹", ++ notes = "批量删除多条浏览足迹记录,传入足迹ID列表。用于足迹管理页面的批量清理。\n\n**权限**:需登录,仅能删除自己的足迹。") + @DeleteMapping("/batch") + public Result batchDeleteFootprints(HttpServletRequest request, + @ApiParam("足迹ID列表") @RequestBody List ids) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java +index 8e7cdc5..0c6487f 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java +@@ -18,7 +18,7 @@ public class MpHomeController { + + private final HomeAggregationService homeAggregationService; + +- @ApiOperation(value = "首页数据", notes = "聚合流程:并行获取推荐产品列表+产品线列表+轮播图 → Redis缓存5分钟 → 返回聚合数据") ++ @ApiOperation(value = "首页数据", notes = "聚合流程:并行获取推荐产品列表+产品线列表+轮播图 → Redis缓存5分钟 → 返回聚合数据\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(产品卡片显示)\n- product_status:产品状态(透传自product-service)") + @GetMapping + public Result getHomeData() { + return Result.success(homeAggregationService.getHomeData()); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java +index d820bba..2d649e1 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java +@@ -22,7 +22,8 @@ public class MpHotelController { + private final MpResourceFeignClient resourceFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("酒店列表") ++ @ApiOperation(value = "酒店列表", ++ notes = "分页查询已上架的酒店列表,支持按关键词、城市、星级筛选。聚合层透传resource-service的酒店数据。") + @GetMapping("/list") + public Result>> listHotels( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -39,7 +40,8 @@ public class MpHotelController { + return resourceFeignClient.listHotels(query); + } + +- @ApiOperation("酒店详情") ++ @ApiOperation(value = "酒店详情", ++ notes = "获取酒店完整信息(含房型列表、图文详情、价格等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{hotelId}") + public Result> getHotelDetail(@ApiParam("酒店ID") @PathVariable Long hotelId) { + Result> result = resourceFeignClient.getHotelDetail(hotelId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java +index 3941bc4..d1403a0 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java +@@ -18,7 +18,7 @@ public class MpInsuranceController { + + private final MpInsuranceFeignClient insuranceFeignClient; + +- @ApiOperation(value = "获取订单所有保单PDF", notes = "合并所有出行人的有效保单为一个PDF,返回base64") ++ @ApiOperation(value = "获取订单所有保单PDF", notes = "合并所有出行人的有效保单为一个PDF,返回base64\n\n**关联字典(BFF透传)**:\n- insurance_status:保险状态(返回字段)") + @GetMapping("/policy-pdf/{orderId}") + public Result> getPolicyPdf( + @ApiParam("订单ID") @PathVariable Long orderId) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java +index bda90ad..a42a662 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java +@@ -31,7 +31,7 @@ public class MpInvoiceController { + return orderFeignClient.applyInvoice(userId, body); + } + +- @ApiOperation("发票详情") ++ @ApiOperation(value = "发票详情", notes = "获取发票的完整信息,包含开票状态、发票抬头、税号、金额、电子发票文件链接等") + @GetMapping("/{id}") + public Result> getInvoiceDetail(@ApiParam("发票ID") @PathVariable Long id, + HttpServletRequest request) { +@@ -39,7 +39,7 @@ public class MpInvoiceController { + return orderFeignClient.getInvoiceDetail(id, userId); + } + +- @ApiOperation("通过订单ID查询发票") ++ @ApiOperation(value = "通过订单ID查询发票", notes = "查询指定订单的发票信息,如果订单未开票则返回null") + @GetMapping("/order/{orderId}") + public Result> getInvoiceByOrderId(@ApiParam("订单ID") @PathVariable Long orderId, + HttpServletRequest request) { +@@ -47,7 +47,7 @@ public class MpInvoiceController { + return orderFeignClient.getInvoiceByOrderId(orderId, userId); + } + +- @ApiOperation("发票换开") ++ @ApiOperation(value = "发票换开", notes = "对已开发票申请换开(修改抬头/税号等),原发票作废后重新开具新发票") + @PostMapping("/{invoiceId}/reissue") + public Result> reissueInvoice( + @ApiParam("发票ID") @PathVariable Long invoiceId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java +index d60be9e..c8d50b5 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java +@@ -57,7 +57,8 @@ public class MpLikeController { + return result; + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "检查当前用户是否已对指定目标点赞,用于前端点赞按钮状态展示。\n\n**权限**:需登录。") + @GetMapping("/{targetType}/{targetId}/check") + public Result checkLike( + @ApiParam("目标类型") @PathVariable String targetType, +@@ -67,7 +68,8 @@ public class MpLikeController { + return userFeignClient.checkLikeStatus(targetType.toUpperCase(), targetId, userId); + } + +- @ApiOperation("批量检查点赞状态") ++ @ApiOperation(value = "批量检查点赞状态", ++ notes = "批量检查当前用户是否已对多个目标点赞,返回已点赞的目标ID列表。用于列表页批量展示点赞状态。\n\n**权限**:需登录。") + @PostMapping("/{targetType}/batch-check") + public Result> batchCheckLiked( + @ApiParam("目标类型") @PathVariable String targetType, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java +index bc4abe0..e1f7fa6 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java +@@ -37,7 +37,7 @@ public class MpOrderController { + return orderFeignClient.createOrder(userId, body); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "分页查询当前用户的订单列表,支持按状态筛选。返回订单摘要信息(不含详细出行人信息)\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(列表筛选+显示)\n- product_type:产品类型(订单卡片显示)") + @GetMapping("/list") + public Result> listOrders(HttpServletRequest request, + @ApiParam("状态") @RequestParam(required = false) String status, +@@ -51,7 +51,7 @@ public class MpOrderController { + return orderFeignClient.listOrders(userId, query); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "获取订单完整信息,包含产品快照、出行人列表、支付信息、合同状态等\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(显示)\n- product_type:产品类型(显示)\n- contract_status:合同状态(显示)") + @GetMapping("/{orderId}") + public Result getOrder(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -86,9 +86,10 @@ public class MpOrderController { + return orderFeignClient.cancelOrder(userId, orderId, body != null ? body : new MpCancelOrderRequest()); + } + +- @ApiOperation("通过联系人手机号+姓名查找订单(无需登录)") ++ @ApiOperation(value = "通过联系人手机号+姓名查找订单(无需登录)", ++ notes = "无需登录即可查询。用于管理员代下单场景:管理员创建订单后,用户通过联系人手机号+姓名查找订单并绑定到自己账号。仅返回尚未绑定用户(userId=NULL)的订单。") + @GetMapping("/lookup") +- public Result lookupByContact(@ApiParam("联系人手机号") @RequestParam String contactPhone, ++ public Result>> lookupByContact(@ApiParam("联系人手机号") @RequestParam String contactPhone, + @ApiParam("联系人姓名") @RequestParam String contactName) { + return orderFeignClient.lookupByContact(contactPhone, contactName); + } +@@ -101,7 +102,7 @@ public class MpOrderController { + return orderFeignClient.bindByContact(userId, body); + } + +- @ApiOperation("同意解锁订单") ++ @ApiOperation(value = "同意解锁订单", notes = "用户同意管理员的修改请求,解除订单锁定状态,允许管理员继续修改订单") + @PostMapping("/{orderId}/approve-unlock") + public Result approveUnlock(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -116,7 +117,7 @@ public class MpOrderController { + return orderFeignClient.getUpcomingDepartures(userId); + } + +- @ApiOperation("各状态订单数量") ++ @ApiOperation(value = "各状态订单数量", notes = "统计当前用户各状态的订单数量,用于「我的」页面的订单状态角标展示\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(状态分类统计)") + @GetMapping("/count") + public Result> countByStatus(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java +index 6ddf62a..274102d 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java +@@ -21,7 +21,7 @@ public class MpPaymentController { + private final MpPaymentFeignClient paymentFeignClient; + + @PostMapping("/prepay") +- @ApiOperation(value = "发起支付", notes = "支付流程:选择支付方式(JSAPI/H5) → 调用微信支付API → 返回支付参数 → 前端调起微信支付") ++ @ApiOperation(value = "发起支付", notes = "支付流程:选择支付方式(JSAPI/H5) → 调用微信支付API → 返回支付参数 → 前端调起微信支付\n\n**关联字典(BFF透传)**:\n- payment_status:支付状态(返回字段)") + public Result> prepay( + HttpServletRequest httpRequest, + @ApiParam("支付请求体") @RequestBody MpPaymentPrepayRequest request) { +@@ -30,7 +30,7 @@ public class MpPaymentController { + } + + @GetMapping("/status/{orderId}") +- @ApiOperation("查询支付状态") ++ @ApiOperation(value = "查询支付状态", notes = "**关联字典(BFF透传)**:\n- payment_status:支付状态(显示)") + public Result> getStatus(@ApiParam("订单ID") @PathVariable Long orderId, + HttpServletRequest httpRequest) { + Long userId = (Long) httpRequest.getAttribute("userId"); +@@ -38,8 +38,8 @@ public class MpPaymentController { + } + + @GetMapping("/transactions/{orderId}") +- @ApiOperation("订单交易记录列表") +- public Result listTransactions(@ApiParam("订单ID") @PathVariable Long orderId, ++ @ApiOperation(value = "订单交易记录列表", notes = "**关联字典(BFF透传)**:\n- payment_status:支付状态(显示)") ++ public Result>> listTransactions(@ApiParam("订单ID") @PathVariable Long orderId, + HttpServletRequest httpRequest) { + Long userId = (Long) httpRequest.getAttribute("userId"); + return paymentFeignClient.listTransactions(userId, orderId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java +index 6aa9542..1aa236f 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java +@@ -34,7 +34,7 @@ public class MpProductController { + private final MpOrderFeignClient orderFeignClient; + private final ProductAggregationService productAggregationService; + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", notes = "分页查询已上架产品,支持按关键词、产品类型(CORE/ROUTE/CUSTOM/GROUP)、季节、天数、目的地、产品线筛选和排序\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(列表筛选+显示)\n- product_status:产品状态(透传自product-service)") + @GetMapping("/list") + public Result>> listProducts( + @ApiParam("搜索关键词") @RequestParam(required = false) String keyword, +@@ -63,7 +63,7 @@ public class MpProductController { + return productFeignClient.listProducts(query); + } + +- @ApiOperation(value = "产品详情(聚合收藏状态)", notes = "聚合流程:获取产品详情 → 并行查询收藏状态 → 异步记录足迹 → 返回聚合数据。支持未登录访问(不返回收藏状态)") ++ @ApiOperation(value = "产品详情(聚合收藏状态)", notes = "聚合流程:获取产品详情 → 并行查询收藏状态 → 异步记录足迹 → 返回聚合数据。支持未登录访问(不返回收藏状态)\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(显示)\n- product_status:产品状态(透传自product-service)") + @GetMapping("/{productId}") + public Result getProduct(HttpServletRequest request, + @ApiParam("产品ID") @PathVariable Long productId) { +@@ -256,7 +256,7 @@ public class MpProductController { + } + } + +- @ApiOperation("产品线列表") ++ @ApiOperation(value = "产品线列表", notes = "返回所有已启用的产品线,用于小程序首页或筛选栏展示") + @GetMapping("/lines") + public Result>> listLines() { + return productFeignClient.listActiveLines(); +@@ -284,7 +284,7 @@ public class MpProductController { + return productFeignClient.listBatchCombos(batchId); + } + +- @ApiOperation("价格日历") ++ @ApiOperation(value = "价格日历", notes = "返回产品指定日期范围内的每日价格,用于日历组件展示。不传日期时默认返回未来一个月") + @GetMapping("/{productId}/price-calendar") + public Result>> getPriceCalendar( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java +index 5a72099..71890d6 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java +@@ -32,7 +32,7 @@ public class MpRefundController { + return orderFeignClient.refundPreview(userId, orderId); + } + +- @ApiOperation("退款原因列表") ++ @ApiOperation(value = "退款原因列表", notes = "返回系统预设的退款原因选项,用于退款申请页面的原因选择") + @GetMapping("/refund-reasons") + public Result> listRefundReasons() { + return orderFeignClient.listRefundReasons(); +@@ -48,7 +48,7 @@ public class MpRefundController { + return orderFeignClient.applyRefund(userId, userName, orderId, body); + } + +- @ApiOperation("退款申请详情") ++ @ApiOperation(value = "退款申请详情", notes = "获取退款申请的完整信息,包含审核状态、退款金额、退款进度和操作记录\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(显示)\n- payment_status:支付/退款状态(显示)") + @GetMapping("/refund/{applicationId}") + public Result getRefundDetail(@ApiParam("退款申请ID") @PathVariable Long applicationId, + HttpServletRequest request) { +@@ -56,7 +56,7 @@ public class MpRefundController { + return orderFeignClient.getRefundDetail(userId, applicationId); + } + +- @ApiOperation("根据订单ID获取最新退款详情") ++ @ApiOperation(value = "根据订单ID获取最新退款详情", notes = "查询订单关联的最新一条退款申请详情,无退款记录时返回null\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(显示)\n- payment_status:支付/退款状态(显示)") + @GetMapping("/{orderId}/refund-detail") + public Result getRefundDetailByOrder(@ApiParam("订单ID") @PathVariable String orderId, + HttpServletRequest request) { +@@ -84,7 +84,7 @@ public class MpRefundController { + return orderFeignClient.refundAppeal(userId, applicationId, body); + } + +- @ApiOperation("撤回退款申请") ++ @ApiOperation(value = "撤回退款申请", notes = "仅PENDING状态的退款申请可撤回,撤回后订单恢复到原状态") + @PostMapping("/refund/{applicationId}/cancel") + public Result cancelRefund(@ApiParam("退款申请ID") @PathVariable Long applicationId, + HttpServletRequest request) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java +index 4b75e9b..38fa21b 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java +@@ -22,7 +22,8 @@ public class MpRestaurantController { + private final MpResourceFeignClient resourceFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("餐厅列表") ++ @ApiOperation(value = "餐厅列表", ++ notes = "分页查询已上架的餐厅列表,支持按关键词和城市筛选。聚合层透传resource-service的餐厅数据。") + @GetMapping("/list") + public Result>> listRestaurants( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -37,7 +38,8 @@ public class MpRestaurantController { + return resourceFeignClient.listRestaurants(query); + } + +- @ApiOperation("餐厅详情") ++ @ApiOperation(value = "餐厅详情", ++ notes = "获取餐厅完整信息(含菜品、图文详情等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{restaurantId}") + public Result> getRestaurantDetail(@ApiParam("餐厅ID") @PathVariable Long restaurantId) { + Result> result = resourceFeignClient.getRestaurantDetail(restaurantId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java +index 1f44df4..1cf55b2 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java +@@ -55,7 +55,7 @@ public class MpReviewController { + return Result.success(categories); + } + +- @ApiOperation(value = "创建评价", notes = "评价流程:订单完成后 → 查询可评价目标列表 → 对每个目标(酒店/景区/活动等)提交评价 → 自动内容审核 → 审核通过后公开展示") ++ @ApiOperation(value = "创建评价", notes = "评价流程:订单完成后 → 查询可评价目标列表 → 对每个目标(酒店/景区/活动等)提交评价 → 自动内容审核 → 审核通过后公开展示\n\n**关联字典(BFF透传)**:\n- review_status:评价审核状态(返回字段)\n- rating_level:评价等级(返回字段)") + @PostMapping("/create") + public Result> createReview(@ApiParam("评价请求体") @RequestBody MpReviewCreateRequest body, + HttpServletRequest request) { +@@ -65,7 +65,7 @@ public class MpReviewController { + return reviewFeignClient.createReview(body, userId); + } + +- @ApiOperation("我的评价列表") ++ @ApiOperation(value = "我的评价列表", notes = "**关联字典(BFF透传)**:\n- review_status:评价审核状态(显示)\n- rating_level:评价等级(显示)") + @GetMapping("/my") + public Result>> getMyReviews( + @ApiParam("页码") @RequestParam(defaultValue = "1") Integer page, +@@ -75,7 +75,7 @@ public class MpReviewController { + return reviewFeignClient.getMyReviews(page, pageSize, userId); + } + +- @ApiOperation(value = "关键词搜索评价(公开)", notes = "按关键词搜索已通过的评价内容,支持按目标类型和目标ID筛选") ++ @ApiOperation(value = "关键词搜索评价(公开)", notes = "按关键词搜索已通过的评价内容,支持按目标类型和目标ID筛选\n\n**关联字典(BFF透传)**:\n- rating_level:评价等级(显示)") + @GetMapping("/search") + public Result>> searchReviews( + @ApiParam(value = "搜索关键词", required = true) @RequestParam String keyword, +@@ -86,7 +86,7 @@ public class MpReviewController { + return reviewFeignClient.searchReviews(keyword, targetType, targetId, page, pageSize); + } + +- @ApiOperation("某目标的已通过评价(公开)") ++ @ApiOperation(value = "某目标的已通过评价(公开)", notes = "**关联字典(BFF透传)**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/target") + public Result>> getTargetReviews( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -102,7 +102,7 @@ public class MpReviewController { + return reviewFeignClient.getTargetReviews(targetType, targetId, ratingLevel, hasImage, hasVideo, page, pageSize); + } + +- @ApiOperation(value = "按产品ID查看评价列表", notes = "返回评价列表+统计数据,支持好中差评/有图/有视频筛选") ++ @ApiOperation(value = "按产品ID查看评价列表", notes = "返回评价列表+统计数据,支持好中差评/有图/有视频筛选\n\n**关联字典(BFF透传)**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/product/{productId}") + public Result> getProductReviews( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -144,7 +144,8 @@ public class MpReviewController { + return reviewFeignClient.getProductHighlights(productId); + } + +- @ApiOperation("评价统计(平均分、数量)") ++ @ApiOperation(value = "评价统计(平均分、数量)", ++ notes = "获取指定目标的评价统计数据(平均评分、总评价数等),用于详情页评价区域展示。产品showReview关闭时返回空统计。") + @GetMapping("/stats") + public Result> getTargetStats( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -174,21 +175,23 @@ public class MpReviewController { + return true; // 查询失败时默认显示 + } + +- @ApiOperation(value = "精选评价列表(公开)", notes = "无需登录,返回精选评价数组,用于评价浏览页") ++ @ApiOperation(value = "精选评价列表(公开)", notes = "无需登录,返回精选评价数组,用于评价浏览页\n\n**关联字典(BFF透传)**:\n- rating_level:评价等级(显示)") + @GetMapping("/featured") + public Result>> getFeaturedReviews( + @ApiParam("数量限制") @RequestParam(defaultValue = "50") Integer limit) { + return reviewFeignClient.getFeaturedReviews(limit); + } + +- @ApiOperation("检查订单是否已评价") ++ @ApiOperation(value = "检查订单是否已评价", ++ notes = "检查指定订单是否已提交评价,用于订单详情页决定是否显示'去评价'按钮。") + @GetMapping("/order/{orderId}/reviewed") + public Result isOrderReviewed( + @ApiParam("订单ID") @PathVariable Long orderId) { + return reviewFeignClient.isOrderReviewed(orderId); + } + +- @ApiOperation("订单可评价目标列表") ++ @ApiOperation(value = "订单可评价目标列表", ++ notes = "返回订单中可评价的资源目标列表(景区/酒店/活动等),用于评价页面展示可评价项。已评价的目标不会重复出现。\n\n**权限**:需登录。") + @GetMapping("/order/{orderId}/reviewable-targets") + public Result>> getReviewableTargets( + @ApiParam("订单ID") @PathVariable Long orderId, HttpServletRequest request) { +@@ -196,7 +199,8 @@ public class MpReviewController { + return reviewFeignClient.getReviewableTargets(orderId, userId); + } + +- @ApiOperation("点赞/取消点赞评价") ++ @ApiOperation(value = "点赞/取消点赞评价", ++ notes = "对评价进行点赞或取消点赞操作,返回当前点赞状态和点赞总数。\n\n**权限**:需登录。") + @PostMapping("/{reviewId}/like") + public Result> toggleLike( + @ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { +@@ -204,7 +208,8 @@ public class MpReviewController { + return reviewFeignClient.toggleLike(reviewId, userId); + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "检查当前用户是否已点赞指定评价,用于评价列表/详情的点赞按钮状态展示。\n\n**权限**:需登录。") + @GetMapping("/{reviewId}/like/check") + public Result checkLiked( + @ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java +index 96a4529..8f59647 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java +@@ -27,7 +27,8 @@ public class MpScenicController { + private final MpUserFeignClient userFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("景区列表") ++ @ApiOperation(value = "景区列表", ++ notes = "分页查询已上架的景区列表,支持按关键词和城市筛选。聚合层透传resource-service的景区数据。") + @GetMapping("/list") + public Result>> listScenic( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -42,7 +43,8 @@ public class MpScenicController { + return resourceFeignClient.listScenic(query); + } + +- @ApiOperation("景区详情") ++ @ApiOperation(value = "景区详情", ++ notes = "获取景区完整信息(含季节素材、图文详情、价格等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{scenicId}") + public Result> getScenicDetail(@ApiParam("景区ID") @PathVariable Long scenicId) { + Result> result = resourceFeignClient.getScenicDetail(scenicId); +@@ -52,7 +54,8 @@ public class MpScenicController { + return result; + } + +- @ApiOperation("附近景区(地理+探索分类聚合)") ++ @ApiOperation(value = "附近景区(地理+探索分类聚合)", ++ notes = "聚合两个数据源:1.基于经纬度的地理位置附近景区(resource-service);2.探索分类关联的景区(user-service)。去重合并后返回,用于景区详情页底部'附近推荐'展示。") + @GetMapping("/{scenicId}/nearby") + public Result>> getNearbyScenic( + @ApiParam("景区ID") @PathVariable Long scenicId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java +index 7a2362a..689c544 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java +@@ -20,7 +20,7 @@ public class MpSearchController { + + private final MpProductFeignClient productFeignClient; + +- @ApiOperation("搜索产品") ++ @ApiOperation(value = "搜索产品", notes = "按关键词搜索已上架产品(匹配产品名称和描述),支持按产品类型进一步筛选\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(筛选+显示)") + @GetMapping + public Result>> search( + @ApiParam("搜索关键词") @RequestParam String keyword, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java +index 8831fd0..4f8f4d9 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java +@@ -22,7 +22,7 @@ public class MpTravelerController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("添加出行人") ++ @ApiOperation(value = "添加出行人", notes = "添加常用出行人信息(姓名/证件/联系方式等),下单时可快速选择。单个用户最多50个出行人") + @PostMapping + public Result> addTraveler(HttpServletRequest request, + @RequestBody MpTravelerRequest body) { +@@ -31,21 +31,23 @@ public class MpTravelerController { + return userFeignClient.addTraveler(userId, map); + } + +- @ApiOperation("出行人列表") ++ @ApiOperation(value = "出行人列表", notes = "返回当前用户的所有出行人列表。如果用户已完善实名信息,列表中会自动包含一条「本人」虚拟记录(travelerId=0)") + @GetMapping + public Result>> listTravelers(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.listTravelers(userId); + } + +- @ApiOperation("出行人详情") ++ @ApiOperation(value = "出行人详情", ++ notes = "获取单个出行人的完整信息(姓名、证件信息、联系方式等)。\n\n**权限**:需登录,仅能查看自己的出行人。") + @GetMapping("/{id}") + public Result> getTraveler(HttpServletRequest request, @ApiParam("出行人ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.getTraveler(userId, id); + } + +- @ApiOperation("更新出行人") ++ @ApiOperation(value = "更新出行人", ++ notes = "修改出行人信息,支持部分更新(只传需要修改的字段)。已关联订单的出行人修改不影响历史订单记录。\n\n**权限**:需登录。") + @PutMapping("/{id}") + public Result> updateTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long id, +@@ -55,14 +57,15 @@ public class MpTravelerController { + return userFeignClient.updateTraveler(userId, id, map); + } + +- @ApiOperation("删除出行人") ++ @ApiOperation(value = "删除出行人", ++ notes = "删除常用出行人记录。默认出行人不可删除,需先取消默认后再删除。\n\n**权限**:需登录。") + @DeleteMapping("/{id}") + public Result deleteTraveler(HttpServletRequest request, @ApiParam("出行人ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.deleteTraveler(userId, id); + } + +- @ApiOperation("设为默认出行人") ++ @ApiOperation(value = "设为默认出行人", notes = "设为默认出行人后,下单时自动作为第一个出行人。每个用户只能有一个默认出行人") + @PutMapping("/{id}/default") + public Result setDefaultTraveler(HttpServletRequest request, @ApiParam("出行人ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java +index 5247c6f..9870345 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java +@@ -22,14 +22,14 @@ public class MpTripController { + private final MpOrderFeignClient orderFeignClient; + private final WeatherService weatherService; + +- @ApiOperation(value = "行程列表", notes = "获取当前登录用户的行程列表(已确认及进行中的订单对应的行程)") ++ @ApiOperation(value = "行程列表", notes = "获取当前登录用户的行程列表(已确认及进行中的订单对应的行程)\n\n**关联字典(BFF透传)**:\n- order_status:订单/行程状态(显示)") + @GetMapping("/list") + public Result>> getTripList(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return orderFeignClient.getTripList(userId); + } + +- @ApiOperation(value = "行程详情", notes = "获取订单对应的行程详情,含每日行程节点信息(景点/酒店/餐厅等)") ++ @ApiOperation(value = "行程详情", notes = "获取订单对应的行程详情,含每日行程节点信息(景点/酒店/餐厅等)\n\n**关联字典(BFF透传)**:\n- order_status:订单/行程状态(显示)") + @GetMapping("/{orderId}") + public Result> getTripDetail(HttpServletRequest request, + @ApiParam(value = "订单ID", required = true) @PathVariable Long orderId) { +@@ -37,7 +37,7 @@ public class MpTripController { + return orderFeignClient.getTripDetail(userId, orderId); + } + +- @ApiOperation(value = "今日行程", notes = "获取今日行程(如果有正在进行中的行程),无行程时data为null") ++ @ApiOperation(value = "今日行程", notes = "获取今日行程(如果有正在进行中的行程),无行程时data为null\n\n**关联字典(BFF透传)**:\n- order_status:订单/行程状态(显示)") + @GetMapping("/today") + public Result> getTodayTrip(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java +index 26146f8..249591a 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java +@@ -20,7 +20,7 @@ public class MpUserController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("发送短信验证码") ++ @ApiOperation(value = "发送短信验证码", notes = "向指定手机号发送登录验证码,有效期5分钟,60秒内不可重复发送") + @PostMapping("/sms/send") + public Result sendSmsCode(@RequestBody MpSmsSendRequest request) { + Map map = new java.util.HashMap<>(); +@@ -45,14 +45,14 @@ public class MpUserController { + return userFeignClient.login(map); + } + +- @ApiOperation("获取用户信息") ++ @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的个人资料,包含头像、昵称、手机号、实名信息等") + @GetMapping("/profile") + public Result> getProfile(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.getProfile(userId); + } + +- @ApiOperation("更新用户信息") ++ @ApiOperation(value = "更新用户信息", notes = "更新当前用户的个人资料,支持部分更新(只传需要修改的字段)。首次完善资料时realName为必填") + @PutMapping("/profile") + public Result> updateProfile(HttpServletRequest request, + @RequestBody MpUserProfileUpdateRequest body) { +@@ -69,7 +69,8 @@ public class MpUserController { + return userFeignClient.updateProfile(userId, map); + } + +- @ApiOperation("用户登出") ++ @ApiOperation(value = "用户登出", ++ notes = "清除用户登录状态和服务端缓存的令牌信息。登出后需重新登录获取新令牌。\n\n**权限**:需登录。") + @PostMapping("/logout") + public Result logout(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java +index 9341450..592fba5 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java +@@ -19,21 +19,21 @@ public class MpWeatherController { + + private final MpOrderFeignClient orderFeignClient; + +- @ApiOperation("获取订单行程天气") ++ @ApiOperation(value = "获取订单行程天气", notes = "根据订单行程中的目的地城市,批量查询每日天气信息,用于行程详情页展示") + @GetMapping("/itinerary/{orderId}") + public Result>> getItineraryWeather( + @ApiParam("订单ID") @PathVariable Long orderId) { + return orderFeignClient.getItineraryWeather(orderId); + } + +- @ApiOperation("获取指定城市实况天气") ++ @ApiOperation(value = "获取指定城市实况天气", notes = "通过高德天气API查询指定城市的实时天气(温度、湿度、风向等)") + @GetMapping("/live") + public Result> getLiveWeather( + @ApiParam("城市名称") @RequestParam String city) { + return orderFeignClient.getLiveWeather(city); + } + +- @ApiOperation("获取指定城市天气预报") ++ @ApiOperation(value = "获取指定城市天气预报", notes = "通过高德天气API查询指定城市未来3天的天气预报信息") + @GetMapping("/forecast") + public Result> getForecastWeather( + @ApiParam("城市名称") @RequestParam String city) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java +index 26fe4ac..c70bd36 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java +@@ -20,13 +20,15 @@ public class MpWikiController { + + private final MpWikiFeignClient wikiFeignClient; + +- @ApiOperation("攻略分类列表") ++ @ApiOperation(value = "攻略分类列表", ++ notes = "获取所有已启用的攻略分类,按排序值排列。用于小程序攻略频道的分类导航展示。") + @GetMapping("/categories") + public Result>> listCategories() { + return wikiFeignClient.listEnabledCategories(); + } + +- @ApiOperation("分类文章列表") ++ @ApiOperation(value = "分类文章列表", ++ notes = "分页查询指定攻略分类下已发布的文章列表,按发布时间倒序排列。用于攻略分类详情页。") + @GetMapping("/category/{categoryId}/articles") + public Result>> listCategoryArticles( + @ApiParam("攻略分类ID") @PathVariable Long categoryId, +@@ -35,13 +37,14 @@ public class MpWikiController { + return wikiFeignClient.listCategoryArticles(categoryId, page, pageSize); + } + +- @ApiOperation("文章详情") ++ @ApiOperation(value = "文章详情", notes = "**关联字典(BFF透传)**:\n- wiki_status:文章状态(返回字段)") + @GetMapping("/article/{articleId}") + public Result> getArticle(@ApiParam("文章ID") @PathVariable Long articleId) { + return wikiFeignClient.getArticle(articleId); + } + +- @ApiOperation("推荐文章列表") ++ @ApiOperation(value = "推荐文章列表", ++ notes = "获取编辑推荐的攻略文章列表(按推荐权重排序),用于首页或攻略频道的推荐位展示。") + @GetMapping("/recommend-articles") + public Result>> listRecommendArticles( + @ApiParam("返回条数") @RequestParam(defaultValue = "10") Integer limit) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java +index f9abab8..d9d2416 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java +@@ -21,14 +21,14 @@ public class MpWishController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("心愿单列表") ++ @ApiOperation(value = "心愿单列表", notes = "返回当前用户的心愿单列表,按创建时间倒序排列") + @GetMapping + public Result>> listWishes(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.listWishes(userId); + } + +- @ApiOperation("创建心愿") ++ @ApiOperation(value = "创建心愿", notes = "创建旅行心愿,描述想去的地方和时间偏好,定制师可据此推荐产品") + @PostMapping + public Result> createWish(@ApiParam("心愿请求体") @RequestBody MpWishCreateRequest body, + HttpServletRequest request) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java +index 9b8e419..dce7686 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java +@@ -28,7 +28,7 @@ public class AdminAlbumController { + + // ==================== 文件夹管理 ==================== + +- @ApiOperation("创建相册文件夹") ++ @ApiOperation(value = "创建相册文件夹", notes = "为订单创建旅行相册文件夹(如'第一天风景'、'合影'等),用于组织旅途照片/视频") + @PostMapping("/{orderId}/album/folder") + public Result createFolder( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -38,7 +38,7 @@ public class AdminAlbumController { + return Result.success(albumService.createFolder(orderId, request, adminId)); + } + +- @ApiOperation("编辑相册文件夹") ++ @ApiOperation(value = "编辑相册文件夹", notes = "修改文件夹名称或描述。仅创建者或超级管理员可操作") + @PutMapping("/album/folder/{folderId}") + public Result updateFolder( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -49,7 +49,7 @@ public class AdminAlbumController { + return Result.success(albumService.updateFolder(folderId, request, adminId, roleKey)); + } + +- @ApiOperation("删除相册文件夹") ++ @ApiOperation(value = "删除相册文件夹", notes = "删除文件夹及其下所有文件。仅创建者或超级管理员可操作。删除后C端用户不再可见") + @DeleteMapping("/album/folder/{folderId}") + public Result deleteFolder( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -60,7 +60,8 @@ public class AdminAlbumController { + return Result.success(null); + } + +- @ApiOperation("查询订单的文件夹列表") ++ @ApiOperation(value = "查询订单的文件夹列表", ++ notes = "获取指定订单的所有相册文件夹,含文件夹名称、描述、封面图、文件数量等信息。") + @GetMapping("/{orderId}/album/folders") + public Result> listFolders( + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -69,7 +70,11 @@ public class AdminAlbumController { + + // ==================== 文件管理 ==================== + +- @ApiOperation("批量添加文件到文件夹") ++ @ApiOperation(value = "批量添加文件到文件夹", notes = "一次添加多个照片/视频到指定文件夹。文件需先通过文件服务上传获取OSS URL\n\n" + ++ "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/album/folder/{folderId}/files") + public Result> addFiles( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -80,7 +85,10 @@ public class AdminAlbumController { + return Result.success(albumService.addFiles(folderId, request, adminId, roleKey)); + } + +- @ApiOperation("编辑文件信息") ++ @ApiOperation(value = "编辑文件信息", notes = "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PutMapping("/album/file/{albumFileId}") + public Result updateFile( + @ApiParam("相册文件ID") @PathVariable Long albumFileId, +@@ -91,7 +99,8 @@ public class AdminAlbumController { + return Result.success(albumService.updateFile(albumFileId, request, adminId, roleKey)); + } + +- @ApiOperation("删除文件") ++ @ApiOperation(value = "删除文件", ++ notes = "删除相册中的单个文件(照片/视频)。仅上传者或超级管理员可操作,删除后C端用户不再可见。") + @DeleteMapping("/album/file/{albumFileId}") + public Result deleteFile( + @ApiParam("相册文件ID") @PathVariable Long albumFileId, +@@ -102,7 +111,10 @@ public class AdminAlbumController { + return Result.success(null); + } + +- @ApiOperation("查询文件夹下的文件列表") ++ @ApiOperation(value = "查询文件夹下的文件列表", notes = "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/album/folder/{folderId}/files") + public Result> listFiles( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -111,7 +123,8 @@ public class AdminAlbumController { + return Result.success(albumService.listFiles(folderId, page, size)); + } + +- @ApiOperation("设置文件夹封面") ++ @ApiOperation(value = "设置文件夹封面", ++ notes = "将文件夹中的指定文件设为封面图,封面图会在文件夹列表中展示。仅上传者或超级管理员可操作。") + @PutMapping("/album/folder/{folderId}/cover") + public Result setCover( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -123,7 +136,11 @@ public class AdminAlbumController { + return Result.success(null); + } + +- @ApiOperation("我的上传(当前管理员上传的所有相册文件)") ++ @ApiOperation(value = "我的上传", notes = "查询当前管理员上传的所有相册文件(跨订单),方便管理自己上传的内容\n\n" + ++ "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/album/my-uploads") + public Result> listMyUploads( + HttpServletRequest httpRequest, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java +index 261c457..85b97c1 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java +@@ -31,7 +31,7 @@ public class AdminEarlyBirdController { + } + } + +- @ApiOperation("早鸟优惠计划列表") ++ @ApiOperation(value = "早鸟优惠计划列表", notes = "分页查询所有早鸟优惠计划。权限:仅超级管理员(SUPER_ADMIN)") + @GetMapping("/list") + public Result> list(HttpServletRequest request, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -41,7 +41,7 @@ public class AdminEarlyBirdController { + return Result.success(result); + } + +- @ApiOperation("早鸟优惠计划详情") ++ @ApiOperation(value = "早鸟优惠计划详情", notes = "权限:仅超级管理员(SUPER_ADMIN)") + @GetMapping("/{planId}") + public Result detail(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId) { +@@ -50,7 +50,8 @@ public class AdminEarlyBirdController { + return Result.success(vo); + } + +- @ApiOperation("创建早鸟优惠计划") ++ @ApiOperation(value = "创建早鸟优惠计划", notes = "创建一个早鸟优惠计划,在指定日期范围内下单且满足最低人数条件的订单可享受优惠。\n" + ++ "下单时系统自动匹配最优的早鸟计划。权限:仅超级管理员(SUPER_ADMIN)") + @PostMapping + public Result create(HttpServletRequest request, + @ApiParam("创建早鸟计划请求") @Valid @RequestBody EarlyBirdPlanRequest planRequest) { +@@ -61,7 +62,7 @@ public class AdminEarlyBirdController { + return Result.success(vo); + } + +- @ApiOperation("修改早鸟优惠计划") ++ @ApiOperation(value = "修改早鸟优惠计划", notes = "权限:仅超级管理员(SUPER_ADMIN)。修改不影响已下单的订单优惠") + @PutMapping("/{planId}") + public Result update(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId, +@@ -71,7 +72,7 @@ public class AdminEarlyBirdController { + return Result.success(); + } + +- @ApiOperation("删除早鸟优惠计划") ++ @ApiOperation(value = "删除早鸟优惠计划", notes = "权限:仅超级管理员(SUPER_ADMIN)。删除不影响已下单的订单优惠") + @DeleteMapping("/{planId}") + public Result delete(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId) { +@@ -80,7 +81,7 @@ public class AdminEarlyBirdController { + return Result.success(); + } + +- @ApiOperation("启用/禁用早鸟优惠计划") ++ @ApiOperation(value = "启用/禁用早鸟优惠计划", notes = "禁用后该计划不再参与自动匹配。权限:仅超级管理员(SUPER_ADMIN)") + @PutMapping("/{planId}/toggle") + public Result toggle(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java +index de26a0f..d79934d 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java +@@ -27,7 +27,8 @@ public class AdminOrderConfigController { + @Value("${order.expiry.redis-key:order:config:expiry-minutes}") + private String expiryRedisKey; + +- @ApiOperation("获取订单过期配置") ++ @ApiOperation(value = "获取订单过期配置", notes = "获取当前的订单未支付自动过期时间(分钟)。\n" + ++ "返回当前值、默认值和配置来源(redis=已自定义, default=使用默认值)") + @GetMapping("/expiry-minutes") + public Result> getExpiryMinutes() { + String val = stringRedisTemplate.opsForValue().get(expiryRedisKey); +@@ -45,7 +46,8 @@ public class AdminOrderConfigController { + )); + } + +- @ApiOperation("设置订单过期时间(分钟)") ++ @ApiOperation(value = "设置订单过期时间(分钟)", notes = "修改订单未支付自动取消的等待时间。存储在Redis中,即时生效。\n" + ++ "仅影响新创建的订单,已有订单的过期时间不变") + @PutMapping("/expiry-minutes") + public Result setExpiryMinutes(@ApiParam("修改订单过期时间请求") @Valid @RequestBody UpdateExpiryMinutesRequest expiryRequest) { + stringRedisTemplate.opsForValue().set(expiryRedisKey, String.valueOf(expiryRequest.getMinutes())); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java +index e7f09ce..72bdfc8 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java +@@ -47,7 +47,18 @@ public class AdminOrderController { + private static final String ORDER_CREATE_DEDUP = "order:admin:create:dedup:"; + + @ApiOperation(value = "创建订单(定制师代下单)", notes = "创建订单流程:选择产品 → 填写联系人和出行人 → 系统计算报价 → 生成订单(PENDING_PAY状态)\n\n" + +- "权限:CUSTOM产品仅创建者可下单,CORE/ROUTE产品所有管理员可下单") ++ "权限:CUSTOM产品仅创建者可下单,CORE/ROUTE产品所有管理员可下单\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)") + @PostMapping("/create") + public Result createOrder(HttpServletRequest request, + @ApiParam("创建订单请求") @Valid @RequestBody AdminCreateOrderRequest createRequest) { +@@ -69,21 +80,41 @@ public class AdminOrderController { + } + } + +- @ApiOperation("报价预览") ++ @ApiOperation(value = "报价预览", notes = "根据产品、出发日期、人数组合实时计算报价。\n" + ++ "返回各资源明细价格和合计金额,前端据此展示报价清单。\n\n" + ++ "注意:报价仅供参考,最终价格以创建订单时为准(价格日历可能变动)") + @PostMapping("/quote") + public Result> quotePreview(@ApiParam("报价预览请求") @Valid @RequestBody QuotePreviewRequest quoteRequest) { + Map result = orderService.quotePreview(quoteRequest); + return Result.success(result); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "支持按关键词(订单号/联系人/产品名)、状态、内部流程状态、产品类型筛选。\n" + ++ "支持按创建时间/出发日期/总价排序。\n\n" + ++ "返回分页结果,包含订单基本信息、状态、支付信息和产品封面\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 筛选参数 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 筛选参数 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> listOrders(@ApiParam("订单查询请求") AdminOrderQueryRequest request) { + PageResult result = orderService.listAdminOrders(request); + return Result.success(result); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "返回订单完整信息,包括:基本信息、产品快照、联系人、出行人列表、支付记录、优惠明细、时间线、内部流程状态等\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 timeline[].action → 字典:order_timeline_action(订单操作类型)\n" + ++ "- 返回字段 todos[].todoType → 字典:order_todo_type(订单待办类型)") + @GetMapping("/{orderId}") + public Result getOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + OrderDetailVO detail = orderService.getAdminOrderDetail(orderId); +@@ -111,7 +142,9 @@ public class AdminOrderController { + "- 旅行中 → 已完成\n" + + "- 已完成 → 售后中\n" + + "- 售后中 → 退款中\n" + +- "- 退款中 → 已退款") ++ "- 退款中 → 已退款\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 status → 字典:order_status(订单状态)") + @PutMapping("/{orderId}/status") + public Result updateStatus(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -134,7 +167,7 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("添加备注") ++ @ApiOperation(value = "添加备注", notes = "向订单时间线添加一条管理员备注。备注会记录操作人和时间,可用于内部沟通和订单跟踪") + @PostMapping("/{orderId}/remark") + public Result addRemark(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -145,7 +178,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("修改定金金额") ++ @ApiOperation(value = "修改定金金额", notes = "修改订单的定金金额。仅待支付(PENDING_PAY)状态可修改。\n\n" + ++ "定金金额不能超过订单总价,修改后影响用户支付页面显示的应付金额") + @PutMapping("/{orderId}/deposit") + public Result updateDeposit(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -156,7 +190,14 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("编辑订单") ++ @ApiOperation(value = "编辑订单", notes = "修改订单的联系人、人数、出发日期、售价、成本、备注等信息。\n" + ++ "仅传入需要修改的字段,未传入的字段不会被修改。\n\n" + ++ "如果提供了出行人列表(travelers),将替换订单的全部出行人。\n" + ++ "已锁定的订单需先调用'申请修改'接口解锁后才能编辑\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)") + @PutMapping("/{orderId}") + public Result editOrder(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -167,7 +208,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("更新房间信息(仅房务管理员/超级管理员)") ++ @ApiOperation(value = "更新房间信息(仅房务管理员/超级管理员)", ++ notes = "更新订单的房间分配信息(房型、房间号、入住安排等)。\n\n**权限**:仅ROOM_MANAGER(房务管理员)或SUPER_ADMIN(超级管理员)可操作。") + @PutMapping("/{orderId}/room-info") + public Result updateRoomInfo(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -183,7 +225,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("更新车辆信息(仅车务管理员/超级管理员)") ++ @ApiOperation(value = "更新车辆信息(仅车务管理员/超级管理员)", ++ notes = "更新订单的车辆分配信息(车型、车牌号、司机等)。\n\n**权限**:仅VEHICLE_MANAGER(车务管理员)或SUPER_ADMIN(超级管理员)可操作。") + @PutMapping("/{orderId}/vehicle-info") + public Result updateVehicleInfo(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -210,7 +253,9 @@ public class AdminOrderController { + } + + @ApiOperation(value = "推进内部流程", notes = "内部流程推进顺序:待配房(PENDING_ROOM) → 待配车(PENDING_VEHICLE) → 待核算(PENDING_FINANCE) → 就绪(READY)\n\n" + +- "仅在订单状态为已确认(CONFIRMED)时有效,每次调用自动推进到下一步") ++ "仅在订单状态为已确认(CONFIRMED)时有效,每次调用自动推进到下一步\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 processStatus → 字典:order_process_status(订单内部流程状态)") + @PutMapping("/{orderId}/process-status") + public Result advanceProcessStatus(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -220,7 +265,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("添加优惠项") ++ @ApiOperation(value = "添加优惠项", notes = "为订单添加手动优惠(如会员折扣、老客优惠等)。\n" + ++ "添加后系统自动重算订单应付金额。一个订单可添加多个优惠项") + @PostMapping("/{orderId}/discount") + public Result addDiscount(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -231,7 +277,7 @@ public class AdminOrderController { + return Result.success(discount); + } + +- @ApiOperation("修改优惠项") ++ @ApiOperation(value = "修改优惠项", notes = "修改已添加的优惠项名称或金额,修改后自动重算订单应付金额") + @PutMapping("/{orderId}/discount/{discountId}") + public Result updateDiscount(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -243,7 +289,7 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("删除优惠项") ++ @ApiOperation(value = "删除优惠项", notes = "删除已添加的优惠项,删除后自动重算订单应付金额") + @DeleteMapping("/{orderId}/discount/{discountId}") + public Result removeDiscount(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -296,7 +342,8 @@ public class AdminOrderController { + return Result.success(diff); + } + +- @ApiOperation("分配车辆信息") ++ @ApiOperation(value = "分配车辆信息", notes = "为订单分配具体的车辆和司机信息(车型、品牌、车牌号、司机姓名和电话)。\n" + ++ "分配后信息将展示在订单详情和C端行程中") + @PutMapping("/{orderId}/vehicle-assignment") + public Result assignVehicle(@ApiParam("订单ID") @PathVariable Long orderId, + @RequestBody @Valid VehicleAssignmentRequest request) { +@@ -304,7 +351,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("分配酒店信息") ++ @ApiOperation(value = "分配酒店信息", notes = "按家庭为订单分配具体的酒店房间(酒店名称、房型、入住/退房日期)。\n" + ++ "每个家庭对应一条分配记录,分配后信息将展示在订单详情和C端行程中") + @PutMapping("/{orderId}/hotel-assignment") + public Result assignHotel(@ApiParam("订单ID") @PathVariable Long orderId, + @RequestBody @Valid HotelAssignmentRequest request) { +@@ -312,7 +360,7 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("设置尾款支付方式") ++ @ApiOperation(value = "设置尾款支付方式", notes = "设置订单尾款的支付方式。ONLINE=线上微信支付,OFFLINE=线下转账(需管理员手动记录尾款到账)") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java +index 83ae39c..9ab5d5e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java +@@ -31,7 +31,11 @@ public class AdminOrderItineraryController { + private final OrderItineraryEditService itineraryEditService; + private final OrderPriceDiffService priceDiffService; + +- @ApiOperation(value = "跳过节点", notes = "将行程中的某个节点标记为跳过(客户不去)") ++ @ApiOperation(value = "跳过节点", notes = "将行程中的某个节点标记为跳过(客户不去)\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/skip") + public Result skipNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -43,7 +47,10 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.skipNode(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "恢复跳过的节点", notes = "取消跳过,恢复为正常状态") ++ @ApiOperation(value = "恢复跳过的节点", notes = "取消跳过,恢复为正常状态\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/skip/{editId}") + public Result unskipNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -58,7 +65,11 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation(value = "新增节点", notes = "在某一天的行程中新增一个节点") ++ @ApiOperation(value = "新增节点", notes = "在某一天的行程中新增一个节点\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/add") + public Result addNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -76,7 +87,10 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.addNode(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "删除新增的节点", notes = "删除通过编辑新增的节点") ++ @ApiOperation(value = "删除新增的节点", notes = "删除通过编辑新增的节点\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/add/{editId}") + public Result removeAddedNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -91,7 +105,10 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation("获取合并后的行程(原始+编辑)") ++ @ApiOperation(value = "获取合并后的行程(原始+编辑)", notes = "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/merged") + public Result>> getMergedItinerary( + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -105,14 +122,19 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.getBalanceAdjustmentSummary(orderId)); + } + +- @ApiOperation("获取行程编辑记录列表") ++ @ApiOperation(value = "获取行程编辑记录列表", notes = "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/edits") + public Result> getEditList( + @ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(itineraryEditService.getEditList(orderId)); + } + +- @ApiOperation(value = "房型切换差价预览", notes = "预览房型切换的差价,不创建记录") ++ @ApiOperation(value = "房型切换差价预览", notes = "预览房型切换的差价,不创建记录\n\n" + ++ "**关联字典**:\n" + ++ "- resource_type(资源类型,返回字段resourceType):HOTEL=酒店") + @PostMapping("/room-type-change/preview") + public Result previewRoomTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -120,7 +142,11 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.previewRoomTypeDiff(orderId, request)); + } + +- @ApiOperation(value = "房型切换", notes = "执行房型切换,自动计算差价,创建待确认记录") ++ @ApiOperation(value = "房型切换", notes = "执行房型切换,自动计算差价,创建待确认记录\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):ROOM_CHANGE=房型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):HOTEL=酒店") + @PostMapping("/room-type-change") + public Result roomTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -132,7 +158,9 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.executeRoomTypeChange(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "车型切换差价预览", notes = "预览车型切换的差价,不创建记录") ++ @ApiOperation(value = "车型切换差价预览", notes = "预览车型切换的差价,不创建记录\n\n" + ++ "**关联字典**:\n" + ++ "- resource_type(资源类型,返回字段resourceType):VEHICLE=车辆") + @PostMapping("/vehicle-type-change/preview") + public Result previewVehicleTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -140,7 +168,11 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.previewVehicleTypeDiff(orderId, request)); + } + +- @ApiOperation(value = "车型切换", notes = "执行车型切换,自动计算差价,创建待确认记录") ++ @ApiOperation(value = "车型切换", notes = "执行车型切换,自动计算差价,创建待确认记录\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):VEHICLE=车辆") + @PostMapping("/vehicle-type-change") + public Result vehicleTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -152,7 +184,11 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.executeVehicleTypeChange(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "新增整天行程", notes = "在订单行程中新增一整天(含多个节点)") ++ @ApiOperation(value = "新增整天行程", notes = "在订单行程中新增一整天(含多个节点)\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):ADD_DAY=新增整天\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/add-day") + public Result> addDay( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -164,7 +200,9 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.addDay(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "删除新增的整天行程", notes = "删除通过新增操作添加的整天行程及其所有子节点,已确认的天不允许删除") ++ @ApiOperation(value = "删除新增的整天行程", notes = "删除通过新增操作添加的整天行程及其所有子节点,已确认的天不允许删除\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/day/{editId}") + public Result removeDay( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -179,7 +217,11 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation(value = "修改编辑记录", notes = "修改待确认状态的编辑记录(如调整价格、名称等)") ++ @ApiOperation(value = "修改编辑记录", notes = "修改待确认状态的编辑记录(如调整价格、名称等)\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PutMapping("/edit/{editId}") + public Result updateEdit( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -192,7 +234,9 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.updateEdit(orderId, editId, updates, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "确认单条修改", notes = "确认一条待确认的行程编辑") ++ @ApiOperation(value = "确认单条修改", notes = "确认一条待确认的行程编辑\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @PostMapping("/confirm/{editId}") + public Result confirmEdit( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -205,7 +249,9 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation(value = "批量确认所有待确认修改", notes = "确认该订单所有待确认的行程编辑") ++ @ApiOperation(value = "批量确认所有待确认修改", notes = "确认该订单所有待确认的行程编辑\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @PostMapping("/confirm-all") + public Result confirmAllPending( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -216,7 +262,9 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.confirmAllPending(orderId, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "撤回待确认的修改", notes = "软删除一条待确认的编辑记录") ++ @ApiOperation(value = "撤回待确认的修改", notes = "软删除一条待确认的编辑记录\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/pending/{editId}") + public Result withdrawPendingEdit( + @ApiParam("订单ID") @PathVariable Long orderId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java +index d7339d2..f708a7f 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java +@@ -29,14 +29,21 @@ public class AdminOrderTodoController { + private final OrderService orderService; + private final UserFeignClient userFeignClient; + +- @ApiOperation("获取订单待办列表") ++ @ApiOperation(value = "获取订单待办列表", notes = "返回指定订单的所有待办项(含已完成和未完成)。\n" + ++ "待办类型包括:配房、配车、签合同、购保险、核算等,随内部流程自动生成\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 todoType → 字典:order_todo_type(订单待办类型)") + @GetMapping("/{orderId}/todos") + public Result> getOrderTodos(@ApiParam("订单ID") @PathVariable Long orderId) { + List todos = orderTodoService.listByOrderId(orderId); + return Result.success(todos); + } + +- @ApiOperation("完成待办") ++ @ApiOperation(value = "完成待办", notes = "将指定待办标记为已完成。\n" + ++ "需要对应角色权限:如配房待办需ROOM_MANAGER角色,配车待办需VEHICLE_MANAGER角色。\n\n" + ++ "完成后系统自动检查是否所有必要待办已完成,若是则推进内部流程\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 todoType → 字典:order_todo_type(订单待办类型)") + @PutMapping("/todo/{todoId}/complete") + public Result completeTodo(HttpServletRequest request, + @ApiParam("待办ID") @PathVariable Long todoId) { +@@ -47,7 +54,11 @@ public class AdminOrderTodoController { + return Result.success(); + } + +- @ApiOperation("我的待办列表") ++ @ApiOperation(value = "我的待办列表", notes = "根据当前管理员ID和角色,查询分配给自己的未完成待办。\n" + ++ "超级管理员可看到所有待办,其他角色只能看到对应类型的待办\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 todoType → 字典:order_todo_type(订单待办类型)\n" + ++ "- 返回字段 orderStatus → 字典:order_status(订单状态)") + @GetMapping("/todo/my-list") + public Result> getMyTodos(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -56,7 +67,7 @@ public class AdminOrderTodoController { + return Result.success(todos); + } + +- @ApiOperation("我的待办数量") ++ @ApiOperation(value = "我的待办数量", notes = "返回当前管理员未完成的待办总数,用于首页角标/红点提醒") + @GetMapping("/todo/my-count") + public Result getMyTodosCount(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -65,7 +76,7 @@ public class AdminOrderTodoController { + return Result.success(count); + } + +- @ApiOperation("定制师列表") ++ @ApiOperation(value = "定制师列表", notes = "获取所有定制师(CUSTOMIZER角色)的列表,用于更换定制师时选择目标定制师") + @GetMapping("/todo/customizer-list") + public Result> getCustomizerList() { + try { +@@ -79,7 +90,7 @@ public class AdminOrderTodoController { + return Result.success(Collections.emptyList()); + } + +- @ApiOperation("更换定制师") ++ @ApiOperation(value = "更换定制师", notes = "将订单转派给另一位定制师。更换后原定制师的待办自动转移,订单时间线会记录此操作") + @PutMapping("/{orderId}/customizer") + public Result changeCustomizer(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -90,7 +101,11 @@ public class AdminOrderTodoController { + return Result.success(); + } + +- @ApiOperation("可签合同订单列表(保险已完成)") ++ @ApiOperation(value = "可签合同订单列表(保险已完成)", notes = "查询保险待办已完成、可以进入签合同环节的订单列表。\n" + ++ "用于合同管理页面展示待签合同的订单\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 todoType → 字典:order_todo_type(订单待办类型)\n" + ++ "- 返回字段 orderStatus → 字典:order_status(订单状态)") + @GetMapping("/todo/contract-eligible") + public Result> getContractEligibleOrders(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java +index fddef53..eb92d44 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java +@@ -31,7 +31,11 @@ public class AdminRefundController { + + // ==================== Refund Applications ==================== + +- @ApiOperation("退款申请列表") ++ @ApiOperation(value = "退款申请列表", notes = "分页查询退款申请,支持按状态筛选。\n" + ++ "状态包括:PENDING(待审批)、APPROVED(已通过)、REJECTED(已拒绝)、REFUNDING(退款中)、REFUNDED(已退款)、CANCELLED(已撤回)、APPEAL(申诉中)\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:refund_status(退款状态)\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/list") + public Result> listApplications( + @ApiParam("状态") @RequestParam(required = false) String status, +@@ -40,14 +44,18 @@ public class AdminRefundController { + return Result.success(refundApplicationService.listApplications(status, page, pageSize)); + } + +- @ApiOperation("退款申请详情") ++ @ApiOperation(value = "退款申请详情", notes = "返回退款申请的完整信息,包括退款原因、申请金额、实退金额、审批记录、申诉信息等\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/{applicationId}") + public Result getDetail(@ApiParam("退款申请ID") @PathVariable Long applicationId) { + return Result.success(refundApplicationService.getDetail(applicationId)); + } + + @ApiOperation(value = "审批退款申请", notes = "退款审批流程:查看退款申请 → 决定通过/拒绝 → 通过时填写实退金额 → 系统自动调起微信退款\n\n" + +- "拒绝后用户可发起申诉") ++ "拒绝后用户可发起申诉\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @PutMapping("/{applicationId}/review") + public Result review(HttpServletRequest request, + @ApiParam("退款申请ID") @PathVariable Long applicationId, +@@ -79,20 +87,26 @@ public class AdminRefundController { + + // ==================== Refund Reasons ==================== + +- @ApiOperation("退款原因列表") ++ @ApiOperation(value = "退款原因列表", notes = "获取所有退款原因选项(含禁用的),用于退款原因管理页面\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 category → 字典:refund_reason_category(退款原因分类)") + @GetMapping("/reason/list") + public Result> listReasons() { + return Result.success(refundReasonService.listReasons(false)); + } + +- @ApiOperation("创建退款原因") ++ @ApiOperation(value = "创建退款原因", notes = "新增退款原因选项,C端用户申请退款时可选择。按sortOrder排序展示\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 category → 字典:refund_reason_category(退款原因分类)") + @PostMapping("/reason") + public Result createReason(@ApiParam("创建退款原因请求") @Valid @RequestBody CreateRefundReasonRequest createRequest) { + return Result.success(refundReasonService.createReason( + createRequest.getReasonText(), createRequest.getCategory(), createRequest.getSortOrder())); + } + +- @ApiOperation("修改退款原因") ++ @ApiOperation(value = "修改退款原因", notes = "修改退款原因的文本、分类或排序,不影响已使用该原因的历史退款申请\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 category → 字典:refund_reason_category(退款原因分类)") + @PutMapping("/reason/{reasonId}") + public Result updateReason(@ApiParam("退款原因ID") @PathVariable Long reasonId, + @ApiParam("修改退款原因请求") @Valid @RequestBody UpdateRefundReasonRequest updateRequest) { +@@ -100,7 +114,7 @@ public class AdminRefundController { + reasonId, updateRequest.getReasonText(), updateRequest.getCategory(), updateRequest.getSortOrder())); + } + +- @ApiOperation("删除退款原因") ++ @ApiOperation(value = "删除退款原因", notes = "软删除退款原因,删除后C端不再展示。不影响已使用该原因的历史退款申请") + @DeleteMapping("/reason/{reasonId}") + public Result deleteReason(@ApiParam("退款原因ID") @PathVariable Long reasonId) { + refundReasonService.deleteReason(reasonId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java +index 9ff5005..e1bc0c8 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java +@@ -22,13 +22,17 @@ public class AdminRefundPolicyController { + + private final RefundPolicyService refundPolicyService; + +- @ApiOperation("退款政策列表") ++ @ApiOperation(value = "退款政策列表", notes = "【关联字典】\n" + ++ "- 返回字段 refundType → 字典:refund_type(退款类型)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> list() { + return Result.success(refundPolicyService.listPolicies()); + } + +- @ApiOperation("退款政策详情") ++ @ApiOperation(value = "退款政策详情", notes = "【关联字典】\n" + ++ "- 返回字段 refundType → 字典:refund_type(退款类型)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/{policyId}") + public Result detail(@ApiParam("退款政策ID") @PathVariable Long policyId) { + return Result.success(refundPolicyService.getDetail(policyId)); +@@ -36,7 +40,10 @@ public class AdminRefundPolicyController { + + @ApiOperation(value = "创建退款政策", notes = "退款政策定义按产品类型和距出发天数的退款比例阶梯\n\n" + + "例如:出发前30天退90%,前15天退70%,前7天退50%,7天内不可退\n\n" + +- "每种产品类型可配置独立的退款政策,用户申请退款时系统自动匹配") ++ "每种产品类型可配置独立的退款政策,用户申请退款时系统自动匹配\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 refundType → 字典:refund_type(退款类型)\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)") + @PostMapping + public Result create(HttpServletRequest request, + @ApiParam("创建退款政策请求") @Valid @RequestBody RefundPolicyRequest policyRequest) { +@@ -44,14 +51,17 @@ public class AdminRefundPolicyController { + return Result.success(refundPolicyService.createPolicy(policyRequest, adminId)); + } + +- @ApiOperation("修改退款政策") ++ @ApiOperation(value = "修改退款政策", notes = "【关联字典】\n" + ++ "- 请求参数 refundType → 字典:refund_type(退款类型)\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)") + @PutMapping("/{policyId}") + public Result update(@ApiParam("退款政策ID") @PathVariable Long policyId, + @ApiParam("修改退款政策请求") @Valid @RequestBody RefundPolicyRequest policyRequest) { + return Result.success(refundPolicyService.updatePolicy(policyId, policyRequest)); + } + +- @ApiOperation("删除退款政策") ++ @ApiOperation(value = "删除退款政策", ++ notes = "软删除退款政策。删除后该产品类型将使用默认退款规则。不影响已使用该政策处理的历史退款申请。") + @DeleteMapping("/{policyId}") + public Result delete(@ApiParam("退款政策ID") @PathVariable Long policyId) { + refundPolicyService.deletePolicy(policyId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java +index 949f142..faf973b 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java +@@ -25,7 +25,15 @@ public class AdminWorkOrderController { + + private final WorkOrderService workOrderService; + +- @ApiOperation("工单列表") ++ @ApiOperation(value = "工单列表", notes = "分页查询工单,支持按状态/类型/优先级/订单编号/处理人筛选。\n" + ++ "工单用于处理旅行中的突发变更需求(如换房、换车、加景点等)\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:work_order_status(工单状态)\n" + ++ "- 筛选参数 type → 字典:work_order_type(工单类型)\n" + ++ "- 筛选参数 priority → 字典:work_order_priority(工单优先级)\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)\n" + ++ "- 返回字段 type → 字典:work_order_type(工单类型)\n" + ++ "- 返回字段 priority → 字典:work_order_priority(工单优先级)") + @GetMapping("/list") + public Result> list( + @ApiParam("状态: PENDING/PROCESSING/RESOLVED/REJECTED") @RequestParam(required = false) String status, +@@ -38,19 +46,32 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.listWorkOrders(status, type, priority, orderNo, assigneeAdminId, page, pageSize)); + } + +- @ApiOperation("工单详情") ++ @ApiOperation(value = "工单详情", notes = "返回工单完整信息,包括关联订单、资源详情、处理记录和备注列表\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)\n" + ++ "- 返回字段 type → 字典:work_order_type(工单类型)\n" + ++ "- 返回字段 priority → 字典:work_order_priority(工单优先级)") + @GetMapping("/{workOrderId}") + public Result getDetail(@ApiParam("工单ID") @PathVariable Long workOrderId) { + return Result.success(workOrderService.getDetail(workOrderId)); + } + +- @ApiOperation("工单统计(待处理数等)") ++ @ApiOperation(value = "工单统计", notes = "返回各状态的工单数量和紧急工单数,用于工单管理页面顶部统计卡片\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:work_order_status(工单状态)") + @GetMapping("/stats") + public Result> getStats() { + return Result.success(workOrderService.getStats()); + } + +- @ApiOperation("创建工单") ++ @ApiOperation(value = "创建工单", notes = "创建旅途中的变更工单,需关联订单ID。\n" + ++ "可指定处理人,未指定则进入待分配状态。可附带差价信息和资源详情JSON\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 type → 字典:work_order_type(工单类型)\n" + ++ "- 请求参数 priority → 字典:work_order_priority(工单优先级)\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)\n" + ++ "- 返回字段 type → 字典:work_order_type(工单类型)\n" + ++ "- 返回字段 priority → 字典:work_order_priority(工单优先级)") + @PostMapping + public Result create(HttpServletRequest request, + @Valid @RequestBody CreateWorkOrderRequest body) { +@@ -59,7 +80,10 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.createWorkOrder(adminId, adminName, body)); + } + +- @ApiOperation("处理工单(解决/驳回)") ++ @ApiOperation(value = "处理工单(解决/驳回)", notes = "解决时需填写处理结果(resolution),驳回时需填写驳回原因(rejectReason)。\n" + ++ "可调整差价(costDifference),正数表示加价,负数表示退费\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)") + @PutMapping("/{workOrderId}/process") + public Result process(HttpServletRequest request, + @ApiParam("工单ID") @PathVariable Long workOrderId, +@@ -69,7 +93,7 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.processWorkOrder(workOrderId, adminId, adminName, body)); + } + +- @ApiOperation("指派工单") ++ @ApiOperation(value = "指派工单", notes = "将工单分配给指定管理员处理。被指派人将在待办列表中看到该工单") + @PutMapping("/{workOrderId}/assign") + public Result assign(HttpServletRequest request, + @ApiParam("工单ID") @PathVariable Long workOrderId, +@@ -80,7 +104,7 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.assignWorkOrder(workOrderId, adminId, adminName, assigneeId, assigneeName)); + } + +- @ApiOperation("添加备注") ++ @ApiOperation(value = "添加工单备注", notes = "在工单中追加备注信息,用于内部沟通和处理过程记录") + @PostMapping("/{workOrderId}/comment") + public Result addComment(HttpServletRequest request, + @ApiParam("工单ID") @PathVariable Long workOrderId, +@@ -94,7 +118,7 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.addComment(workOrderId, adminId, adminName, content)); + } + +- @ApiOperation("按订单查工单数量") ++ @ApiOperation(value = "按订单查工单数量", notes = "返回指定订单关联的工单总数,用于订单详情页展示工单角标") + @GetMapping("/count-by-order/{orderId}") + public Result countByOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(workOrderService.countByOrderId(orderId)); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java +index 0d65e46..e8684ef 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java +@@ -16,7 +16,7 @@ import java.util.List; + /** + * 相册内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序相册(Feign调用)") ++@Api(tags = "【内部接口】小程序相册(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/album") + @RequiredArgsConstructor +@@ -24,13 +24,14 @@ public class InternalAlbumController { + + private final AlbumService albumService; + +- @ApiOperation("用户有相册的订单列表") ++ @ApiOperation(value = "用户有相册的订单列表", notes = "返回用户所有有相册文件夹的订单(含订单基本信息和相册封面),用于C端'我的相册'入口") + @GetMapping("/orders") + public Result> listAlbumOrders(@RequestParam Long userId) { + return Result.success(albumService.listUserAlbumOrders(userId)); + } + +- @ApiOperation("订单的文件夹列表") ++ @ApiOperation(value = "订单的文件夹列表", ++ notes = "内部服务间调用。返回指定用户指定订单下的相册文件夹列表,会校验订单归属权限。") + @GetMapping("/order/{orderId}/folders") + public Result> listFolders( + @RequestParam Long userId, +@@ -38,7 +39,10 @@ public class InternalAlbumController { + return Result.success(albumService.listUserFolders(userId, orderId)); + } + +- @ApiOperation("文件夹下的文件列表") ++ @ApiOperation(value = "文件夹下的文件列表", notes = "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/folder/{folderId}/files") + public Result> listFiles( + @RequestParam Long userId, +@@ -48,7 +52,7 @@ public class InternalAlbumController { + return Result.success(albumService.listUserFiles(userId, folderId, page, size)); + } + +- @ApiOperation("获取文件下载链接") ++ @ApiOperation(value = "获取文件下载链接", notes = "生成带签名的临时下载URL(有效期1小时),用于C端用户下载原图/视频") + @GetMapping("/file/{albumFileId}/download-url") + public Result getDownloadUrl( + @RequestParam Long userId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java +index 0fd0c6a..110daf9 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】工作台统计(Feign调用)") ++@Api(tags = "【内部接口】工作台统计(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order/dashboard") + @RequiredArgsConstructor +@@ -19,7 +19,9 @@ public class InternalDashboardController { + + private final DashboardStatsService dashboardStatsService; + +- @ApiOperation("概览统计(支持定制师/全局,支持今日/本周/本月)") ++ @ApiOperation(value = "概览统计", notes = "返回订单量、成交金额、待处理订单数等概览数据。\n" + ++ "传customizerId则返回该定制师的数据,不传则返回全局数据。\n" + ++ "period支持: today(今日)、week(本周)、month(本月)") + @GetMapping("/overview-stats") + public Result> getOverviewStats( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -27,7 +29,9 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getOverviewStats(customizerId, period)); + } + +- @ApiOperation("待办分类汇总") ++ @ApiOperation(value = "待办分类汇总", notes = "按待办类型分组统计当前管理员的未完成待办数量,用于工作台待办卡片展示\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的待办类型key → 字典:order_todo_type(订单待办类型)") + @GetMapping("/todo-summary") + public Result> getTodoSummary( + @ApiParam("管理员ID") @RequestParam Long adminId, +@@ -35,7 +39,7 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getTodoSummary(adminId, roleKey)); + } + +- @ApiOperation("数据趋势(按天聚合)") ++ @ApiOperation(value = "数据趋势", notes = "按天聚合的订单量和金额趋势数据,用于折线图展示。支持最近7天或30天") + @GetMapping("/trend") + public Result>> getTrend( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -46,7 +50,9 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getTrend(customizerId, days)); + } + +- @ApiOperation("转化漏斗") ++ @ApiOperation(value = "转化漏斗", notes = "展示订单从创建→支付→确认→完成的转化率漏斗数据\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 订单状态 → 字典:order_status(订单状态)") + @GetMapping("/funnel") + public Result> getFunnel( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -54,7 +60,10 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getFunnel(customizerId, period)); + } + +- @ApiOperation("即将出行列表") ++ @ApiOperation(value = "即将出行列表", notes = "返回最近即将出发的订单列表,按出发日期升序。用于工作台提醒关注即将出行的客户\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/upcoming-trips") + public Result>> getUpcomingTrips( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -62,14 +71,14 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getUpcomingTrips(customizerId, limit)); + } + +- @ApiOperation("业绩排行(本月定制师排名)") ++ @ApiOperation(value = "业绩排行", notes = "按定制师维度统计成交金额排名,支持本周/本月周期。用于工作台排行榜展示") + @GetMapping("/ranking") + public Result>> getRanking( + @ApiParam("时间范围: month/week") @RequestParam(defaultValue = "month") String period) { + return Result.success(dashboardStatsService.getRanking(period)); + } + +- @ApiOperation("日历事件") ++ @ApiOperation(value = "日历事件", notes = "返回指定月份的出发日期事件列表,用于工作台日历组件展示。每个事件包含订单基本信息") + @GetMapping("/calendar-events") + public Result>> getCalendarEvents( + @ApiParam("定制师ID") @RequestParam(required = false) Long customizerId, +@@ -78,14 +87,14 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getCalendarEvents(customizerId, year, month)); + } + +- @ApiOperation("财务统计") ++ @ApiOperation(value = "财务统计", notes = "返回收入、成本、利润等财务汇总数据,支持按时间周期统计") + @GetMapping("/finance-stats") + public Result> getFinanceStats( + @ApiParam("时间范围") @RequestParam(defaultValue = "today") String period) { + return Result.success(dashboardStatsService.getFinanceStats(period)); + } + +- @ApiOperation("退款汇总") ++ @ApiOperation(value = "退款汇总", notes = "返回退款总额、退款笔数、退款率等汇总信息。传customizerId可查看单个定制师的退款数据") + @GetMapping("/refund-summary") + public Result> getRefundSummary( + @ApiParam("定制师ID") @RequestParam(required = false) Long customizerId) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java +index bb7a01e..cd52e45 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; + + import java.util.Map; + +-@Api(tags = "【内部接口】定制师订单(Feign调用)") ++@Api(tags = "【内部接口】定制师订单(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order") + @RequiredArgsConstructor +@@ -20,20 +20,29 @@ public class InternalDesignerOrderController { + + private final OrderService orderService; + +- @ApiOperation("获取定制师订单统计") ++ @ApiOperation(value = "获取定制师订单统计", notes = "返回指定定制师的订单统计数据(各状态数量、总金额等),用于定制师工作台概览\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:order_status(订单状态)") + @GetMapping("/designer-stats") + public Result> getDesignerOrderStats( + @ApiParam("定制师管理员ID") @RequestParam Long customizerId) { + return Result.success(orderService.getDesignerOrderStats(customizerId)); + } + +- @ApiOperation("获取全局订单统计") ++ @ApiOperation(value = "获取全局订单统计", notes = "返回全平台的订单统计数据(各状态数量、总金额等),用于管理层工作台概览\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:order_status(订单状态)") + @GetMapping("/global-stats") + public Result> getGlobalOrderStats() { + return Result.success(orderService.getGlobalOrderStats()); + } + +- @ApiOperation("定制师订单列表") ++ @ApiOperation(value = "定制师订单列表", notes = "分页查询指定定制师负责的订单,支持按状态和关键词筛选\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/designer-list") + public Result> listDesignerOrders( + @ApiParam("定制师管理员ID") @RequestParam Long customizerId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java +index 97b3871..b1bf9e7 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java +@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController; + import java.math.BigDecimal; + import java.util.List; + +-@Api(tags = "【内部接口】早鸟优惠(Feign调用)") ++@Api(tags = "【内部接口】早鸟优惠(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/early-bird") + @RequiredArgsConstructor +@@ -23,14 +23,17 @@ public class InternalEarlyBirdController { + + private final EarlyBirdPlanService earlyBirdPlanService; + +- @ApiOperation("获取当前有效的早鸟优惠计划列表") ++ @ApiOperation(value = "获取当前有效的早鸟优惠计划列表", notes = "返回当前日期处于生效期内且已启用的早鸟计划,C端下单时展示可用优惠") + @GetMapping("/active") + public Result> listActivePlans() { + List plans = earlyBirdPlanService.listActivePlans(); + return Result.success(plans); + } + +- @ApiOperation("匹配最优早鸟优惠计划") ++ @ApiOperation(value = "匹配最优早鸟优惠计划", notes = "根据产品类型、出行人数、订单总价匹配优惠金额最大的早鸟计划。\n" + ++ "无匹配返回null。供下单时自动匹配调用\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)") + @GetMapping("/match") + public Result matchPlan( + @RequestParam String productType, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java +index e84a0e6..310b627 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java +@@ -15,7 +15,7 @@ import javax.validation.Valid; + * C端发票内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序发票(Feign调用)") ++@Api(tags = "【内部接口】小程序发票(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/invoice") + @RequiredArgsConstructor +@@ -23,21 +23,33 @@ public class InternalInvoiceController { + + private final InvoiceService invoiceService; + +- @ApiOperation("申请开票") ++ @ApiOperation(value = "申请开票", notes = "用户对已支付订单申请开具电子发票。支持个人和企业抬头。\n" + ++ "同一订单只能开一次发票(可换开)\n\n" + ++ "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,请求/返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @PostMapping("/apply") + public Result applyInvoice(@RequestParam Long userId, + @Valid @RequestBody InvoiceApplyRequest request) { + return Result.success(invoiceService.applyInvoice(userId, request)); + } + +- @ApiOperation("发票详情") ++ @ApiOperation(value = "发票详情", notes = "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @GetMapping("/{id}") + public Result getInvoiceDetail(@RequestParam Long userId, + @PathVariable Long id) { + return Result.success(invoiceService.getInvoiceDetail(userId, id)); + } + +- @ApiOperation("通过订单ID查询发票") ++ @ApiOperation(value = "通过订单ID查询发票", notes = "查询订单关联的发票信息。未开票时返回null\n\n" + ++ "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @GetMapping("/order/{orderId}") + public Result getInvoiceByOrderId(@RequestParam Long userId, + @PathVariable Long orderId) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java +index c27da3a..ec5f305 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java +@@ -24,7 +24,7 @@ import java.util.Map; + * C端订单内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序订单(Feign调用)") ++@Api(tags = "【内部接口】小程序订单(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/order") + @RequiredArgsConstructor +@@ -32,7 +32,13 @@ public class InternalMpOrderController { + + private final OrderService orderService; + +- @ApiOperation("创建订单") ++ @ApiOperation(value = "创建订单", notes = "供BFF层调用的C端下单接口。创建后返回订单详情(含支付信息),前端可直接跳转支付\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @PostMapping("/create") + public Result createOrder(@RequestParam Long userId, + @Valid @RequestBody CreateOrderRequest request) { +@@ -41,21 +47,32 @@ public class InternalMpOrderController { + return Result.success(detail); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> listOrders(@RequestParam Long userId, + MpOrderQueryRequest query) { + return Result.success(orderService.listUserOrders(userId, query)); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 timeline[].action → 字典:order_timeline_action(订单操作类型)") + @GetMapping("/{orderId}") + public Result getOrder(@RequestParam Long userId, + @PathVariable Long orderId) { + return Result.success(orderService.getUserOrderDetail(userId, orderId)); + } + +- @ApiOperation("取消订单") ++ @ApiOperation(value = "取消订单", ++ notes = "内部服务间调用,供BFF层调用的用户取消订单接口。仅允许取消待支付/已付定金状态的订单。") + @PostMapping("/{orderId}/cancel") + public Result cancelOrder(@RequestParam Long userId, + @PathVariable Long orderId, +@@ -65,7 +82,8 @@ public class InternalMpOrderController { + return Result.success(); + } + +- @ApiOperation("订单资源详情(按分类)") ++ @ApiOperation(value = "订单资源详情(按分类)", ++ notes = "内部服务间调用。解析订单的产品快照JSON,按资源类型分类提取资源详情(景区/酒店/活动/餐厅等),返回Map结构。") + @GetMapping("/{orderId}/resources") + public Result>>> getOrderResources( + @RequestParam Long userId, +@@ -73,7 +91,7 @@ public class InternalMpOrderController { + return Result.success(orderService.getOrderSnapshotResources(userId, orderId)); + } + +- @ApiOperation("通过联系人手机号+姓名查找订单(无需登录)") ++ @ApiOperation(value = "通过联系人手机号+姓名查找订单", notes = "无需登录。用于管理员代下单场景:管理员创建订单后用户通过手机号+姓名查找并绑定订单") + @GetMapping("/lookup") + public Result> lookupByContact( + @RequestParam String contactPhone, +@@ -81,7 +99,8 @@ public class InternalMpOrderController { + return Result.success(orderService.lookupByContact(contactPhone, contactName)); + } + +- @ApiOperation("绑定未绑定的订单(通过联系人手机号+姓名)") ++ @ApiOperation(value = "绑定未绑定的订单", notes = "将userId=NULL且联系人手机号+姓名匹配的订单绑定到当前用户。\n" + ++ "用于管理员代下单后用户登录自动关联订单。返回绑定的订单数量") + @PostMapping("/bind-by-contact") + public Result bindByContact(@RequestParam Long userId, + @Valid @RequestBody BindByContactRequest request) { +@@ -89,7 +108,7 @@ public class InternalMpOrderController { + return Result.success(bindCount); + } + +- @ApiOperation("客户同意解锁订单") ++ @ApiOperation(value = "客户同意解锁订单", notes = "管理员申请修改锁定订单后,C端用户确认同意解锁。解锁后管理员可重新编辑订单") + @PostMapping("/{orderId}/approve-unlock") + public Result approveUnlock(@RequestParam Long userId, + @PathVariable Long orderId) { +@@ -103,13 +122,16 @@ public class InternalMpOrderController { + return Result.success(orderService.getUpcomingDepartures(userId)); + } + +- @ApiOperation("各状态订单数量") ++ @ApiOperation(value = "各状态订单数量", notes = "返回用户各状态的订单数量Map,用于小程序订单页Tab角标显示\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:order_status(订单状态)") + @GetMapping("/count") + public Result> countByStatus(@RequestParam Long userId) { + return Result.success(orderService.countByStatusForUser(userId)); + } + +- @ApiOperation("标记订单已评价(评价服务回调)") ++ @ApiOperation(value = "标记订单已评价", notes = "评价服务(review-service)在用户发布评价后回调此接口,将订单标记为已评价。\n" + ++ "标记后订单详情不再显示'去评价'按钮") + @PutMapping("/{orderId}/mark-reviewed") + public Result markReviewed(@PathVariable Long orderId) { + orderService.markReviewed(orderId); +@@ -118,7 +140,13 @@ public class InternalMpOrderController { + + @ApiOperation(value = "用户修改订单", notes = "用户可修改出发日期和出行人,修改后重走内部流程(级联检测+价格重算)。" + + "仅待支付/已付定金/已支付/已确认/待付尾款/待出发状态可修改。" + +- "内部流程已启动的订单修改后会通知定制师,返回message中包含提示") ++ "内部流程已启动的订单修改后会通知定制师,返回message中包含提示\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @PutMapping("/{orderId}/edit") + public Result userEditOrder(@RequestParam Long userId, + @PathVariable Long orderId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java +index db0d1cc..8e4b990 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java +@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】小程序行程(Feign调用)") ++@Api(tags = "【内部接口】小程序行程(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/trip") + @RequiredArgsConstructor +@@ -18,20 +18,29 @@ public class InternalMpTripController { + + private final TripService tripService; + +- @ApiOperation("行程列表") ++ @ApiOperation(value = "行程列表", notes = "返回用户所有有效订单的行程概要列表(已确认/待出发/出行中/已完成),按出发日期排序\n\n" + ++ "**关联字典**:\n" + ++ "- order_status(订单状态,返回字段status):CONFIRMED=已确认, PENDING_DEPARTURE=待出发, TRAVELLING=出行中, COMPLETED=已完成\n" + ++ "- trip_phase(行程阶段,返回字段tripPhase):BEFORE_START=出发前, IN_PROGRESS=出行中, ENDED=已结束") + @GetMapping("/list") + public Result>> getTripList(@RequestParam Long userId) { + return Result.success(tripService.getTripList(userId)); + } + +- @ApiOperation("行程详情") ++ @ApiOperation(value = "行程详情", notes = "返回订单的完整行程信息,包括每日行程节点、酒店安排、车辆安排、天气预报等\n\n" + ++ "**关联字典**:\n" + ++ "- order_status(订单状态,返回字段status):CONFIRMED=已确认, PENDING_DEPARTURE=待出发, TRAVELLING=出行中, COMPLETED=已完成\n" + ++ "- trip_phase(行程阶段,返回字段tripPhase):BEFORE_START=出发前, IN_PROGRESS=出行中, ENDED=已结束") + @GetMapping("/{orderId}") + public Result> getTripDetail(@RequestParam Long userId, + @PathVariable Long orderId) { + return Result.success(tripService.getTripDetail(userId, orderId)); + } + +- @ApiOperation("今日行程") ++ @ApiOperation(value = "今日行程", notes = "返回用户今天的行程安排。如果今天有正在出行的订单,返回当天的行程节点和安排;否则返回null\n\n" + ++ "**关联字典**:\n" + ++ "- order_status(订单状态,返回字段status):CONFIRMED=已确认, PENDING_DEPARTURE=待出发, TRAVELLING=出行中, COMPLETED=已完成\n" + ++ "- trip_phase(行程阶段,返回字段tripPhase):BEFORE_START=出发前, IN_PROGRESS=出行中, ENDED=已结束") + @GetMapping("/today") + public Result> getTodayTrip(@RequestParam Long userId) { + Map trip = tripService.getTodayTrip(userId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java +index 887cf27..38d3022 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; + + import javax.validation.Valid; + +-@Api(tags = "内部-订单统计") ++@Api(tags = "内部-订单统计", hidden = true) + @RestController + @RequestMapping("/internal/mp/order") + @RequiredArgsConstructor +@@ -21,19 +21,24 @@ public class InternalOrderStatsController { + private final OrderService orderService; + private final InvoiceService invoiceService; + +- @ApiOperation("获取产品已购出行人总数") ++ @ApiOperation(value = "获取产品已购出行人总数", notes = "统计指定产品的有效订单(非取消/非退款)出行人总数,用于产品详情页显示'已报名X人'") + @GetMapping("/product-sold-count") + public Result getProductSoldCount(@RequestParam Long productId) { + return Result.success(orderService.getProductSoldCount(productId)); + } + +- @ApiOperation("获取产品参与家庭数") ++ @ApiOperation(value = "获取产品参与家庭数", notes = "统计指定产品的有效订单数(一个订单视为一个家庭),用于产品详情页显示'已有X个家庭参与'") + @GetMapping("/participant-family-count") + public Result getParticipantFamilyCount(@RequestParam Long productId) { + return Result.success(orderService.getParticipantFamilyCount(productId)); + } + +- @ApiOperation("发票换开") ++ @ApiOperation(value = "发票换开", notes = "已开发票更换抬头信息(如个人改企业、更换公司名称等)。\n" + ++ "原发票作废,重新生成新发票\n\n" + ++ "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,请求/返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @PostMapping("/invoice/reissue") + public Result reissueInvoice(@RequestBody @Valid InvoiceReissueRequest request) { + return Result.success(invoiceService.reissueInvoice(request)); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java +index 2b39654..656382a 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + /** + * Internal API for payment service - 出行人验证 + */ +-@Api(tags = "【内部接口】订单出行人(Feign调用)") ++@Api(tags = "【内部接口】订单出行人(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order/traveler") + @RequiredArgsConstructor +@@ -19,7 +19,11 @@ public class InternalOrderTravelerController { + + private final OrderTravelerService orderTravelerService; + +- @ApiOperation("验证订单出行人信息(供支付服务调用)") ++ @ApiOperation(value = "验证订单出行人信息", notes = "供支付服务在发起支付前调用。验证出行人数量是否满足订单要求、证件信息是否完整。\n" + ++ "返回验证结果,包含是否通过和具体错误信息列表\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 出行人证件类型 → 字典:id_card_type(证件类型)\n" + ++ "- 涉及字段 出行人类型 → 字典:traveler_type(出行人类型)") + @GetMapping("/validate/{orderId}") + public Result validateTravelers(@PathVariable Long orderId) { + TravelerValidationDTO validation = orderTravelerService.validateTravelers(orderId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java +index b708e85..be4a57c 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java +@@ -21,7 +21,7 @@ import java.util.stream.Collectors; + * Internal endpoints for payment-service to call via Feign. + * Not exposed through gateway, no authentication interceptor. + */ +-@Api(tags = "【内部接口】订单-支付/合同/保险(Feign调用)") ++@Api(tags = "【内部接口】订单-支付/合同/保险(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order") + @RequiredArgsConstructor +@@ -30,13 +30,16 @@ public class InternalPaymentOrderController { + private final OrderService orderService; + private final OrderTodoService orderTodoService; + +- @ApiOperation("获取订单支付信息") ++ @ApiOperation(value = "获取订单支付信息", notes = "供支付服务调用。返回订单号、应付金额、定金金额、已付金额等支付所需信息") + @GetMapping("/{orderId}/pay-info") + public Result getPayInfo(@PathVariable Long orderId) { + return Result.success(orderService.getPayInfo(orderId)); + } + +- @ApiOperation("通知支付成功") ++ @ApiOperation(value = "通知支付成功", notes = "支付服务收到微信支付回调后调用。更新订单状态(PENDING_PAY→DEPOSIT_PAID/PAID)和已付金额。\n" + ++ "幂等处理:重复调用不会重复更新\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 订单status → 字典:order_status(订单状态)") + @PostMapping("/payment-result") + public Result notifyPaymentResult(@RequestBody PaymentResultDTO dto) { + orderService.handlePaymentSuccess(dto.getOrderId(), dto.getPayType(), +@@ -44,14 +47,16 @@ public class InternalPaymentOrderController { + return Result.success(); + } + +- @ApiOperation("通知退款成功") ++ @ApiOperation(value = "通知退款成功", notes = "支付服务收到微信退款回调后调用。更新订单已退金额,若全额退款则将订单状态改为已退款(REFUNDED)") + @PostMapping("/refund-result") + public Result notifyRefundResult(@RequestBody RefundResultDTO dto) { + orderService.handleRefundSuccess(dto.getOrderId(), dto.getRefundAmount()); + return Result.success(); + } + +- @ApiOperation("获取订单基本信息(供合同服务调用)") ++ @ApiOperation(value = "获取订单基本信息(供合同服务调用)", notes = "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/{orderId}/basic") + public Result> getOrderBasic(@PathVariable Long orderId) { + OrderInfo order = orderService.getById(orderId); +@@ -80,7 +85,8 @@ public class InternalPaymentOrderController { + return Result.success(data); + } + +- @ApiOperation("获取用户订单ID列表(供合同服务调用)") ++ @ApiOperation(value = "获取用户订单ID列表(供合同服务调用)", ++ notes = "内部服务间调用。返回指定用户的所有订单ID列表,供合同服务查询用户关联合同时使用。") + @GetMapping("/ids-by-user") + public Result> getOrderIdsByUser(@RequestParam Long userId) { + List orders = orderService.list( +@@ -94,7 +100,8 @@ public class InternalPaymentOrderController { + return Result.success(ids); + } + +- @ApiOperation("完成待办项(供合同/保险服务调用)") ++ @ApiOperation(value = "完成待办项(供合同/保险服务调用)", ++ notes = "内部服务间调用。合同服务签约完成或保险服务投保完成后调用此接口,将对应待办标记为已完成。系统自动检查是否所有必要待办已完成并推进内部流程。") + @PostMapping("/{orderId}/complete-todo/{todoType}") + public Result completeTodoByType(@PathVariable Long orderId, + @PathVariable String todoType) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java +index 2464f08..f7c334f 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java +@@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*; + import javax.validation.Valid; + import java.util.List; + +-@Api(tags = "【内部接口】退款(Feign调用)") ++@Api(tags = "【内部接口】退款(Feign调用)", hidden = true) + @RestController + @RequiredArgsConstructor + public class InternalRefundController { +@@ -27,20 +27,26 @@ public class InternalRefundController { + + // ==================== C-end (BFF → order-service) ==================== + +- @ApiOperation(value = "退款金额预览", notes = "退款预览:根据退款政策和距出发天数,计算可退金额和退款比例") ++ @ApiOperation(value = "退款金额预览", notes = "退款预览:根据退款政策和距出发天数,计算可退金额和退款比例\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 refundType → 字典:refund_type(退款类型)") + @GetMapping("/internal/mp/order/{orderId}/refund-preview") + public Result preview(@RequestParam("userId") Long userId, + @PathVariable Long orderId) { + return Result.success(refundApplicationService.previewRefund(orderId, userId)); + } + +- @ApiOperation("退款原因列表") ++ @ApiOperation(value = "退款原因列表(C端)", notes = "返回启用中的退款原因选项,供C端用户申请退款时选择\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 category → 字典:refund_reason_category(退款原因分类)") + @GetMapping("/internal/mp/order/refund-reasons") + public Result> listReasons() { + return Result.success(refundReasonService.listReasons(true)); + } + +- @ApiOperation(value = "提交退款申请", notes = "退款申请流程:用户选择退款原因 → 填写退款说明 → 系统根据退款政策计算可退金额 → 生成退款申请(PENDING状态) → 等待管理员审批") ++ @ApiOperation(value = "提交退款申请", notes = "退款申请流程:用户选择退款原因 → 填写退款说明 → 系统根据退款政策计算可退金额 → 生成退款申请(PENDING状态) → 等待管理员审批\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @PostMapping("/internal/mp/order/{orderId}/refund") + public Result apply(@RequestParam("userId") Long userId, + @RequestParam(value = "userName", required = false) String userName, +@@ -49,14 +55,18 @@ public class InternalRefundController { + return Result.success(refundApplicationService.apply(orderId, userId, userName, request)); + } + +- @ApiOperation("退款申请详情") ++ @ApiOperation(value = "退款申请详情(C端)", notes = "返回退款申请信息,仅允许查看自己的退款申请\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/internal/mp/order/refund/{applicationId}") + public Result getDetail(@RequestParam("userId") Long userId, + @PathVariable Long applicationId) { + return Result.success(refundApplicationService.getDetailForUser(applicationId, userId)); + } + +- @ApiOperation("根据订单ID获取最新退款申请详情") ++ @ApiOperation(value = "根据订单ID获取最新退款申请", notes = "返回订单关联的最新一条退款申请,用于订单详情页展示退款进度。无退款申请时返回null\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/internal/mp/order/{orderId}/refund-detail") + public Result getDetailByOrder(@RequestParam("userId") Long userId, + @PathVariable Long orderId) { +@@ -72,7 +82,7 @@ public class InternalRefundController { + return Result.success(refundApplicationService.appeal(applicationId, userId, request)); + } + +- @ApiOperation("撤回退款申请") ++ @ApiOperation(value = "撤回退款申请", notes = "用户主动撤回退款申请。仅在待审批(PENDING)状态下可撤回。撤回后订单恢复原状态") + @PostMapping("/internal/mp/order/refund/{applicationId}/cancel") + public Result cancel(@RequestParam("userId") Long userId, + @PathVariable Long applicationId) { +@@ -82,16 +92,18 @@ public class InternalRefundController { + + // ==================== Approval callback ==================== + +- @ApiOperation("企微退款申诉审批结果回调") ++ @ApiOperation(value = "企微退款申诉审批结果回调", notes = "企微OA审批完成后由callback-service调用。\n" + ++ "审批通过则退款申请状态变为APPEAL_APPROVED,等待管理员确认实退金额后执行退款") + @PostMapping("/internal/order/refund-appeal-result") +- public Result handleRefundAppealResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleRefundAppealResult(@RequestBody ApprovalResultDTO dto) { + refundApplicationService.handleAppealResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); + } + +- @ApiOperation("企微退款申请审批结果回调") ++ @ApiOperation(value = "企微退款申请审批结果回调", notes = "企微OA审批完成后由callback-service调用。\n" + ++ "审批通过则自动执行微信退款,审批拒绝则退款申请状态变为REJECTED") + @PostMapping("/internal/order/refund-application-result") +- public Result handleRefundApplicationResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleRefundApplicationResult(@RequestBody ApprovalResultDTO dto) { + refundApplicationService.handleApplicationApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java +index f29e8f9..9b3806e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java +@@ -35,7 +35,13 @@ public class MpOrderController { + private static final String ORDER_CREATE_DEDUP = "order:create:dedup:"; + + @ApiOperation(value = "创建订单", notes = "C端下单流程:选择产品 → 填写联系人信息和出行人 → 系统报价 → 生成订单(PENDING_PAY状态)\n\n" + +- "联系人和出行人是独立概念,联系人不必是出行人之一") ++ "联系人和出行人是独立概念,联系人不必是出行人之一\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @PostMapping("/create") + public Result createOrder(HttpServletRequest request, + @ApiParam("创建订单请求") @Valid @RequestBody CreateOrderRequest createRequest) { +@@ -55,7 +61,12 @@ public class MpOrderController { + } + } + +- @ApiOperation("我的订单列表") ++ @ApiOperation(value = "我的订单列表", notes = "查询当前用户的订单列表,支持按状态筛选。\n" + ++ "用户需先完善个人资料(realName)后才能看到订单\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> listOrders(HttpServletRequest request, + @ApiParam("订单查询请求") MpOrderQueryRequest queryRequest) { +@@ -64,7 +75,15 @@ public class MpOrderController { + return Result.success(result); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "获取订单完整信息。仅能查看自己的订单,查看他人订单会返回权限错误\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 timeline[].action → 字典:order_timeline_action(订单操作类型)") + @GetMapping("/{orderId}") + public Result getOrder(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java +index 9e92157..1df079f 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "内部天气接口(Feign)") ++@Api(tags = "内部天气接口(Feign)", hidden = true) + @RestController + @RequestMapping("/internal/mp/weather") + @RequiredArgsConstructor +@@ -20,21 +20,21 @@ public class MpWeatherController { + + private final WeatherService weatherService; + +- @ApiOperation("获取订单行程天气") ++ @ApiOperation(value = "获取订单行程天气", notes = "根据订单行程中的城市和日期,批量查询天气信息。返回每天每个城市的天气数据列表") + @GetMapping("/itinerary/{orderId}") + public Result>> getItineraryWeather( + @ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(weatherService.getItineraryWeather(orderId)); + } + +- @ApiOperation("获取指定城市实况天气") ++ @ApiOperation(value = "获取指定城市实况天气", notes = "调用高德天气API查询城市实时天气(温度、湿度、风向等),结果缓存30分钟") + @GetMapping("/live") + public Result getLiveWeather( + @ApiParam("城市名称") @RequestParam String city) { + return Result.success(weatherService.getLiveWeather(city)); + } + +- @ApiOperation("获取指定城市天气预报") ++ @ApiOperation(value = "获取指定城市天气预报", notes = "调用高德天气API查询城市未来3天天气预报,结果缓存2小时") + @GetMapping("/forecast") + public Result getForecastWeather( + @ApiParam("城市名称") @RequestParam String city) { +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java b/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java +index 3392e72..10a9ea4 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java +@@ -27,13 +27,13 @@ public class AdminPaymentController { + private final RefundService refundService; + + @GetMapping("/list") +- @ApiOperation(value = "支付交易列表", notes = "分页查询支付交易记录,支持按订单号、交易状态、交易类型筛选") ++ @ApiOperation(value = "支付交易列表", notes = "分页查询支付交易记录,支持按订单号、交易状态、交易类型筛选\n\n**关联字典**:\n- payment_mode:支付模式(列表筛选+显示)") + public Result> listTransactions(@ApiParam("支付查询条件") @Valid PaymentQueryRequest request) { + return Result.success(paymentService.listTransactions(request)); + } + + @GetMapping("/{transactionId}") +- @ApiOperation(value = "交易详情", notes = "获取单笔交易的完整信息,包含微信支付流水号") ++ @ApiOperation(value = "交易详情", notes = "获取单笔交易的完整信息,包含微信支付流水号\n\n**关联字典**:\n- payment_mode:支付模式(显示)") + public Result getDetail(@ApiParam("交易ID") @PathVariable Long transactionId) { + return Result.success(paymentService.getDetail(transactionId)); + } +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java b/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java +index d195a48..dbdfc84 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java +@@ -25,14 +25,14 @@ import java.util.List; + @RestController + @RequestMapping("/internal/payment") + @RequiredArgsConstructor +-@Api(tags = "【内部接口】支付(Feign调用)") ++@Api(tags = "【内部接口】支付(Feign调用)", hidden = true) + public class InternalPaymentController { + + private final PaymentService paymentService; + private final RefundService refundService; + + @PostMapping("/prepay") +- @ApiOperation("Create prepay order (called by BFF)") ++ @ApiOperation(value = "创建预支付订单", notes = "由BFF层调用,向微信支付API发起预支付请求,返回前端调起支付所需的参数(prepay_id等)") + public Result prepay( + @RequestParam("userId") Long userId, + @Valid @RequestBody PrepayRequest request) { +@@ -41,7 +41,7 @@ public class InternalPaymentController { + } + + @GetMapping("/status/{orderId}") +- @ApiOperation("Query payment status (called by BFF)") ++ @ApiOperation(value = "查询支付状态", notes = "查询订单的支付状态,含用户权限校验(userId不匹配时拒绝访问)\n\n**关联字典**:\n- payment_status:支付状态(返回字段)") + public Result getStatus(@RequestParam(value = "userId", required = false) Long userId, + @PathVariable Long orderId) { + PaymentVO vo = paymentService.getPaymentStatus(orderId); +@@ -53,7 +53,7 @@ public class InternalPaymentController { + } + + @GetMapping("/transactions/{orderId}") +- @ApiOperation("List all transactions for an order (called by BFF)") ++ @ApiOperation(value = "订单交易记录列表", notes = "查询指定订单的所有支付交易记录(含支付和退款),含用户权限校验\n\n**关联字典**:\n- payment_status:支付状态(返回字段)") + public Result> listTransactions(@RequestParam(value = "userId", required = false) Long userId, + @PathVariable Long orderId) { + List list = paymentService.listByOrder(orderId); +@@ -67,7 +67,7 @@ public class InternalPaymentController { + } + + @PostMapping("/refund") +- @ApiOperation("Create refund (called by order-service)") ++ @ApiOperation(value = "创建退款", notes = "由订单服务调用,向微信支付API发起退款请求。退款金额不能超过原支付金额,退款结果通过微信回调异步通知") + public Result createRefund(@Valid @RequestBody PaymentRefundRequest refundRequest) { + RefundRequest request = new RefundRequest(); + request.setOrderId(refundRequest.getOrderId()); +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java b/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java +index d950113..8b8106b 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java +@@ -23,14 +23,14 @@ import java.util.Map; + @RestController + @RequestMapping("/pay/callback") + @RequiredArgsConstructor +-@Api(tags = "【回调接口】支付回调") ++@Api(tags = "【回调接口】支付回调", hidden = true) + public class PaymentCallbackController { + + private final PaymentService paymentService; + private final RefundService refundService; + + @PostMapping("/notify/{mchId}") +- @ApiOperation("支付成功回调") ++ @ApiOperation(value = "支付成功回调", notes = "微信支付成功后的异步通知回调(无需认证,通过微信签名验证安全性)。验证签名 → 更新支付状态 → 发送MQ消息通知订单服务") + public ResponseEntity> payNotify( + @PathVariable String mchId, + HttpServletRequest request) { +@@ -49,7 +49,7 @@ public class PaymentCallbackController { + } + + @PostMapping("/refund-notify/{mchId}") +- @ApiOperation("退款回调") ++ @ApiOperation(value = "退款回调", notes = "微信退款结果的异步通知回调(无需认证,通过微信签名验证安全性)。验证签名 → 更新退款状态 → 发送MQ消息通知订单服务") + public ResponseEntity> refundNotify( + @PathVariable String mchId, + HttpServletRequest request) { +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java +index 3d92709..5a21261 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java +@@ -21,7 +21,12 @@ public class DistrictController { + + private final AmapDistrictService amapDistrictService; + +- @ApiOperation("搜索行政区划(城市/区县)") ++ @ApiOperation(value = "搜索行政区划(城市/区县)", ++ notes = "通过高德地图 API 搜索行政区划,用于产品的出发城市和目的地城市选择。\n" ++ + "输入关键词(如\"丽江\"、\"昆明\"),返回匹配的城市/区县列表,包含行政区划编码。\n\n" ++ + "**关联字典**:\n" ++ + "- cities(城市):搜索结果可用于产品行程中的城市预览\n" ++ + "- city(城市筛选):搜索结果可用于资源面板城市筛选") + @GetMapping("/search") + public Result> search( + @ApiParam("搜索关键词") @RequestParam String keywords) { +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java +index b1bba5b..8e8827f 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java +@@ -21,13 +21,19 @@ public class FamilyController { + + private final ProductFamilyService familyService; + +- @ApiOperation("获取家庭分组列表") ++ @ApiOperation(value = "获取家庭分组列表", ++ notes = "获取产品的家庭分组列表,按排序序号升序。\n\n" ++ + "**仅适用于 CUSTOM(定制)产品**。\n" ++ + "家庭分组用于将定制产品的行程按家庭单位分配,每个家庭可以有不同的人数和行程安排。\n" ++ + "行程节点通过 familyIds 字段关联到具体的家庭分组。") + @GetMapping("/families") + public Result> listFamilies(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(familyService.listFamilies(productId)); + } + +- @ApiOperation("添加家庭分组") ++ @ApiOperation(value = "添加家庭分组", ++ notes = "为 CUSTOM 定制产品添加一个家庭分组,指定家庭名称和各类型人数。\n" ++ + "添加后可在行程节点中关联此家庭,实现按家庭分配行程。") + @PostMapping("/family") + public Result addFamily( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -35,7 +41,9 @@ public class FamilyController { + return Result.success(familyService.addFamily(productId, request)); + } + +- @ApiOperation("更新家庭分组") ++ @ApiOperation(value = "更新家庭分组", ++ notes = "更新家庭分组的名称、各类型人数等信息。\n" ++ + "**仅适用于 CUSTOM(定制)产品**。") + @PutMapping("/family/{familyId}") + public Result updateFamily( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -44,7 +52,9 @@ public class FamilyController { + return Result.success(familyService.updateFamily(familyId, request)); + } + +- @ApiOperation("删除家庭分组") ++ @ApiOperation(value = "删除家庭分组", ++ notes = "删除家庭分组。如果有行程节点通过 familyIds 关联了该分组,需要手动移除关联。\n" ++ + "**仅适用于 CUSTOM(定制)产品**。") + @DeleteMapping("/family/{familyId}") + public Result deleteFamily( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java +index 9d4395e..6cc32f3 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java +@@ -32,20 +32,34 @@ public class FormulaController { + + // ===== Group endpoints ===== + +- @ApiOperation("公式组列表") ++ @ApiOperation(value = "公式组列表", ++ notes = "获取定价公式组列表,可按产品类型筛选。\n\n" ++ + "**公式引擎说明**:定价公式用于自动计算产品的成本价和售价。\n" ++ + "每种产品类型可以有多个公式组,但同一时间只能有一个激活的公式组。\n" ++ + "公式组包含多个步骤,按顺序执行,每步计算一个中间变量或最终结果。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选条件):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/group/list") + public Result> listGroups( + @RequestParam(required = false) String productType) { + return Result.success(groupService.listGroups(productType)); + } + +- @ApiOperation("公式组详情") ++ @ApiOperation(value = "公式组详情", ++ notes = "获取公式组完整信息。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/group/{groupId}") + public Result getGroup(@PathVariable Long groupId) { + return Result.success(groupService.getGroup(groupId)); + } + +- @ApiOperation("创建公式组") ++ @ApiOperation(value = "创建公式组", ++ notes = "创建一个新的定价公式组。创建后默认为未激活状态。\n\n" ++ + "公式组编码(groupCode)在同一产品类型下必须唯一。\n" ++ + "建议命名规范:{产品类型}_PRICING_V{版本号},如 CORE_PRICING_V2。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,公式组所属类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/group") + public Result createGroup(@Valid @RequestBody FormulaGroupRequest request, + HttpServletRequest httpRequest) { +@@ -53,21 +67,31 @@ public class FormulaController { + return Result.success(groupService.createGroup(request, adminId)); + } + +- @ApiOperation("更新公式组") ++ @ApiOperation(value = "更新公式组", ++ notes = "更新公式组信息。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PutMapping("/group/{groupId}") + public Result updateGroup(@PathVariable Long groupId, + @Valid @RequestBody FormulaGroupRequest request) { + return Result.success(groupService.updateGroup(groupId, request)); + } + +- @ApiOperation("激活公式组") ++ @ApiOperation(value = "激活公式组", ++ notes = "激活指定公式组,同时自动停用同产品类型下的其他公式组。\n\n" ++ + "同一产品类型下只能有一个激活的公式组,激活操作具有排他性。\n" ++ + "激活后,该产品类型的自动成本计算将使用此公式组。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,同类型排他激活):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PutMapping("/group/{groupId}/activate") + public Result activateGroup(@PathVariable Long groupId) { + groupService.activateGroup(groupId); + return Result.success(); + } + +- @ApiOperation("删除公式组") ++ @ApiOperation(value = "删除公式组", ++ notes = "删除公式组及其下所有步骤。\n" ++ + "**限制**:已激活的公式组不能删除,需先激活其他公式组。") + @DeleteMapping("/group/{groupId}") + public Result deleteGroup(@PathVariable Long groupId) { + groupService.deleteGroup(groupId); +@@ -76,25 +100,35 @@ public class FormulaController { + + // ===== Step endpoints ===== + +- @ApiOperation("公式步骤列表") ++ @ApiOperation(value = "公式步骤列表", ++ notes = "获取公式组下所有步骤,按执行顺序(executionOrder)升序排列。\n" ++ + "步骤按顺序依次执行,前一步的输出变量可作为后续步骤的输入。") + @GetMapping("/group/{groupId}/steps") + public Result> listSteps(@PathVariable Long groupId) { + return Result.success(stepService.listSteps(groupId)); + } + +- @ApiOperation("公式步骤详情") ++ @ApiOperation(value = "公式步骤详情", ++ notes = "获取单个公式步骤的完整信息,包含表达式、输入/输出变量、执行顺序等。") + @GetMapping("/step/{formulaId}") + public Result getStep(@PathVariable Long formulaId) { + return Result.success(stepService.getStep(formulaId)); + } + +- @ApiOperation("创建公式步骤") ++ @ApiOperation(value = "创建公式步骤", ++ notes = "在公式组中创建一个计算步骤。\n\n" ++ + "**表达式语法**:使用 Aviator 表达式引擎,支持数学运算、条件判断、内置函数等。\n" ++ + "示例:`baseCost = adultCount * adultUnitCost + childCount * childUnitCost`\n\n" ++ + "**输入变量**:可引用公式变量表中定义的变量,或前置步骤的输出变量。\n" ++ + "**输出变量**:每个步骤必须指定一个输出变量名,供后续步骤引用。") + @PostMapping("/step") + public Result createStep(@Valid @RequestBody FormulaStepRequest request) { + return Result.success(stepService.createStep(request)); + } + +- @ApiOperation("更新公式步骤") ++ @ApiOperation(value = "更新公式步骤", ++ notes = "更新公式步骤的表达式、输入/输出变量等。\n" ++ + "每次更新会自动保存一个版本快照,可通过版本历史接口查看和回滚。") + @PutMapping("/step/{formulaId}") + public Result updateStep(@PathVariable Long formulaId, + @Valid @RequestBody FormulaStepRequest request, +@@ -103,27 +137,36 @@ public class FormulaController { + return Result.success(stepService.updateStep(formulaId, request, adminId)); + } + +- @ApiOperation("启用/禁用公式步骤") ++ @ApiOperation(value = "启用/禁用公式步骤", ++ notes = "切换公式步骤的启用状态。\n" ++ + "禁用的步骤在公式执行时会被跳过,不影响其他步骤的执行。\n" ++ + "适用场景:临时跳过某个计算步骤进行调试或测试。") + @PutMapping("/step/{formulaId}/toggle") + public Result toggleStep(@PathVariable Long formulaId) { + stepService.toggleStep(formulaId); + return Result.success(); + } + +- @ApiOperation("删除公式步骤") ++ @ApiOperation(value = "删除公式步骤", ++ notes = "删除指定的公式步骤。删除后其他步骤的执行顺序不会自动调整。\n" ++ + "**注意**:如果后续步骤引用了被删步骤的输出变量,执行时会报错。") + @DeleteMapping("/step/{formulaId}") + public Result deleteStep(@PathVariable Long formulaId) { + stepService.deleteStep(formulaId); + return Result.success(); + } + +- @ApiOperation("公式步骤版本历史") ++ @ApiOperation(value = "公式步骤版本历史", ++ notes = "获取公式步骤的所有历史版本列表,按版本号倒序。\n" ++ + "每次更新步骤表达式会自动创建新版本,方便追溯和回滚。") + @GetMapping("/step/{formulaId}/versions") + public Result> listVersions(@PathVariable Long formulaId) { + return Result.success(stepService.listVersions(formulaId)); + } + +- @ApiOperation("回滚公式步骤到指定版本") ++ @ApiOperation(value = "回滚公式步骤到指定版本", ++ notes = "将公式步骤回滚到历史版本。\n" ++ + "回滚操作会用历史版本的表达式、变量等覆盖当前内容,并创建一个新的版本记录。") + @PutMapping("/step/{formulaId}/rollback/{versionNum}") + public Result rollbackStep(@PathVariable Long formulaId, + @PathVariable Integer versionNum, +@@ -134,7 +177,11 @@ public class FormulaController { + + // ===== Test endpoint ===== + +- @ApiOperation("测试公式执行") ++ @ApiOperation(value = "测试公式执行", ++ notes = "使用自定义变量值测试公式组的执行结果,不影响任何业务数据。\n\n" ++ + "传入公式组ID和测试变量(变量名→值的映射),返回每个步骤的执行结果。\n" ++ + "适用于公式调试:验证表达式是否正确、计算结果是否符合预期。\n" ++ + "如果某步骤执行出错,会在结果中标明错误信息。") + @PostMapping("/test") + public Result testFormulas(@Valid @RequestBody FormulaTestRequest request) { + return Result.success(testService.testFormulas(request)); +@@ -142,27 +189,41 @@ public class FormulaController { + + // ===== Var endpoints ===== + +- @ApiOperation("公式变量列表") ++ @ApiOperation(value = "公式变量列表", ++ notes = "获取公式变量列表,可按变量分类筛选。\n\n" ++ + "**变量分类**:\n" ++ + "- INPUT:输入变量,从业务数据获取(如成人人数、资源单价)\n" ++ + "- INTERMEDIATE:中间变量,由公式步骤计算得出\n" ++ + "- OUTPUT:输出变量,最终报价结果(如总成本、售价)") + @GetMapping("/var/list") + public Result> listVars( + @RequestParam(required = false) String category) { + return Result.success(varService.listVars(category)); + } + +- @ApiOperation("创建公式变量") ++ @ApiOperation(value = "创建公式变量", ++ notes = "创建公式变量定义。变量名(varName)全局唯一,建议使用驼峰命名。\n" ++ + "可指定适用的产品类型列表(productTypes),为空则适用于所有类型。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,变量适用范围):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/var") + public Result createVar(@Valid @RequestBody FormulaVarRequest request) { + return Result.success(varService.createVar(request)); + } + +- @ApiOperation("更新公式变量") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java +index 7e553dc..ab7b818 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java +@@ -25,7 +25,16 @@ public class GroupBatchController { + + // ===== Batch CRUD ===== + +- @ApiOperation("创建主批次") ++ @ApiOperation(value = "创建主批次", ++ notes = "为 GROUP(小蒙马拼团)产品创建一个团期主批次。\n\n" ++ + "**仅适用于 GROUP 产品类型**。\n" ++ + "每个批次有独立的出发日期、报名截止日期、人数上限。\n" ++ + "创建后状态为 PENDING(待开放),需手动开启报名。\n\n" ++ + "**批次状态流转**:PENDING → ENROLLING(报名中)→ CONFIRMED(已成团)→ CLOSED(已关闭)\n" ++ + "任意报名状态均可被解散(DISBANDED)。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限GROUP):GROUP=小蒙马拼团\n" ++ + "- batch_status(批次状态):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束") + @PostMapping + public Result createBatch(@PathVariable Long productId, + @Valid @RequestBody GroupBatchCreateRequest request, +@@ -34,7 +43,11 @@ public class GroupBatchController { + return Result.success(batchService.createBatch(productId, request, adminId)); + } + +- @ApiOperation("创建子批次(溢出)") ++ @ApiOperation(value = "创建子批次(溢出)", ++ notes = "当主批次人数满员时,创建子批次接收溢出报名。\n\n" ++ + "子批次共享主批次的出发日期和行程,但有独立的人数上限和报名人数。\n" ++ + "适用场景:某团期特别火爆,需要扩容但希望分开管理。\n" ++ + "子批次在列表中显示为主批次的子级节点。") + @PostMapping("/{batchId}/sub-batch") + public Result createSubBatch(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -44,7 +57,9 @@ public class GroupBatchController { + return Result.success(batchService.createSubBatch(batchId, request, adminId)); + } + +- @ApiOperation("更新批次") ++ @ApiOperation(value = "更新批次", ++ notes = "更新批次基本信息。仅传入需要修改的字段。\n" ++ + "已有报名人员的批次修改人数上限时,不能低于已报名人数。") + @PutMapping("/{batchId}") + public Result updateBatch(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -52,20 +67,30 @@ public class GroupBatchController { + return Result.success(batchService.updateBatch(batchId, request)); + } + +- @ApiOperation("删除批次") ++ @ApiOperation(value = "删除批次", ++ notes = "删除批次(软删除)。\n" ++ + "**限制**:已有报名人员的批次不能直接删除,需先解散批次。") + @DeleteMapping("/{batchId}") + public Result deleteBatch(@PathVariable Long productId, @PathVariable Long batchId) { + batchService.deleteBatch(batchId); + return Result.success(); + } + +- @ApiOperation("批次列表(树形)") ++ @ApiOperation(value = "批次列表(树形)", ++ notes = "获取产品所有批次,以树形结构返回(主批次包含子批次列表)。\n" ++ + "按出发日期升序排列,包含每个批次的报名人数和剩余名额。\n\n" ++ + "**关联字典**:\n" ++ + "- batch_status(批次状态,返回字段):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束") + @GetMapping("/list") + public Result> listBatches(@PathVariable Long productId) { + return Result.success(batchService.listBatches(productId)); + } + +- @ApiOperation("批次详情") ++ @ApiOperation(value = "批次详情", ++ notes = "获取单个批次的完整信息,包括批次基本信息、服务人员配置、套餐组合等。\n\n" ++ + "**关联字典**:\n" ++ + "- batch_status(批次状态):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束\n" ++ + "- staff_type(人员类型,服务人员配置):GUIDE=领队, DRIVER=司机, PHOTOGRAPHER=摄影师, ASSISTANT=助理, OTHER=其他") + @GetMapping("/{batchId}") + public Result getBatchDetail(@PathVariable Long productId, + @PathVariable Long batchId) { +@@ -74,21 +99,33 @@ public class GroupBatchController { + + // ===== Status operations ===== + +- @ApiOperation("开启报名(PENDING->ENROLLING)") ++ @ApiOperation(value = "开启报名(PENDING->ENROLLING)", ++ notes = "将批次从 PENDING 状态变更为 ENROLLING(报名中)。\n" ++ + "开启后用户可在小程序端看到该团期并报名。\n" ++ + "前提条件:产品必须已上架(PUBLISHED)。") + @PutMapping("/{batchId}/open") + public Result openEnrollment(@PathVariable Long productId, @PathVariable Long batchId) { + batchService.openEnrollment(batchId); + return Result.success(); + } + +- @ApiOperation("关闭报名(ENROLLING/CONFIRMED->CLOSED)") ++ @ApiOperation(value = "关闭报名(ENROLLING/CONFIRMED->CLOSED)", ++ notes = "关闭批次报名,不再接受新的报名。\n" ++ + "已报名的订单不受影响,仅阻止新增报名。\n" ++ + "适用于报名截止日期到达或手动提前关闭的场景。") + @PutMapping("/{batchId}/close") + public Result closeEnrollment(@PathVariable Long productId, @PathVariable Long batchId) { + batchService.closeEnrollment(batchId); + return Result.success(); + } + +- @ApiOperation("解散批次") ++ @ApiOperation(value = "解散批次", ++ notes = "解散批次并处理已报名的订单。\n\n" ++ + "**重要**:解散操作会触发以下流程:\n" ++ + "1. 批次状态变更为 DISBANDED\n" ++ + "2. 通过 MQ 消息通知订单服务,自动取消该批次下的所有未完成订单\n" ++ + "3. 已支付订单会触发退款流程\n\n" ++ + "必须填写解散原因(如:报名人数不足、行程调整等)。") + @PostMapping("/{batchId}/disband") + public Result disbandBatch(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -103,7 +140,13 @@ public class GroupBatchController { + + // ===== Staff operations ===== + +- @ApiOperation("保存服务人员(全量替换)") ++ @ApiOperation(value = "保存服务人员(全量替换)", ++ notes = "保存批次的服务人员配置,采用全量替换模式(先删后增)。\n\n" ++ + "每次提交完整的人员列表,替换掉该批次原有的所有人员配置。\n" ++ + "人员来源于资源服务的人员库,通过 staffId 关联。\n" ++ + "**角色类型**:LEADER(领队)/PHOTOGRAPHER(摄影师)/DRIVER(司机)/OTHER(其他)\n\n" ++ + "**关联字典**:\n" ++ + "- staff_type(人员类型):GUIDE=领队, DRIVER=司机, PHOTOGRAPHER=摄影师, ASSISTANT=助理, OTHER=其他") + @PostMapping("/{batchId}/staff") + public Result> saveStaff(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -111,14 +154,18 @@ public class GroupBatchController { + return Result.success(staffService.saveStaff(batchId, productId, requests)); + } + +- @ApiOperation("服务人员列表") ++ @ApiOperation(value = "服务人员列表", ++ notes = "**关联字典**:\n" ++ + "- staff_type(人员类型):GUIDE=领队, DRIVER=司机, PHOTOGRAPHER=摄影师, ASSISTANT=助理, OTHER=其他") + @GetMapping("/{batchId}/staff") + public Result> listStaff(@PathVariable Long productId, + @PathVariable Long batchId) { + return Result.success(staffService.listStaff(batchId)); + } + +- @ApiOperation("从其他批次复制服务人员") ++ @ApiOperation(value = "从其他批次复制服务人员", ++ notes = "将源批次的服务人员配置复制到当前批次(全量替换当前批次已有人员)。\n" ++ + "适用场景:多个团期使用相同的服务人员班底。") + @PostMapping("/{batchId}/staff/copy-from/{sourceId}") + public Result> copyStaff(@PathVariable Long productId, + @PathVariable Long batchId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java +index 61d9a75..7a6ea65 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java +@@ -36,7 +36,7 @@ import java.util.Map; + * C端产品内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序产品(Feign调用)") ++@Api(tags = "【内部接口】小程序产品(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/product") + @RequiredArgsConstructor +@@ -50,39 +50,56 @@ public class InternalMpProductController { + private final ProductPriceCalendarMapper priceCalendarMapper; + private final GroupTourBatchMapper groupTourBatchMapper; + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", ++ notes = "内部Feign接口,返回已上架产品列表。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选+返回字段):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/list") + public Result> listProducts(@Valid MpProductQueryRequest query) { + return Result.success(productService.listPublishedProducts(query)); + } + +- @ApiOperation("产品详情") ++ @ApiOperation(value = "产品详情", ++ notes = "内部Feign接口,返回已上架产品详情。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态):PUBLISHED=已上架\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}") + public Result getProduct(@PathVariable Long productId) { + return Result.success(productService.getPublishedProduct(productId)); + } + +- @ApiOperation("报价计算") ++ @ApiOperation(value = "报价计算", ++ notes = "内部服务间调用,供 hl-mp-service BFF 层 Feign 调用的报价计算接口。\n" ++ + "计算逻辑与管理后台报价一致,根据日期和人数计算总价。") + @PostMapping("/{productId}/quote") + public Result calculateQuote(@PathVariable Long productId, + @Valid @RequestBody QuoteRequest request) { + return Result.success(quoteCalculatorService.calculateQuote(productId, request)); + } + +- @ApiOperation("产品线列表(活跃)") ++ @ApiOperation(value = "产品线列表(活跃)", ++ notes = "内部服务间调用,供 hl-mp-service 获取所有启用的产品线列表,用于小程序端筛选。") + @GetMapping("/lines") + public Result> listActiveLines() { + return Result.success(productLineService.listAllActive()); + } + +- @ApiOperation("推荐产品列表") ++ @ApiOperation(value = "推荐产品列表", ++ notes = "返回推荐的已上架产品。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,返回字段):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/recommend") + public Result> listRecommendProducts( + @RequestParam(defaultValue = "6") int limit) { + return Result.success(productService.listRecommendProducts(limit)); + } + +- @ApiOperation("C端价格日历") ++ @ApiOperation(value = "C端价格日历", ++ notes = "内部服务间调用,供 hl-mp-service 获取产品的价格日历数据。\n\n" ++ + "可通过 startDate/endDate 限定查询范围,不传则返回今天及之后的所有可用日期。\n" ++ + "返回每天的售价和库存信息,供小程序端日历选择器使用。") + @GetMapping("/{productId}/price-calendar") + public Result>> getPriceCalendar( + @PathVariable Long productId, +@@ -91,7 +108,10 @@ public class InternalMpProductController { + return Result.success(priceCalendarService.getMpPriceCalendar(productId, startDate, endDate)); + } + +- @ApiOperation("产品最早可订日期") ++ @ApiOperation(value = "产品最早可订日期", ++ notes = "根据产品类型查询最早可预订日期。GROUP类型查批次出发日期,CORE/CUSTOM类型查价格日历。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响查询逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/earliest-booking-date") + public Result getEarliestBookingDate(@RequestParam Long productId) { + Product product = productMapper.selectById(productId); +@@ -137,7 +157,10 @@ public class InternalMpProductController { + } + } + +- @ApiOperation("定制师产品统计(C端用)") ++ @ApiOperation(value = "定制师产品统计(C端用)", ++ notes = "统计指定定制师已发布的产品数量。\n\n" ++ + "**关联字典**:\n" ++ + "- product_status(产品状态,统计条件):PUBLISHED=已上架") + @GetMapping("/designer-stats") + public Result> getDesignerStats(@RequestParam Long customizerId) { + long routeCount = productMapper.selectCount( +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java +index 978f513..7c0b2e7 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java +@@ -49,7 +49,7 @@ import java.util.stream.Collectors; + @RestController + @RequestMapping("/internal/product") + @RequiredArgsConstructor +-@Api(tags = "【内部接口】产品(Feign调用)") ++@Api(tags = "【内部接口】产品(Feign调用)", hidden = true) + public class InternalProductController { + + private final ProductStatusService productStatusService; +@@ -66,8 +66,12 @@ public class InternalProductController { + private final GroupTourBatchMapper groupBatchMapper; + private final ObjectMapper objectMapper; + ++ @ApiOperation(value = "处理产品审批结果", ++ notes = "接收企微审批回调结果,更新产品状态。\n\n" ++ + "**关联字典**:\n" ++ + "- product_status(产品状态):PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@Valid @RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@Valid @RequestBody ApprovalResultDTO dto) { + try { + productStatusService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +@@ -78,10 +82,12 @@ public class InternalProductController { + } + } + +- /** +- * 获取产品详情(不过滤状态,供 order-service 创建订单时获取快照) +- * 可选传入 date 参数,传入后会从资源价格日历查询各节点的成本价并填入快照 +- */ ++ @ApiOperation(value = "获取产品详情(内部)", ++ notes = "不过滤状态,供 order-service 创建订单时获取快照。可选传入 date 参数查询各节点成本价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}/detail") + public Result getProductDetail(@PathVariable Long productId, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) { +@@ -91,19 +97,20 @@ public class InternalProductController { + return Result.success(productService.getProduct(productId)); + } + +- /** +- * 报价计算(供 order-service 创建订单时自动报价) +- */ ++ @ApiOperation(value = "报价计算(内部)", ++ notes = "供 order-service 创建订单时自动报价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响计算逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/{productId}/quote") + public Result calculateQuote(@PathVariable Long productId, + @Valid @RequestBody QuoteRequest request) { + return Result.success(quoteCalculatorService.calculateQuote(productId, request)); + } + +- /** +- * 简单报价:直接从价格日历取售价 × 人数,不走资源价格计算。 +- * 小童 = 儿童售价 × 折扣比例,幼童 = 固定价格。 +- */ ++ @ApiOperation(value = "简单报价(内部)", ++ notes = "直接从价格日历取售价乘以人数,不走资源价格计算。CUSTOM/ROUTE按整单,CORE/GROUP按人头。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响计算逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/{productId}/simple-quote") + public Result> simpleQuote( + @PathVariable Long productId, +@@ -253,6 +260,10 @@ public class InternalProductController { + /** + * Deduct stock (optimistic lock: only succeeds if stock >= count) + */ ++ @ApiOperation(value = "扣减库存(内部)", ++ notes = "内部服务间调用,供 order-service 创建订单时扣减价格日历库存。\n\n" ++ + "使用乐观锁机制:只有当库存 >= count 时才扣减成功。\n" ++ + "扣减失败返回错误(库存不足),调用方需处理失败情况。") + @PostMapping("/{productId}/deduct-stock") + public Result deductStock(@PathVariable Long productId, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") String date, +@@ -268,6 +279,9 @@ public class InternalProductController { + /** + * Restore stock (compensation for cancelled/expired orders) + */ ++ @ApiOperation(value = "恢复库存(内部)", ++ notes = "内部服务间调用,供 order-service 订单取消/过期时恢复价格日历库存。\n" ++ + "用于补偿已扣减的库存,恢复数量不校验上限。") + @PostMapping("/{productId}/restore-stock") + public Result restoreStock(@PathVariable Long productId, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") String date, +@@ -281,6 +295,9 @@ public class InternalProductController { + * Get itinerary resources (SCENIC/ACTIVITY/HOTEL) for review service. + * Returns deduplicated list of { resourceType, resourceId, resourceName }. + */ ++ @ApiOperation(value = "获取行程关联资源(内部)", ++ notes = "内部服务间调用,供 review-service 获取产品行程中关联的资源列表。\n\n" ++ + "返回去重后的景区(SCENIC)、活动(ACTIVITY)、酒店(HOTEL)资源,用于评价时选择关联的资源对象。") + @GetMapping("/{productId}/itinerary-resources") + public Result>> getItineraryResources(@PathVariable Long productId) { + // Allowed resource types for review +@@ -310,9 +327,11 @@ public class InternalProductController { + return Result.success(result); + } + +- /** +- * 变更定制产品状态(供 order-service 调用:下单→ORDERED / 取消→COMPLETED) +- */ ++ @ApiOperation(value = "变更定制产品状态(内部)", ++ notes = "供 order-service 调用:下单时 COMPLETED→ORDERED,取消时 ORDERED→COMPLETED。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限CUSTOM):CUSTOM=定制产品\n" ++ + "- product_status(产品状态):COMPLETED=已完成, ORDERED=已下单") + @PutMapping("/{productId}/custom-status") + public Result changeCustomProductStatus(@PathVariable Long productId, + @RequestParam String targetStatus) { +@@ -339,6 +358,10 @@ public class InternalProductController { + /** + * Enroll participants (optimistic lock on batch). + */ ++ @ApiOperation(value = "报名入团(内部)", ++ notes = "内部服务间调用,供 order-service 下单时增加批次已报名人数。\n\n" ++ + "使用乐观锁机制:只有当剩余名额 >= peopleCount 时才报名成功。\n" ++ + "报名成功后自动检查是否满员(FULL)或达到成团条件(CONFIRMED)。") + @PostMapping("/batch/{batchId}/enroll") + public Result enrollBatch(@PathVariable Long batchId, + @RequestParam @Min(1) int peopleCount) { +@@ -349,6 +372,9 @@ public class InternalProductController { + /** + * Unenroll participants (compensation for cancellation). + */ ++ @ApiOperation(value = "退出报名(内部)", ++ notes = "内部服务间调用,供 order-service 订单取消/退款时减少批次已报名人数。\n" ++ + "用于补偿已报名的人数,恢复剩余名额。") + @PostMapping("/batch/{batchId}/unenroll") + public Result unenrollBatch(@PathVariable Long batchId, + @RequestParam @Min(1) int peopleCount) { +@@ -356,9 +382,10 @@ public class InternalProductController { + return Result.success(); + } + +- /** +- * Get batch info (for order snapshot). +- */ ++ @ApiOperation(value = "批次信息(内部)", ++ notes = "供 order-service 创建订单时获取批次快照。\n\n" ++ + "**关联字典**:\n" ++ + "- batch_status(批次状态,返回字段):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束") + @GetMapping("/batch/{batchId}/info") + public Result> getBatchInfo(@PathVariable Long batchId) { + GroupTourBatch batch = groupTourBatchService.getBatchById(batchId); +@@ -385,6 +412,10 @@ public class InternalProductController { + /** + * GROUP quote: returns adult/child dynamic pricing for a batch. + */ ++ @ApiOperation(value = "GROUP产品报价(内部)", ++ notes = "内部服务间调用,供 order-service 和 mp-service 获取 GROUP 产品按套餐组合的报价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限GROUP):GROUP=小蒙马拼团") + @GetMapping("/{productId}/group-quote") + public Result getGroupQuote(@PathVariable Long productId, + @RequestParam Long batchId, +@@ -395,6 +426,9 @@ public class InternalProductController { + /** + * C-end calendar data for GROUP products. + */ ++ @ApiOperation(value = "团期日历数据(内部)", ++ notes = "内部服务间调用,供小程序端展示 GROUP 产品的团期日历。\n\n" ++ + "返回可报名批次的出发日期、状态、剩余名额等信息,用于日历选择器展示。") + @GetMapping("/{productId}/batches/calendar") + public Result> getBatchesCalendar(@PathVariable Long productId) { + return Result.success(groupTourBatchService.listCalendar(productId)); +@@ -403,6 +437,9 @@ public class InternalProductController { + /** + * C-end combo list for a batch (套餐列表). + */ ++ @ApiOperation(value = "批次套餐列表(内部)", ++ notes = "内部服务间调用,供小程序端展示 GROUP 产品批次下的套餐组合列表。\n\n" ++ + "每个套餐包含成人/儿童人数搭配、售价、原价、库存和已售数量。") + @GetMapping("/batch/{batchId}/combos") + public Result>> listBatchCombos(@PathVariable Long batchId) { + List combos = comboMapper.selectList( +@@ -431,7 +468,9 @@ public class InternalProductController { + + // ===== 定制师内部接口 ===== + +- @ApiOperation("获取定制师已发布产品ID列表") ++ @ApiOperation(value = "获取定制师已发布产品ID列表", ++ notes = "**关联字典**:\n" ++ + "- product_status(产品状态,筛选条件):PUBLISHED=已上架") + @GetMapping("/designer-published-ids") + public Result> getDesignerPublishedProductIds(@RequestParam Long createBy) { + List ids = productService.getDesignerPublishedProductIds(createBy); +@@ -439,19 +478,28 @@ public class InternalProductController { + return Result.success(strIds); + } + +- @ApiOperation("获取全局产品统计") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java +index f813a83..7ea5e3b 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java +@@ -28,7 +28,10 @@ public class ItineraryController { + + // ========================= Day ========================= + +- @ApiOperation("更新行程天") ++ @ApiOperation(value = "更新行程天", ++ notes = "更新指定天的行程信息,如当天主题、概述等。\n" ++ + "行程天在创建产品时根据 tripDays 自动生成,不支持单独增删,只能更新。\n" ++ + "dayNumber 从 1 开始,对应第几天的行程。") + @PutMapping("/item/{productId}/day/{dayNumber}") + public Result updateDay( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -37,7 +40,9 @@ public class ItineraryController { + return Result.success(dayService.updateDay(productId, dayNumber, request)); + } + +- @ApiOperation("获取行程天列表") ++ @ApiOperation(value = "获取行程天列表", ++ notes = "获取产品所有行程天的信息,按 dayNumber 升序排列。\n" ++ + "每一天包含当天主题、概述等信息,不包含节点详情(节点通过单独接口获取)。") + @GetMapping("/item/{productId}/days") + public Result> listDays(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(dayService.listDays(productId)); +@@ -45,7 +50,14 @@ public class ItineraryController { + + // ========================= Node ========================= + +- @ApiOperation("添加行程节点") ++ @ApiOperation(value = "添加行程节点", ++ notes = "在指定天添加一个行程节点。节点是行程的最小单元,可关联资源服务中的景区、酒店、活动等。\n\n" ++ + "**节点类型**:TRANSPORT(交通)/SCENIC(景区)/DINING(餐饮)/ACTIVITY(活动)/" ++ + "PHOTOGRAPHY(摄影)/HOTEL(酒店)/FREE(自由活动)/CUSTOM(自定义)\n\n" ++ + "**CUSTOM 定制产品特有**:可通过 familyIds 指定节点所属的家庭分组,实现按家庭分配行程。\n" ++ + "新建节点自动追加到当天最后位置,可通过排序接口调整顺序。\n\n" ++ + "**关联字典**:\n" ++ + "- city(城市,资源面板筛选用):用于在添加节点时按城市筛选可选资源") + @PostMapping("/item/{productId}/day/{dayNumber}/node") + public Result createNode( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -54,7 +66,12 @@ public class ItineraryController { + return Result.success(nodeService.createNode(productId, dayNumber, request)); + } + +- @ApiOperation("更新行程节点") ++ @ApiOperation(value = "更新行程节点", ++ notes = "更新行程节点信息,仅传入需要修改的字段。\n" ++ + "可修改节点名称、时间、关联资源、图片、描述等。\n\n" ++ + "**关联字典**:\n" ++ + "- city(城市):资源面板城市筛选\n" ++ + "- cities(城市ID映射):城市名称预览") + @PutMapping("/node/{nodeId}") + public Result updateNode( + @ApiParam("行程节点ID") @PathVariable Long nodeId, +@@ -62,14 +79,17 @@ public class ItineraryController { + return Result.success(nodeService.updateNode(nodeId, request)); + } + +- @ApiOperation("删除行程节点") ++ @ApiOperation(value = "删除行程节点", ++ notes = "删除指定行程节点,同天其他节点的排序自动调整。") + @DeleteMapping("/node/{nodeId}") + public Result deleteNode(@ApiParam("行程节点ID") @PathVariable Long nodeId) { + nodeService.deleteNode(nodeId); + return Result.success(); + } + +- @ApiOperation("行程节点拖拽排序") ++ @ApiOperation(value = "行程节点拖拽排序", ++ notes = "重新排列指定天的所有行程节点顺序。前端拖拽排序后,将新的节点ID顺序全量提交。\n" ++ + "nodeIds 列表中的顺序即为新的排序顺序(从上到下)。") + @PutMapping("/item/{productId}/day/{dayNumber}/nodes/sort") + public Result sortNodes( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -79,13 +99,17 @@ public class ItineraryController { + return Result.success(); + } + +- @ApiOperation("复制行程节点") ++ @ApiOperation(value = "复制行程节点", ++ notes = "复制指定节点到同一天的末尾位置,包括节点的所有属性(名称、资源关联、图片等)。\n" ++ + "适用场景:同一天有相似的行程安排时快速复制。") + @PostMapping("/node/{nodeId}/copy") + public Result copyNode(@ApiParam("行程节点ID") @PathVariable Long nodeId) { + return Result.success(nodeService.copyNode(nodeId)); + } + +- @ApiOperation("移动行程节点到其他天") ++ @ApiOperation(value = "移动行程节点到其他天", ++ notes = "将节点从当前天移动到目标天的末尾位置。\n" ++ + "移动后原天和目标天的节点排序自动调整。") + @PutMapping("/node/{nodeId}/move") + public Result moveNode( + @ApiParam("行程节点ID") @PathVariable Long nodeId, +@@ -93,7 +117,12 @@ public class ItineraryController { + return Result.success(nodeService.moveNode(nodeId, request.getTargetDayNumber())); + } + +- @ApiOperation("获取某天的节点列表") ++ @ApiOperation(value = "获取某天的节点列表", ++ notes = "获取指定天的所有行程节点,按排序顺序返回。\n" ++ + "每个节点包含类型、名称、时间、关联资源信息、图片等完整数据。\n\n" ++ + "**关联字典**:\n" ++ + "- city(城市):资源面板城市筛选\n" ++ + "- cities(城市ID映射):城市名称预览") + @GetMapping("/item/{productId}/day/{dayNumber}/nodes") + public Result> listNodes( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -103,7 +132,10 @@ public class ItineraryController { + + // ========================= Hotel ========================= + +- @ApiOperation("添加每日住宿") ++ @ApiOperation(value = "添加每日住宿", ++ notes = "为指定天添加住宿安排,关联资源服务中的酒店和房型。\n" ++ + "每天可以有多个住宿选项(如不同档次),参与成本自动计算。\n" ++ + "住宿费用会体现在价格日历的成本计算中。") + @PostMapping("/item/{productId}/day/{dayNumber}/hotel") + public Result addHotel( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -112,7 +144,8 @@ public class ItineraryController { + return Result.success(hotelService.addHotel(productId, dayNumber, request)); + } + +- @ApiOperation("更新每日住宿") ++ @ApiOperation(value = "更新每日住宿", ++ notes = "更新住宿记录的酒店、房型、数量等信息。") + @PutMapping("/hotel/{id}") + public Result updateHotel( + @ApiParam("住宿记录ID") @PathVariable Long id, +@@ -120,14 +153,16 @@ public class ItineraryController { + return Result.success(hotelService.updateHotel(id, request)); + } + +- @ApiOperation("删除每日住宿") ++ @ApiOperation(value = "删除每日住宿", ++ notes = "删除指定住宿记录。删除后该天的住宿成本会从报价中移除。") + @DeleteMapping("/hotel/{id}") + public Result deleteHotel(@ApiParam("住宿记录ID") @PathVariable Long id) { + hotelService.deleteHotel(id); + return Result.success(); + } + +- @ApiOperation("获取某天的住宿列表") ++ @ApiOperation(value = "获取某天的住宿列表", ++ notes = "获取指定天的所有住宿安排,包含酒店名称、房型、数量等信息。") + @GetMapping("/item/{productId}/day/{dayNumber}/hotels") + public Result> listHotels( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -137,7 +172,9 @@ public class ItineraryController { + + // ========================= Dining ========================= + +- @ApiOperation("添加每日餐厅推荐") ++ @ApiOperation(value = "添加每日餐厅推荐", ++ notes = "为指定天添加餐饮推荐,关联资源服务中的餐厅。\n" ++ + "用于展示当天的用餐安排,可按早/午/晚分类。") + @PostMapping("/item/{productId}/day/{dayNumber}/dining") + public Result addDiningOption( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -146,7 +183,8 @@ public class ItineraryController { + return Result.success(diningOptionService.addDiningOption(productId, dayNumber, request)); + } + +- @ApiOperation("更新餐饮推荐") ++ @ApiOperation(value = "更新餐饮推荐", ++ notes = "更新餐饮推荐的餐厅、用餐类型(早/午/晚)、描述等信息。") + @PutMapping("/dining/{id}") + public Result updateDiningOption( + @ApiParam("餐饮推荐ID") @PathVariable Long id, +@@ -154,7 +192,8 @@ public class ItineraryController { + return Result.success(diningOptionService.updateDiningOption(id, request)); + } + +- @ApiOperation("获取某天的餐厅推荐列表") ++ @ApiOperation(value = "获取某天的餐厅推荐列表", ++ notes = "获取指定天的所有餐饮推荐,包含餐厅名称、用餐类型、描述等信息。") + @GetMapping("/item/{productId}/day/{dayNumber}/dining") + public Result> listDining( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -162,7 +201,8 @@ public class ItineraryController { + return Result.success(diningOptionService.listDiningOptions(productId, dayNumber)); + } + +- @ApiOperation("删除餐饮推荐") ++ @ApiOperation(value = "删除餐饮推荐", ++ notes = "删除指定的餐饮推荐记录。") + @DeleteMapping("/dining/{id}") + public Result deleteDiningOption(@ApiParam("餐饮推荐ID") @PathVariable Long id) { + diningOptionService.deleteDiningOption(id); +@@ -171,7 +211,9 @@ public class ItineraryController { + + // ========================= Supplies ========================= + +- @ApiOperation("添加物资配品") ++ @ApiOperation(value = "添加物资配品", ++ notes = "为产品添加物资配品(如帐篷、睡袋、登山杖等),关联资源服务中的物资。\n" +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java +index 526bc16..94a6723 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java +@@ -31,19 +31,33 @@ public class MpProductController { + private final ProductService productService; + private final QuoteCalculatorService quoteCalculatorService; + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表(C端)", ++ notes = "小程序端产品列表接口,仅返回已上架(PUBLISHED)的产品。\n\n" ++ + "支持按产品类型、季节、行程天数、目的地、产品线、支付模式、定制师等筛选。\n" ++ + "默认按 sortOrder 排序,也可按价格或行程天数排序。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选条件):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/list") + public Result> listProducts(@ApiParam("产品查询请求") @Valid MpProductQueryRequest query) { + return Result.success(productService.listPublishedProducts(query)); + } + +- @ApiOperation("产品详情") ++ @ApiOperation(value = "产品详情(C端)", ++ notes = "小程序端产品详情接口,仅返回已上架(PUBLISHED)的产品。\n" ++ + "包含完整的行程信息、定价配置、费用说明、创作者寄语等。\n" ++ + "未上架的产品会返回 404 错误。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}") + public Result getProduct(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(productService.getPublishedProduct(productId)); + } + +- @ApiOperation("报价计算") ++ @ApiOperation(value = "报价计算(C端)", ++ notes = "小程序端报价计算接口,根据用户选择的日期和人数计算总价。\n" ++ + "内部会校验产品是否存在且已上架。\n" ++ + "详细计算逻辑参见管理后台的报价计算接口说明。") + @PostMapping("/{productId}/quote") + public Result calculateQuote( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java +index cdd0cb8..1599755 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java +@@ -28,7 +28,18 @@ public class PricingController { + + // ========== 定价规则 ========== + +- @ApiOperation("保存定价规则") ++ @ApiOperation(value = "保存定价规则", ++ notes = "保存或更新产品的定价配置(一个产品仅一条定价记录,重复调用为覆盖更新)。\n\n" ++ + "**定价模式**:\n" ++ + "- AUTO:自动计算,通过公式引擎根据行程资源价格自动测算成本和售价\n" ++ + "- MANUAL:手动定价,直接在价格日历中手动设置每日价格\n" ++ + "- CUSTOM:定制定价,设置整单总价(customTotalPrice),不按人头\n\n" ++ + "**利润模式**(AUTO 模式下生效):\n" ++ + "- FIXED:固定金额加价,售价 = 成本 + profitAmount\n" ++ + "- PERCENT:百分比加价,售价 = 成本 × (1 + markupPercent/100)\n\n" ++ + "**支付方式**:FULL=全款支付,DEPOSIT=定金+尾款(需设置 depositRatio 或 depositAmount)\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):费用配置中车辆相关成本计算") + @PostMapping("/pricing") + public Result savePricing( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -36,7 +47,11 @@ public class PricingController { + return Result.success(pricingService.savePricing(productId, request)); + } + +- @ApiOperation("获取定价规则") ++ @ApiOperation(value = "获取定价规则", ++ notes = "获取产品的定价配置,包括定价模式、利润设置、儿童/婴儿价格、支付方式等。\n" ++ + "如果产品尚未设置定价规则,返回 null。\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):费用配置中车辆相关成本显示") + @GetMapping("/pricing") + public Result getPricing(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(pricingService.getPricing(productId)); +@@ -44,7 +59,11 @@ public class PricingController { + + // ========== 价格日历 ========== + +- @ApiOperation("获取月度价格日历") ++ @ApiOperation(value = "获取月度价格日历", ++ notes = "获取指定月份的价格日历数据列表。\n\n" ++ + "每条数据包含:日期、成人售价/成本价、儿童售价/成本价、库存、状态(OPEN/CLOSED)等。\n" ++ + "**CORE/GROUP 产品**:价格为单人价格,按人头 × 价格计算总价。\n" ++ + "**CUSTOM/ROUTE 产品**:价格为整单总价,不乘以人头数。") + @GetMapping("/price-calendar") + public Result> getMonthCalendar( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -53,7 +72,10 @@ public class PricingController { + return Result.success(calendarService.getMonthCalendar(productId, year, month)); + } + +- @ApiOperation("设置单日价格") ++ @ApiOperation(value = "设置单日价格", ++ notes = "设置或更新指定日期的价格和库存。如果该日期已有记录则更新,否则新建。\n\n" ++ + "可设置成人售价/成本价、儿童售价/成本价、库存数量、状态(OPEN/CLOSED)。\n" ++ + "状态为 CLOSED 的日期不会出现在小程序端的可选日期中。") + @PostMapping("/price-calendar") + public Result setDayPrice( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -61,7 +83,11 @@ public class PricingController { + return Result.success(calendarService.setDayPrice(productId, request)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", ++ notes = "批量设置日期范围内的价格和库存,支持按星期筛选。\n\n" ++ + "指定 startDate 和 endDate 日期范围,可选 selectedWeekdays 过滤星期几。\n" ++ + "示例:设置5月1日-5月31日的工作日(周一到周五=[1,2,3,4,5])价格。\n" ++ + "selectedWeekdays 为空时,范围内所有日期都会被设置。") + @PostMapping("/price-calendar/batch") + public Result> batchSetPrices( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -69,7 +95,13 @@ public class PricingController { + return Result.success(calendarService.batchSetPrices(productId, request)); + } + +- @ApiOperation("测算预览(不写入数据库)") ++ @ApiOperation(value = "测算预览(不写入数据库)", ++ notes = "根据行程中的资源价格日历,自动计算指定日期的成本价和售价,仅预览不保存。\n\n" ++ + "用于在设置价格日历前预览自动计算的结果。\n" ++ + "计算逻辑:汇总当天所有行程节点关联资源的价格 → 应用公式引擎 → 加上利润。\n" ++ + "GROUP 产品需要传 adultCount 参数(影响均摊计算)。\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):车辆费用成本测算") + @PostMapping("/price-calendar/calc-preview") + public Result calcPreview( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -77,13 +109,21 @@ public class PricingController { + return Result.success(calendarService.calcPreview(productId, request)); + } + +- @ApiOperation("重新测算所有自动测算日期的价格") ++ @ApiOperation(value = "重新测算所有自动测算日期的价格", ++ notes = "重新计算价格日历中所有 costAutoCalc=true 的日期的成本价和售价。\n\n" ++ + "适用场景:资源价格调整后,批量刷新所有自动计算的价格日历。\n" ++ + "返回更新的日期数量和详情。手动设置的价格(costAutoCalc=false)不受影响。") + @PostMapping("/price-calendar/recalculate") + public Result> recalculate(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(calendarService.recalculateAll(productId)); + } + +- @ApiOperation("自动计算成本并同步到价格日历") ++ @ApiOperation(value = "自动计算成本并同步到价格日历", ++ notes = "根据出发日期和人数,自动计算成本并将结果写入价格日历。\n\n" ++ + "与测算预览不同,此接口会实际更新价格日历数据。\n" ++ + "计算逻辑:查询各资源的价格日历 → 汇总成本 → 应用公式和利润规则 → 写入结果。\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):车辆费用成本计算") + @PostMapping("/price-calendar/auto-calc") + public Result autoCalcCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -100,7 +140,10 @@ public class PricingController { + + // ========== 费用包含/不包含 ========== + +- @ApiOperation("添加费用项") ++ @ApiOperation(value = "添加费用项", ++ notes = "添加产品的费用包含/不包含说明项。\n\n" ++ + "用于在产品详情页展示\"费用包含\"和\"费用不包含\"信息。\n" ++ + "仅用于前端展示,不参与报价计算。") + @PostMapping("/cost-item") + public Result addCostItem( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -108,7 +151,8 @@ public class PricingController { + return Result.success(costItemService.addCostItem(productId, request)); + } + +- @ApiOperation("更新费用项") ++ @ApiOperation(value = "更新费用项", ++ notes = "更新费用包含/不包含说明项的内容。仅用于前端展示,不参与报价计算。") + @PutMapping("/cost-item/{itemId}") + public Result updateCostItem( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -117,7 +161,8 @@ public class PricingController { + return Result.success(costItemService.updateCostItem(itemId, request)); + } + +- @ApiOperation("删除费用项") ++ @ApiOperation(value = "删除费用项", ++ notes = "删除费用包含/不包含说明项。") + @DeleteMapping("/cost-item/{itemId}") + public Result deleteCostItem( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -126,7 +171,8 @@ public class PricingController { + return Result.success(); + } + +- @ApiOperation("获取费用项列表") ++ @ApiOperation(value = "获取费用项列表", ++ notes = "获取产品的所有费用包含/不包含说明项列表。") + @GetMapping("/cost-items") + public Result> listCostItems(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(costItemService.listCostItems(productId)); +@@ -134,7 +180,10 @@ public class PricingController { + + // ========== 额外成本关联 ========== + +- @ApiOperation("添加额外成本关联") ++ @ApiOperation(value = "添加额外成本关联", ++ notes = "关联资源服务中的费用项(cost_item)到产品,参与成本自动计算。\n\n" ++ + "额外成本是指不包含在行程节点中、但需要计入总成本的费用。\n" ++ + "例如:导游服务费、保险费、通讯费等固定运营开支。") + @PostMapping("/extra-cost") + public Result addExtraCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -142,7 +191,8 @@ public class PricingController { + return Result.success(extraCostService.addExtraCost(productId, request)); + } + +- @ApiOperation("更新额外成本关联") ++ @ApiOperation(value = "更新额外成本关联", ++ notes = "更新额外成本关联的费用项、数量等信息。修改后会影响成本自动计算结果。") + @PutMapping("/extra-cost/{ecId}") + public Result updateExtraCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -151,7 +201,8 @@ public class PricingController { + return Result.success(extraCostService.updateExtraCost(ecId, request)); + } + +- @ApiOperation("删除额外成本关联") ++ @ApiOperation(value = "删除额外成本关联", ++ notes = "删除额外成本关联记录。删除后该费用项不再计入成本自动计算。") + @DeleteMapping("/extra-cost/{ecId}") + public Result removeExtraCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -160,7 +211,8 @@ public class PricingController { + return Result.success(); + } + +- @ApiOperation("获取额外成本关联列表") ++ @ApiOperation(value = "获取额外成本关联列表", ++ notes = "获取产品关联的所有额外成本项列表,包含费用项名称、金额等信息。") + @GetMapping("/extra-costs") + public Result> listExtraCosts(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(extraCostService.listExtraCosts(productId)); +@@ -168,7 +220,10 @@ public class PricingController { + +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java +index bc250d7..5f48dff 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java +@@ -28,7 +28,20 @@ public class ProductController { + private final ProductStatusService productStatusService; + private final RouteMapService routeMapService; + +- @ApiOperation("创建产品(草稿)") ++ @ApiOperation(value = "创建产品(草稿)", ++ notes = "创建一个新产品,初始状态为 DRAFT(草稿)。\n\n" ++ + "**产品类型说明**:\n" ++ + "- CORE:核心产品,标准旅游产品,支持上架/下架审批流程\n" ++ + "- GROUP:小蒙马拼团,需配合团期批次管理,按人头计价\n" ++ + "- CUSTOM:定制产品,由定制师为客户量身定制,按单计价\n" ++ + "- ROUTE:线路产品,预设线路模板,按单计价\n\n" ++ + "**注意事项**:\n" ++ + "- 创建后需依次完善行程、定价、价格日历等信息\n" ++ + "- CUSTOM/ROUTE 产品的价格日历存储的是整单总价,不按人头乘算\n" ++ + "- GROUP 产品需额外创建团期批次才能报名\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @PostMapping + public Result createProduct( + @ApiParam("创建产品请求") @Valid @RequestBody ProductCreateRequest request, +@@ -37,13 +50,28 @@ public class ProductController { + return Result.success(productService.createProduct(request, adminId)); + } + +- @ApiOperation("获取产品详情") ++ @ApiOperation(value = "获取产品详情", ++ notes = "获取产品完整信息,包括基本信息、行程天列表、定价配置、费用项等。\n" ++ + "返回数据包含关联的行程节点资源详情,适用于产品编辑页面。\n" ++ + "不过滤产品状态,所有状态的产品都可查看。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}") + public Result getProduct(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(productService.getProduct(productId)); + } + +- @ApiOperation("更新产品") ++ @ApiOperation(value = "更新产品", ++ notes = "更新产品基本信息,仅传入需要修改的字段,未传字段不会被覆盖。\n\n" ++ + "**权限说明**:\n" ++ + "- 普通管理员只能编辑自己创建的产品\n" ++ + "- SUPER_ADMIN 可编辑所有产品\n\n" ++ + "**注意**:行程、定价、价格日历等通过各自独立的接口管理,不在此接口中处理。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @PutMapping("/{productId}") + public Result updateProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -54,7 +82,10 @@ public class ProductController { + return Result.success(productService.updateProduct(productId, request, adminId, role)); + } + +- @ApiOperation("删除产品") ++ @ApiOperation(value = "删除产品", ++ notes = "软删除产品(设置 deleted_at 字段)。\n\n" ++ + "**权限说明**:普通管理员只能删除自己创建的产品,SUPER_ADMIN 可删除所有产品。\n" ++ + "**限制**:已上架(PUBLISHED)的产品不能直接删除,需先下架。") + @DeleteMapping("/{productId}") + public Result deleteProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -65,17 +96,33 @@ public class ProductController { + return Result.success(); + } + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", ++ notes = "分页查询产品列表,支持多维度筛选和排序。\n\n" ++ + "**权限说明**:\n" ++ + "- 普通管理员只能看到自己创建的产品\n" ++ + "- SUPER_ADMIN 可看到所有产品\n\n" ++ + "**筛选条件**:关键词(名称/副标题模糊匹配)、产品类型、状态、文件夹、产品线、季节、行程天数。\n" ++ + "支持多状态筛选(statuses 字段,逗号分隔)。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选条件):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态,筛选条件+返回字段):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单") + @GetMapping("/list") + public Result> listProducts( + @ApiParam("产品查询请求") @Valid ProductQueryRequest query, + HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +- boolean isSuperAdmin = "SUPER_ADMIN".equals(httpRequest.getAttribute("role")); +- return Result.success(productService.listProducts(query, adminId, isSuperAdmin)); ++ String role = (String) httpRequest.getAttribute("role"); ++ boolean canViewAll = "SUPER_ADMIN".equals(role) || "CUSTOMER_SERVICE".equals(role); ++ return Result.success(productService.listProducts(query, adminId, canViewAll)); + } + +- @ApiOperation("复制产品") ++ @ApiOperation(value = "复制产品", ++ notes = "深度复制产品,包括行程天、行程节点、定价配置、住宿、餐饮、物资、人员配置等所有关联数据。\n\n" ++ + "复制后的产品状态为 DRAFT,名称自动添加\"(副本)\"后缀。\n" ++ + "适用场景:基于已有产品快速创建新产品。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,返回字段):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态,复制后固定为 DRAFT)") + @PostMapping("/{productId}/copy") + public Result copyProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -84,7 +131,9 @@ public class ProductController { + return Result.success(productService.copyProduct(productId, adminId)); + } + +- @ApiOperation("移动产品到文件夹") ++ @ApiOperation(value = "移动产品到文件夹", ++ notes = "将产品移动到指定文件夹,或移出文件夹(folderId 传空字符串或 null)。\n" ++ + "文件夹用于组织管理产品,不影响产品的业务逻辑。") + @PutMapping("/{productId}/move") + public Result moveProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -95,7 +144,10 @@ public class ProductController { + return Result.success(); + } + +- @ApiOperation("生成定制产品分享链接") ++ @ApiOperation(value = "生成定制产品分享链接", ++ notes = "为 CUSTOM(定制)产品生成小程序分享链接,用于定制师发送给客户查看方案。\n\n" ++ + "**限制**:仅 CUSTOM 类型且状态为 COMPLETED 的产品可生成。\n" ++ + "**权限**:普通管理员只能为自己创建的产品生成链接,SUPER_ADMIN 不受限制。") + @PostMapping("/{productId}/share-link") + public Result generateShareLink( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -105,7 +157,10 @@ public class ProductController { + return Result.success(productService.generateShareLink(productId, adminId, role)); + } + +- @ApiOperation("手动生成路径图") ++ @ApiOperation(value = "手动生成路径图", ++ notes = "根据产品行程节点的经纬度信息,调用地图API生成行程路径图。\n\n" ++ + "通常在行程编辑完成后手动触发,生成结果为 OSS 图片 URL。\n" ++ + "如果行程节点没有经纬度信息,则无法生成路径图。") + @PostMapping("/{productId}/generate-route-map") + public Result generateRouteMap(@ApiParam("产品ID") @PathVariable Long productId) { + try { +@@ -116,7 +171,20 @@ public class ProductController { + } + } + +- @ApiOperation("产品状态变更(上架/下架等)") ++ @ApiOperation(value = "产品状态变更(上架/下架/完成)", ++ notes = "根据产品类型,状态流转规则不同:\n\n" ++ + "**核心产品(CORE) / 小蒙马(GROUP)**:支持上架/下架,需企微审批\n" ++ + "- DRAFT → PENDING_REVIEW → REVIEWED → PUBLISHED(上架)\n" ++ + "- PUBLISHED → UNPUBLISHED(下架)\n" ++ + "- UNPUBLISHED → PUBLISHED(重新上架)\n" ++ + "- REJECTED → DRAFT(驳回后重新编辑)\n\n" ++ + "**定制产品(CUSTOM)**:仅支持完成,无上架/下架概念\n" ++ + "- DRAFT → COMPLETED(定制师完成设计)\n" ++ + "- COMPLETED → ORDERED(客户下单,系统自动变更)\n" ++ + "- ORDERED → COMPLETED(订单取消/退款后回退)\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响状态流转规则):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态,请求+返回字段):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单") + @PutMapping("/{productId}/status") + public Result changeStatus( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java +index 2562b23..2b69413 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java +@@ -23,7 +23,9 @@ public class ProductFolderController { + + private final ProductFolderService folderService; + +- @ApiOperation("创建文件夹") ++ @ApiOperation(value = "创建文件夹", ++ notes = "创建产品文件夹,用于组织管理产品。支持多级目录结构。\n" ++ + "文件夹归属于创建人,普通管理员只能看到自己的文件夹。") + @PostMapping + public Result createFolder( + @ApiParam("创建文件夹请求") @Valid @RequestBody FolderCreateRequest request, +@@ -33,7 +35,9 @@ public class ProductFolderController { + return Result.success(folderService.createFolder(request, adminId, ownerName)); + } + +- @ApiOperation("更新文件夹") ++ @ApiOperation(value = "更新文件夹", ++ notes = "更新文件夹名称等信息。\n" ++ + "**权限说明**:普通管理员只能更新自己创建的文件夹,SUPER_ADMIN 可更新任何文件夹。") + @PutMapping("/{folderId}") + public Result updateFolder( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -44,7 +48,9 @@ public class ProductFolderController { + return Result.success(folderService.updateFolder(folderId, request, adminId, isSuperAdmin)); + } + +- @ApiOperation("删除文件夹") ++ @ApiOperation(value = "删除文件夹", ++ notes = "删除文件夹。如果文件夹下有产品,产品会自动移到根目录(folderId 置空)。\n" ++ + "普通管理员只能删除自己的文件夹,SUPER_ADMIN 可删除任何文件夹。") + @DeleteMapping("/{folderId}") + public Result deleteFolder(@ApiParam("文件夹ID") @PathVariable Long folderId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -53,7 +59,10 @@ public class ProductFolderController { + return Result.success(); + } + +- @ApiOperation("获取文件夹树") ++ @ApiOperation(value = "获取文件夹树", ++ notes = "获取当前用户可见的文件夹树形结构。\n" ++ + "普通管理员只能看到自己创建的文件夹,SUPER_ADMIN 可看到所有文件夹。\n" ++ + "返回结构为嵌套的树形列表,包含每个文件夹的子文件夹。") + @GetMapping("/tree") + public Result> getFolderTree(HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java +index 28d7d17..13683ab 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java +@@ -25,7 +25,9 @@ public class ProductLineController { + + private final ProductLineService lineService; + +- @ApiOperation("创建产品线") ++ @ApiOperation(value = "创建产品线", ++ notes = "创建产品线,用于对产品进行业务分类(如:亲子游、蜜月游、探险游等)。\n" ++ + "产品线在小程序端可作为筛选条件,帮助用户快速找到感兴趣的产品类别。") + @PostMapping + public Result createLine( + @ApiParam("创建产品线请求") @Valid @RequestBody LineCreateRequest request, +@@ -34,7 +36,8 @@ public class ProductLineController { + return Result.success(lineService.createLine(request, adminId)); + } + +- @ApiOperation("更新产品线") ++ @ApiOperation(value = "更新产品线", ++ notes = "更新产品线名称、描述、状态等信息。") + @PutMapping("/{lineId}") + public Result updateLine( + @ApiParam("产品线ID") @PathVariable Long lineId, +@@ -42,26 +45,31 @@ public class ProductLineController { + return Result.success(lineService.updateLine(lineId, request)); + } + +- @ApiOperation("删除产品线") ++ @ApiOperation(value = "删除产品线", ++ notes = "删除产品线(软删除)。已关联产品的产品线仍可删除,但关联产品的产品线字段不会被清空。") + @DeleteMapping("/{lineId}") + public Result deleteLine(@ApiParam("产品线ID") @PathVariable Long lineId) { + lineService.deleteLine(lineId); + return Result.success(); + } + +- @ApiOperation("产品线详情") ++ @ApiOperation(value = "产品线详情", ++ notes = "获取指定产品线的完整信息。") + @GetMapping("/{lineId}") + public Result getLine(@ApiParam("产品线ID") @PathVariable Long lineId) { + return Result.success(lineService.getLine(lineId)); + } + +- @ApiOperation("产品线列表(分页)") ++ @ApiOperation(value = "产品线列表(分页)", ++ notes = "分页查询产品线列表,支持按名称关键词筛选。") + @GetMapping("/list") + public Result> listLines(@ApiParam("产品线查询请求") @Valid LineQueryRequest query) { + return Result.success(lineService.listLines(query)); + } + +- @ApiOperation("所有启用的产品线") ++ @ApiOperation(value = "所有启用的产品线", ++ notes = "获取所有启用状态的产品线,不分页。\n" ++ + "适用于产品编辑时的产品线下拉选择,以及小程序端的筛选项。") + @GetMapping("/active") + public Result> listAllActive() { + return Result.success(lineService.listAllActive()); +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java +index b6676e4..81f33f0 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java +@@ -23,7 +23,18 @@ public class QuoteController { + private final QuoteCalculatorService quoteCalculatorService; + private final CostCalculationService costCalculationService; + +- @ApiOperation("计算报价") ++ @ApiOperation(value = "计算报价", ++ notes = "根据出发日期和人数组合,计算产品的完整报价。\n\n" ++ + "**计算流程**:\n" ++ + "1. 从价格日历获取指定日期的单价\n" ++ + "2. 按人数类型分别计算:成人 × 成人价、儿童 × 儿童价\n" ++ + "3. 小童按儿童价 × 折扣比例(childDiscountPercent)计算\n" ++ + "4. 婴儿使用固定价格(babyPrice)\n" ++ + "5. 儿童加床(childNeedBed=true)额外加收 childWithBed 费用\n\n" ++ + "**CUSTOM/ROUTE 产品**:价格日历存的是整单总价,不按人头乘算。\n" ++ + "**GROUP 产品**:建议使用 group-quote 接口,支持套餐组合报价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响计算逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/quote") + public Result calculateQuote( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -31,7 +42,13 @@ public class QuoteController { + return Result.success(quoteCalculatorService.calculateQuote(productId, request)); + } + +- @ApiOperation("GROUP产品报价(按组合)") ++ @ApiOperation(value = "GROUP产品报价(按套餐组合)", ++ notes = "为 GROUP(小蒙马拼团)产品按团期批次和套餐组合计算报价。\n\n" ++ + "GROUP 产品的价格由批次下的套餐组合(combo)决定,不同组合有不同的成人/儿童人数搭配和价格。\n" ++ + "传入 batchId 指定团期批次,adultCount 用于匹配合适的套餐组合。\n\n" ++ + "**与普通报价的区别**:普通报价从价格日历取单价,GROUP 报价从套餐组合取打包价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限GROUP):GROUP=小蒙马拼团") + @GetMapping("/group-quote") + public Result calculateGroupQuote( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java +index ab64e9e..4015f1e 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java +@@ -26,7 +26,7 @@ public class ActivityController { + + private final ActivityService activityService; + +- @ApiOperation("创建游玩项目") ++ @ApiOperation(value = "创建游玩项目", notes = "新建游玩项目资源(如漂流、骑行、篝火晚会等),初始状态为草稿(status=0)。需通过「提交启用/禁用审批」走企微审批后上架。支持按项收费(PER_ITEM)和按人收费(PER_PERSON)两种计费方式。\n\n**关联字典**:\n- activity_category:活动分类(表单选择)\n- activity_billing_type:计费方式(表单选择)") + @PostMapping("/item") + public Result createActivity( + @ApiParam("游玩项目创建请求") @Valid @RequestBody ActivityCreateRequest request, +@@ -35,19 +35,19 @@ public class ActivityController { + return Result.success(activityService.createActivity(request, adminId)); + } + +- @ApiOperation("游玩项目列表") ++ @ApiOperation(value = "游玩项目列表", notes = "分页查询游玩项目列表,支持按名称、状态、分类等条件筛选。返回摘要信息,按sortOrder倒序+创建时间倒序排列。\n\n**关联字典**:\n- activity_category:活动分类(筛选+列表显示)\n- activity_billing_type:计费方式(列表显示)") + @GetMapping("/items") + public Result> listActivities(@ApiParam("游玩项目查询请求") @Valid ActivityQueryRequest query) { + return Result.success(activityService.listActivities(query)); + } + +- @ApiOperation("游玩项目详情") ++ @ApiOperation(value = "游玩项目详情", notes = "获取游玩项目完整信息,包含富文本内容、素材URL、标签、价格日历等。\n\n**关联字典**:\n- activity_category:活动分类(详情显示)\n- activity_billing_type:计费方式(详情显示)") + @GetMapping("/item/{activityId}") + public Result getActivity(@ApiParam("游玩项目ID") @PathVariable Long activityId) { + return Result.success(activityService.getActivity(activityId)); + } + +- @ApiOperation("更新游玩项目") ++ @ApiOperation(value = "更新游玩项目", notes = "更新游玩项目基本信息,不改变当前状态。已上架的项目修改后仍保持上架。\n\n**关联字典**:\n- activity_category:活动分类(表单选择)\n- activity_billing_type:计费方式(表单选择)") + @PutMapping("/item/{activityId}") + public Result updateActivity( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -57,7 +57,7 @@ public class ActivityController { + return Result.success(activityService.updateActivity(activityId, request, adminId)); + } + +- @ApiOperation("删除游玩项目") ++ @ApiOperation(value = "删除游玩项目", notes = "软删除游玩项目。仅SUPER_ADMIN或创建者可操作。删除后关联的素材引用会被清理。") + @DeleteMapping("/item/{activityId}") + public Result deleteActivity( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -68,7 +68,7 @@ public class ActivityController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。审批通过后自动更新状态,返回审批单号spNo。") + @PostMapping("/item/{activityId}/submit-approval") + public Result> submitApproval( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -80,7 +80,7 @@ public class ActivityController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("启用/禁用切换") ++ @ApiOperation(value = "启用/禁用切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{activityId}/status") + public Result updateStatus( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -91,7 +91,7 @@ public class ActivityController { + return Result.success(); + } + +- @ApiOperation("批量启用/禁用") ++ @ApiOperation(value = "批量启用/禁用", notes = "批量修改多个游玩项目的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("游玩项目状态请求") @Valid @RequestBody ActivityStatusRequest request, +@@ -103,7 +103,7 @@ public class ActivityController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个游玩项目。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java +index 9fec542..3fff48f 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java +@@ -25,7 +25,7 @@ public class ActivityPriceCalendarController { + + private final ActivityPriceCalendarService priceService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询游玩项目的每日价格和可接待状态。") + @GetMapping("/item/{activityId}/prices") + public Result getPriceCalendar( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -34,7 +34,7 @@ public class ActivityPriceCalendarController { + return Result.success(priceService.getPriceCalendar(activityId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置成本价和可接待状态。支持按星期过滤和排除特定日期。") + @PutMapping("/item/{activityId}/prices") + public Result batchSetPrices( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -43,7 +43,7 @@ public class ActivityPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改可接待状态") ++ @ApiOperation(value = "批量修改可接待状态", notes = "批量修改指定日期范围内的可接待状态,不影响价格。") + @PutMapping("/item/{activityId}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -52,7 +52,7 @@ public class ActivityPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量清除价格") ++ @ApiOperation(value = "批量清除价格", notes = "删除指定日期范围内的所有价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/item/{activityId}/prices") + public Result deletePrices( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java +index 2a01cd2..80b72a0 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java +@@ -27,7 +27,7 @@ public class ActivityTagController { + + private final ActivityTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询游玩项目标签库,支持按关键词搜索。包含预设标签和自定义标签。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class ActivityTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于项目编辑时的标签选择下拉。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。可指定颜色(tagColor),默认#409EFF。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class ActivityTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。用于项目编辑时快速输入新标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class ActivityTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色,所有关联项目自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class ActivityTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并自动解除所有项目与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新项目标签") ++ @ApiOperation(value = "更新项目标签", notes = "全量替换指定项目的标签列表。传入tagIds为最终关联的标签ID列表,为空则清除所有标签。") + @PutMapping("/item/{activityId}/tags") + public Result updateActivityTags( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -87,7 +87,7 @@ public class ActivityTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个项目批量添加/移除标签。增量操作,不影响未指定的标签。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java +index e24ce98..1b5dd8f 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】游玩项目(Feign调用)") ++@Api(tags = "【内部接口】游玩项目(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/activity") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalActivityController { + + private final ActivityService activityService; + +- @ApiOperation("获取项目简要信息") ++ @ApiOperation(value = "获取项目简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个游玩项目的简要信息,返回ID、名称、分类编码、计费类型、状态。不存在时返回错误。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{activityId}") + public Result> getActivityBrief(@PathVariable Long activityId) { + Activity item = activityService.getActivityEntity(activityId); +@@ -41,7 +41,7 @@ public class InternalActivityController { + return Result.success(brief); + } + +- @ApiOperation("批量获取项目简要信息") ++ @ApiOperation(value = "批量获取项目简要信息", notes = "【仅限内部Feign调用】批量获取游玩项目简要信息,最多500个ID。不存在的ID自动过滤,返回实际找到的项目列表。供产品服务批量查询行程节点绑定的活动资源。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getActivityBatch(@RequestParam @Size(max = 500) List activityIds) { + List> results = activityIds.stream() +@@ -61,9 +61,9 @@ public class InternalActivityController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo(审批单号)匹配游玩项目并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + activityService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java +index 63164c0..03e9f1d 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; + /** + * C端活动内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序活动(Feign调用)") ++@Api(tags = "【内部接口】小程序活动(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/activity") + @RequiredArgsConstructor +@@ -22,14 +22,14 @@ public class InternalMpActivityController { + + private final ActivityService activityService; + +- @ApiOperation("C端活动列表") ++ @ApiOperation(value = "C端活动列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架活动,支持分页和筛选。C端用户通过小程序间接访问。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- environment_type(环境类型,返回字段environmentType):INDOOR=室内, OUTDOOR=户外, MIXED=混合") + @GetMapping("/list") + public Result> listActivities(ActivityQueryRequest query) { + query.setStatus(1); + return Result.success(activityService.listActivities(query)); + } + +- @ApiOperation("C端活动详情") ++ @ApiOperation(value = "C端活动详情", notes = "【仅限内部Feign调用】供mp-service获取活动完整详情,包含封面、轮播图、标签、富文本介绍等。注意:不限制status,由BFF层校验是否展示。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- environment_type(环境类型,返回字段environmentType):INDOOR=室内, OUTDOOR=户外, MIXED=混合") + @GetMapping("/{activityId}") + public Result getActivityDetail(@PathVariable Long activityId) { + ActivityVO vo = activityService.getActivity(activityId); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java +index 3fcaf95..a7c45f5 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java +@@ -40,7 +40,7 @@ import java.util.stream.Collectors; + */ + @Slf4j + @Validated +-@Api(tags = "【内部接口】资源摘要(Feign调用)") ++@Api(tags = "【内部接口】资源摘要(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/resource") + @RequiredArgsConstructor +@@ -60,7 +60,7 @@ public class InternalMpResourceBriefController { + + private final MaterialRefFeignClient materialRefClient; + +- @ApiOperation("批量查询景区摘要") ++ @ApiOperation(value = "批量查询景区摘要", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用(收藏列表/足迹列表),返回最小化信息:id、name、coverUrl、tags。最多500个ID。") + @GetMapping("/scenic/brief") + public Result>> getScenicBrief(@RequestParam @Size(max = 500) List ids) { + if (ids == null || ids.isEmpty()) { +@@ -94,7 +94,7 @@ public class InternalMpResourceBriefController { + return Result.success(result); + } + +- @ApiOperation("批量查询餐厅摘要") ++ @ApiOperation(value = "批量查询餐厅摘要", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用,返回最小化信息。最多500个ID。") + @GetMapping("/restaurant/brief") + public Result>> getRestaurantBrief(@RequestParam @Size(max = 500) List ids) { + if (ids == null || ids.isEmpty()) { +@@ -126,7 +126,7 @@ public class InternalMpResourceBriefController { + return Result.success(result); + } + +- @ApiOperation("批量查询活动摘要") ++ @ApiOperation(value = "批量查询活动摘要", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用,返回最小化信息。最多500个ID。") + @GetMapping("/activity/brief") + public Result>> getActivityBrief(@RequestParam @Size(max = 500) List ids) { + if (ids == null || ids.isEmpty()) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java +index d4158a8..44cd22e 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java +@@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.*; + *

+ */ + @Slf4j +-@Api(tags = "【内部接口】资源审批(Feign调用)") ++@Api(tags = "【内部接口】资源审批(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/resource") + @RequiredArgsConstructor +@@ -42,9 +42,9 @@ public class InternalResourceController { + private final StaffService staffService; + + /** 处理审批回调 - 分发到9个资源领域服务 */ +- @ApiOperation("处理审批回调 - 分发到9个资源领域服务") ++ @ApiOperation(value = "处理审批回调 - 分发到9个资源领域服务", notes = "【仅限内部Feign调用】接收企微审批回调结果,按thirdNo(审批单号)在9个资源领域中匹配并更新状态。每个领域服务内部通过approval_no匹配,未找到则忽略(幂等处理)。由hl-callback-service通过MQ消费后调用。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + + // 分发到9个领域服务 - 每个服务内部检查approval_no +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java +index a6adb66..e726a14 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java +@@ -41,7 +41,7 @@ import java.util.stream.Collectors; + * 供产品服务的行程节点获取绑定资源的详细信息(含图片、地址等) + */ + @Slf4j +-@Api(tags = "【内部接口】资源详情(Feign调用)") ++@Api(tags = "【内部接口】资源详情(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/resource") + @RequiredArgsConstructor +@@ -69,7 +69,7 @@ public class InternalResourceDetailController { + * @param activityIds 活动ID列表 + * @return resourceType:resourceId → ResourceDetailDTO + */ +- @ApiOperation("批量查询资源详情(行程节点用)") ++ @ApiOperation(value = "批量查询资源详情(行程节点用)", notes = "【仅限内部Feign调用】供产品服务获取行程节点绑定资源的详细信息。按类型分组查询,返回Map。包含封面、轮播图URL、地址、坐标、标签、富文本介绍等完整信息。\n\n**关联字典**:\n- city(城市,返回字段city)") + @GetMapping("/batch-details") + public Result> batchDetails( + @RequestParam(required = false) List scenicIds, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java +index 366168b..e1ddd03 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java +@@ -53,7 +53,7 @@ import java.util.stream.Collectors; + @RestController + @RequestMapping("/internal/resource/prices") + @RequiredArgsConstructor +-@Api(tags = "【内部接口】资源价格(Feign调用)") ++@Api(tags = "【内部接口】资源价格(Feign调用)", hidden = true) + public class InternalResourcePriceController { + + private final ScenicPriceCalendarMapper scenicPriceMapper; +@@ -71,7 +71,7 @@ public class InternalResourcePriceController { + private final SuppliesItemMapper suppliesItemMapper; + private final SuppliesService suppliesService; + +- /** 查询景区价格 */ ++ /** 查询景区价格 - 按景区ID和日期范围查询价格日历的成本价 */ + @PostMapping("/scenic") + public Result> getScenicPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -108,7 +108,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询酒店价格(按hotelId查最低房型价格) */ ++ /** 查询酒店价格 - 按hotelId查询日期范围内最低房型的成本价(取所有房型中最低价) */ + @PostMapping("/hotel") + public Result> getHotelPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -143,7 +143,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询房型价格(按roomTypeId精确查询) */ ++ /** 查询房型价格 - 按roomTypeId精确查询日期范围内的成本价(取最低价) */ + @PostMapping("/room-type") + public Result> getRoomTypePrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -178,7 +178,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询活动价格 */ ++ /** 查询活动价格 - 按活动ID和日期范围查询价格日历的成本价 */ + @PostMapping("/activity") + public Result> getActivityPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -214,7 +214,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询车辆价格 */ ++ /** 查询车辆价格 - 按车型ID和日期范围查询价格日历的成本价 */ + @PostMapping("/vehicle") + public Result> getVehiclePrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -250,7 +250,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询服务项价格 */ ++ /** 查询服务项价格 - 按服务项ID和日期范围查询价格日历的成本价 */ + @PostMapping("/service") + public Result> getServicePrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -283,13 +283,13 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询餐厅价格(餐厅无价格日历,返回空) */ ++ /** 查询餐厅价格 - 餐厅无独立价格日历,始终返回空列表(餐费通过费用项管理) */ + @PostMapping("/restaurant") + public Result> getRestaurantPrices(@RequestBody PriceQuery query) { + return Result.success(new ArrayList<>()); + } + +- /** 查询服务人员价格(按人员类型) */ ++ /** 查询服务人员价格 - 按staffType(人员类型)和日期范围查询价格日历的成本价(人员价格按类型而非个人) */ + @PostMapping("/staff") + public Result> getStaffPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -321,7 +321,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询酒店下所有房型(简要信息) */ ++ /** 查询酒店下所有已启用房型 - 返回roomTypeId、name、maxOccupancy、basePrice,按sortOrder排序 */ + @GetMapping("/room-types-by-hotel/{hotelId}") + public Result> getRoomTypesByHotel(@PathVariable Long hotelId) { + List roomTypes = roomTypeMapper.selectList( +@@ -336,7 +336,7 @@ public class InternalResourcePriceController { + return Result.success(vos); + } + +- /** 查询所有可用车型(简要信息) */ ++ /** 查询所有已启用车型 - 返回vehicleId、name、seatCount、basePrice,按sortOrder排序,供产品服务车辆下拉选择使用 */ + @GetMapping("/vehicle-models") + public Result> getVehicleModels() { + List vehicles = vehicleModelMapper.selectList( +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java +index 019a26f..3ef23db 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RestController; + import java.util.HashMap; + import java.util.Map; + +-@Api(tags = "【内部接口】资源统计(Feign调用)") ++@Api(tags = "【内部接口】资源统计(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/resource") + @RequiredArgsConstructor +@@ -24,7 +24,7 @@ public class InternalResourceStatsController { + private final RoomTypeMapper roomTypeMapper; + private final VehicleModelMapper vehicleModelMapper; + +- @ApiOperation("获取酒店统计") ++ @ApiOperation(value = "获取酒店统计", notes = "【仅限内部Feign调用】返回酒店总数和房型总数,供管理后台仪表盘展示。") + @GetMapping("/hotel/stats") + public Result> getHotelStats() { + long totalHotels = hotelMapper.selectCount(null); +@@ -36,7 +36,7 @@ public class InternalResourceStatsController { + return Result.success(stats); + } + +- @ApiOperation("获取车辆统计") ++ @ApiOperation(value = "获取车辆统计", notes = "【仅限内部Feign调用】返回车型总数,供管理后台仪表盘展示。") + @GetMapping("/vehicle/stats") + public Result> getVehicleStats() { + long totalVehicles = vehicleModelMapper.selectCount(null); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java +index ce21f8c..b138078 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java +@@ -28,7 +28,7 @@ public class CostItemController { + + private final CostItemService costItemService; + +- @ApiOperation("创建费用项") ++ @ApiOperation(value = "创建费用项", notes = "新建费用项(如门票成本、餐费、保险费等),用于产品报价计算。费用项有独立的价格日历,价格变更会记录变更日志。创建后需走企微审批上架。\n\n**关联字典**:\n- cost_category:费用分类(表单选择)\n- cost_apply_role:适用角色(表单选择)\n- cost_unit:计量单位(表单选择)") + @PostMapping("/item") + public Result createCostItem(@ApiParam("费用项创建请求") @Valid @RequestBody CostItemCreateRequest request, + HttpServletRequest httpRequest) { +@@ -36,19 +36,19 @@ public class CostItemController { + return Result.success(costItemService.createCostItem(request, adminId)); + } + +- @ApiOperation("费用项列表") ++ @ApiOperation(value = "费用项列表", notes = "分页查询费用项列表,支持按名称、状态等条件筛选。\n\n**关联字典**:\n- cost_category:费用分类(筛选+列表显示)\n- cost_apply_role:适用角色(筛选+列表显示)\n- cost_unit:计量单位(列表显示)") + @GetMapping("/items") + public Result> listCostItems(@ApiParam("费用项查询请求") @Valid CostItemQueryRequest query) { + return Result.success(costItemService.listCostItems(query)); + } + +- @ApiOperation("费用项详情") ++ @ApiOperation(value = "费用项详情", notes = "获取费用项完整信息,包含当前价格、引用计数等。\n\n**关联字典**:\n- cost_category:费用分类(详情显示)\n- cost_apply_role:适用角色(详情显示)\n- cost_unit:计量单位(详情显示)") + @GetMapping("/item/{costId}") + public Result getCostItem(@ApiParam("费用项ID") @PathVariable Long costId) { + return Result.success(costItemService.getCostItem(costId)); + } + +- @ApiOperation("更新费用项") ++ @ApiOperation(value = "更新费用项", notes = "更新费用项信息。如果修改了价格,会自动记录价格变更日志。\n\n**关联字典**:\n- cost_category:费用分类(表单选择)\n- cost_apply_role:适用角色(表单选择)\n- cost_unit:计量单位(表单选择)") + @PutMapping("/item/{costId}") + public Result updateCostItem(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("费用项更新请求") @Valid @RequestBody CostItemUpdateRequest request, +@@ -57,7 +57,7 @@ public class CostItemController { + return Result.success(costItemService.updateCostItem(costId, request, adminId)); + } + +- @ApiOperation("删除费用项") ++ @ApiOperation(value = "删除费用项", notes = "软删除费用项。仅SUPER_ADMIN或创建者可操作。被产品引用(refCount>0)的费用项不建议删除。") + @DeleteMapping("/item/{costId}") + public Result deleteCostItem(@ApiParam("费用项ID") @PathVariable Long costId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -66,7 +66,7 @@ public class CostItemController { + return Result.success(); + } + +- @ApiOperation("提交审批") ++ @ApiOperation(value = "提交审批", notes = "向企微OA提交费用项启用/禁用审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{costId}/submit-approval") + public Result> submitApproval(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("审批提交请求体") @Valid @RequestBody ApprovalSubmitRequest request, +@@ -76,13 +76,13 @@ public class CostItemController { + return Result.success(java.util.Map.of("spNo", spNo)); + } + +- @ApiOperation("启用的费用项列表") ++ @ApiOperation(value = "启用的费用项列表", notes = "查询所有已启用(status=1)的费用项,不分页。用于产品编排时选择费用项的下拉列表。\n\n**关联字典**:\n- cost_category:费用分类(列表显示)\n- cost_apply_role:适用角色(列表显示)\n- cost_unit:计量单位(列表显示)") + @GetMapping("/items/enabled") + public Result> listEnabledCostItems() { + return Result.success(costItemService.listEnabledCostItems()); + } + +- @ApiOperation("费用项价格变更记录") ++ @ApiOperation(value = "费用项价格变更记录", notes = "查询费用项的历史价格变更记录,按时间倒序排列。用于追溯价格调整历史。") + @GetMapping("/item/{costId}/price-logs") + public Result> getPriceLogs(@ApiParam("费用项ID") @PathVariable Long costId) { + return Result.success(costItemService.getPriceLogs(costId)); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java +index 862c1b2..95007f0 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java +@@ -26,7 +26,7 @@ public class CostPriceCalendarController { + + private final CostPriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询费用项的每日价格。费用项价格日历用于产品报价计算时按日期获取成本价。") + @GetMapping("/item/{costId}/prices") + public Result getPriceCalendar(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("年份") @RequestParam @Min(2020) @Max(2100) Integer year, +@@ -34,7 +34,7 @@ public class CostPriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(costId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置费用项的成本价。") + @PutMapping("/item/{costId}/prices") + public Result batchSetPrices(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("价格日历设置请求") @Valid @RequestBody PriceCalendarSetRequest request) { +@@ -42,7 +42,7 @@ public class CostPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("清除价格日历") ++ @ApiOperation(value = "清除价格日历", notes = "删除指定日期范围内费用项的价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/item/{costId}/prices") + public Result deletePrices(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("开始日期") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java +index 5e27f64..361c8de 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java +@@ -20,7 +20,7 @@ import java.util.Map; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】费用项(Feign调用)") ++@Api(tags = "【内部接口】费用项(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/cost") + @RequiredArgsConstructor +@@ -28,21 +28,21 @@ public class InternalCostController { + + private final CostItemService costItemService; + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配费用项并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + costItemService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); + } + +- @ApiOperation("批量获取费用项") ++ @ApiOperation(value = "批量获取费用项", notes = "【仅限内部Feign调用】批量获取费用项完整信息(含名称、分类、计费类型、基础价格等),最多500个ID。供产品服务批量查询产品关联的费用项。\n\n**关联字典**:\n- cost_unit(计费单位,返回字段unit):PER_PERSON=元/人, PER_VEHICLE=元/台, PER_DAY=元/天, PER_TIME=元/次, PER_ROOM=元/间, PER_TABLE=元/桌, FIXED=固定金额\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result> batchGetCostItems(@RequestParam @Size(max = 500) List costIds) { + return Result.success(costItemService.batchGetCostItems(costIds)); + } + +- @ApiOperation("按日期获取费用项价格") ++ @ApiOperation(value = "按日期获取费用项价格", notes = "【仅限内部Feign调用】按指定日期批量查询费用项的成本价格。返回Map。优先取价格日历,无日历则取basePrice。供产品服务报价计算器使用。") + @GetMapping("/items/prices-by-date") + public Result> getByDatePrices( + @RequestParam @Size(max = 500) List costIds, +@@ -50,7 +50,7 @@ public class InternalCostController { + return Result.success(costItemService.getByDatePrices(costIds, date)); + } + +- @ApiOperation("更新引用计数") ++ @ApiOperation(value = "更新引用计数", notes = "【仅限内部Feign调用】更新费用项的引用计数。delta>0表示新增引用,delta<0表示减少引用。供产品服务在关联/取消关联费用项时调用,用于统计资源被使用次数。") + @PostMapping("/item/{costId}/ref-count") + public Result updateRefCount(@PathVariable Long costId, @RequestParam int delta) { + costItemService.updateRefCount(costId, delta); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java +index 4a0c2c5..7faaef1 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java +@@ -26,7 +26,7 @@ public class HotelController { + + private final HotelService hotelService; + +- @ApiOperation("创建住宿") ++ @ApiOperation(value = "创建住宿", notes = "新建住宿资源(酒店/民宿/营地等),初始状态为草稿(status=0)。创建后需通过「提交启用/禁用审批」走企微OA审批流程才能上架。住宿下可继续创建房型(RoomType),房型有独立的价格日历。\n\n**关联字典**:\n- hotel_type:住宿类型(表单选择)\n- hotel_star_level:酒店星级(表单选择)\n- hotel_facility:酒店设施(表单多选)") + @PostMapping("/item") + public Result createHotel( + @ApiParam("住宿创建请求") @Valid @RequestBody HotelCreateRequest request, +@@ -35,25 +35,25 @@ public class HotelController { + return Result.success(hotelService.createHotel(request, adminId)); + } + +- @ApiOperation("住宿列表") ++ @ApiOperation(value = "住宿列表", notes = "分页查询住宿列表,支持按名称关键词、状态、住宿类型等条件筛选。返回列表摘要信息,按sortOrder倒序+创建时间倒序排列。\n\n**关联字典**:\n- hotel_type:住宿类型(筛选+列表显示)\n- hotel_star_level:酒店星级(筛选+列表显示)\n- hotel_facility:酒店设施(列表显示)") + @GetMapping("/items") + public Result> listHotels(@ApiParam("住宿查询请求") @Valid HotelQueryRequest query) { + return Result.success(hotelService.listHotels(query)); + } + +- @ApiOperation("所有启用的住宿(不分页,仅ID和名称)") ++ @ApiOperation(value = "所有启用的住宿(不分页,仅ID和名称)", notes = "返回所有已上架(status=1)的住宿简要信息,用于下拉选择框。每项只含hotelId和name字段。适用于房型管理时选择所属住宿、产品编排时绑定住宿资源等场景。") + @GetMapping("/items/all-simple") + public Result>> listAllSimple() { + return Result.success(hotelService.listAllSimple()); + } + +- @ApiOperation("住宿详情") ++ @ApiOperation(value = "住宿详情", notes = "获取住宿完整信息,包含素材URL、标签列表、房型列表等。素材ID会自动解析为OSS访问地址。\n\n**关联字典**:\n- hotel_type:住宿类型(详情显示)\n- hotel_star_level:酒店星级(详情显示)\n- hotel_facility:酒店设施(详情显示)") + @GetMapping("/item/{hotelId}") + public Result getHotel(@ApiParam("住宿ID") @PathVariable Long hotelId) { + return Result.success(hotelService.getHotel(hotelId)); + } + +- @ApiOperation("更新住宿") ++ @ApiOperation(value = "更新住宿", notes = "更新住宿基本信息。更新不会改变当前状态,已上架的住宿修改后仍保持上架状态。\n\n**关联字典**:\n- hotel_type:住宿类型(表单选择)\n- hotel_star_level:酒店星级(表单选择)\n- hotel_facility:酒店设施(表单多选)") + @PutMapping("/item/{hotelId}") + public Result updateHotel( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -63,7 +63,7 @@ public class HotelController { + return Result.success(hotelService.updateHotel(hotelId, request, adminId)); + } + +- @ApiOperation("删除住宿") ++ @ApiOperation(value = "删除住宿", notes = "软删除住宿。仅SUPER_ADMIN或创建者可操作。删除住宿会同时删除其下所有房型和价格日历数据。") + @DeleteMapping("/item/{hotelId}") + public Result deleteHotel( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -74,7 +74,7 @@ public class HotelController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交住宿启用/禁用审批。targetStatus=1申请上架,targetStatus=2申请下架。审批通过后自动更新状态。返回企微审批单号spNo。") + @PostMapping("/item/{hotelId}/submit-approval") + public Result> submitApproval( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -86,7 +86,7 @@ public class HotelController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("启用/禁用切换") ++ @ApiOperation(value = "启用/禁用切换", notes = "直接修改住宿状态(跳过审批),仅限SUPER_ADMIN使用。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{hotelId}/status") + public Result updateStatus( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -97,7 +97,7 @@ public class HotelController { + return Result.success(); + } + +- @ApiOperation("批量启用/禁用") ++ @ApiOperation(value = "批量启用/禁用", notes = "批量修改多个住宿的状态,跳过审批流程。hotelIds为住宿ID列表(字符串格式)。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("住宿状态请求") @Valid @RequestBody HotelStatusRequest request, +@@ -109,7 +109,7 @@ public class HotelController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个住宿及其关联的房型和价格日历。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java +index 3b229f8..02e8708 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java +@@ -27,7 +27,7 @@ public class HotelTagController { + + private final HotelTagService tagService; + +- @ApiOperation("预设标签列表(分页)") ++ @ApiOperation(value = "预设标签列表(分页)", notes = "分页查询住宿标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class HotelTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("所有标签列表") ++ @ApiOperation(value = "所有标签列表", notes = "不分页返回所有标签,用于住宿编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class HotelTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("查找或创建自定义标签") ++ @ApiOperation(value = "查找或创建自定义标签", notes = "按名称查找标签,不存在则自动创建。用于住宿编辑时快速输入新标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class HotelTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", notes = "修改标签名称或颜色,所有关联住宿自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class HotelTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有住宿与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("设置住宿标签") ++ @ApiOperation(value = "设置住宿标签", notes = "全量替换指定住宿的标签列表。") + @PutMapping("/item/{hotelId}/tags") + public Result updateHotelTags( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -87,7 +87,7 @@ public class HotelTagController { + return Result.success(); + } + +- @ApiOperation("批量添加/移除标签") ++ @ApiOperation(value = "批量添加/移除标签", notes = "对多个住宿批量添加/移除标签。增量操作,不影响未指定的标签。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags(@ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { + List hotelIds = request.getHotelIds().stream() +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java +index c758f6e..4b81939 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java +@@ -18,7 +18,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】住宿(Feign调用)") ++@Api(tags = "【内部接口】住宿(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/hotel") + @RequiredArgsConstructor +@@ -27,7 +27,7 @@ public class InternalHotelController { + private final HotelService hotelService; + private final RoomTypeService roomTypeService; + +- @ApiOperation("获取住宿简要信息") ++ @ApiOperation(value = "获取住宿简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个住宿的简要信息,返回ID、名称、住宿类型、状态。不存在时返回错误。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{hotelId}") + public Result> getHotelBrief(@PathVariable Long hotelId) { + Hotel item = hotelService.getHotelEntity(hotelId); +@@ -42,7 +42,7 @@ public class InternalHotelController { + return Result.success(brief); + } + +- @ApiOperation("批量获取住宿简要信息") ++ @ApiOperation(value = "批量获取住宿简要信息", notes = "【仅限内部Feign调用】批量获取住宿简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询行程节点绑定的住宿资源。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getHotelBatch(@RequestParam @Size(max = 500) List hotelIds) { + List> results = hotelIds.stream() +@@ -61,9 +61,9 @@ public class InternalHotelController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配住宿和房型并更新启用/禁用状态。住宿和房型共享同一审批模板,此接口同时尝试匹配两者。由hl-callback-service通过MQ消费后调用。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + hotelService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + // Also try room type (same template, same callback) +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java +index ce4fd47..2a820f5 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; + /** + * C端住宿内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序酒店(Feign调用)") ++@Api(tags = "【内部接口】小程序酒店(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/hotel") + @RequiredArgsConstructor +@@ -22,7 +22,7 @@ public class InternalMpHotelController { + + private final HotelService hotelService; + +- @ApiOperation("C端住宿列表") ++ @ApiOperation(value = "C端住宿列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架住宿,支持分页和筛选。C端用户通过小程序间接访问。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- hotel_star(星级,返回字段starLevel):FIVE=五星, FOUR=四星, THREE=三星, UNRATED=未评级") + @GetMapping("/list") + public Result> listHotels(HotelQueryRequest query) { + // Force status=1 for C-side (only show published hotels) +@@ -30,7 +30,7 @@ public class InternalMpHotelController { + return Result.success(hotelService.listHotels(query)); + } + +- @ApiOperation("C端住宿详情") ++ @ApiOperation(value = "C端住宿详情", notes = "【仅限内部Feign调用】供mp-service获取住宿完整详情,包含房型列表、封面、轮播图、地址等。注意:不限制status,由BFF层校验是否展示。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- hotel_star(星级,返回字段starLevel):FIVE=五星, FOUR=四星, THREE=三星, UNRATED=未评级") + @GetMapping("/{hotelId}") + public Result getHotelDetail(@PathVariable Long hotelId) { + HotelVO vo = hotelService.getHotel(hotelId); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java +index cf6df6c..d883d85 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java +@@ -25,7 +25,7 @@ public class RoomPriceCalendarController { + + private final RoomPriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询房型的每日价格和可售状态。每个房型有独立的价格日历。") + @GetMapping("/room-type/{roomTypeId}/prices") + public Result getPriceCalendar( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -34,7 +34,7 @@ public class RoomPriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(roomTypeId, year, month)); + } + +- @ApiOperation("批量设置价格日历") ++ @ApiOperation(value = "批量设置价格日历", notes = "在指定日期范围内批量设置房型的成本价和可售状态。支持按星期过滤和排除特定日期。") + @PutMapping("/room-type/{roomTypeId}/prices") + public Result batchSetPrices( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -43,7 +43,7 @@ public class RoomPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改日期可售状态") ++ @ApiOperation(value = "批量修改日期可售状态", notes = "批量修改指定日期范围内房型的可售状态,不影响价格。") + @PutMapping("/room-type/{roomTypeId}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -52,7 +52,7 @@ public class RoomPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("删除价格日历") ++ @ApiOperation(value = "删除价格日历", notes = "删除指定日期范围内房型的所有价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/room-type/{roomTypeId}/prices") + public Result deletePrices( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java +index 2048f4c..0d9cf42 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java +@@ -26,7 +26,7 @@ public class RoomTypeController { + + private final RoomTypeService roomTypeService; + +- @ApiOperation("创建房型") ++ @ApiOperation(value = "创建房型", notes = "在指定住宿下创建房型(如标准间、大床房、套房等)。每个房型有独立的价格日历、最大入住人数(maxOccupancy)和基础价格(basePrice)。房型初始状态为草稿(status=0),需独立审批后才能启用。创建后可通过「提交房型启用审批」接口提交企微OA审批。\n\n**关联字典**:\n- room_category:房型分类(表单选择)\n- bed_type:床型(表单选择)\n- window_type:窗户类型(表单选择)\n- bathroom_type:卫浴类型(表单选择)\n- room_facility:房间设施(表单多选)") + @PostMapping("/{hotelId}/room-type") + public Result createRoomType( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -36,19 +36,19 @@ public class RoomTypeController { + return Result.success(roomTypeService.createRoomType(hotelId, request, adminId)); + } + +- @ApiOperation("房型列表") ++ @ApiOperation(value = "房型列表", notes = "获取指定住宿下的所有房型列表(不分页),按sortOrder排序。\n\n**关联字典**:\n- room_category:房型分类(列表/详情显示)\n- bed_type:床型(列表/详情显示)\n- window_type:窗户类型(列表/详情显示)\n- bathroom_type:卫浴类型(列表/详情显示)\n- room_facility:房间设施(列表/详情显示)") + @GetMapping("/{hotelId}/room-types") + public Result> listRoomTypes(@ApiParam("住宿ID") @PathVariable Long hotelId) { + return Result.success(roomTypeService.listRoomTypes(hotelId)); + } + +- @ApiOperation("房型详情") ++ @ApiOperation(value = "房型详情", notes = "获取房型完整信息,包含价格、入住人数、素材等。\n\n**关联字典**:\n- room_category:房型分类(列表/详情显示)\n- bed_type:床型(列表/详情显示)\n- window_type:窗户类型(列表/详情显示)\n- bathroom_type:卫浴类型(列表/详情显示)\n- room_facility:房间设施(列表/详情显示)") + @GetMapping("/room-type/{roomTypeId}") + public Result getRoomType(@ApiParam("房型ID") @PathVariable Long roomTypeId) { + return Result.success(roomTypeService.getRoomType(roomTypeId)); + } + +- @ApiOperation("更新房型") ++ @ApiOperation(value = "更新房型", notes = "更新房型基本信息,不改变当前状态。\n\n**关联字典**:\n- room_category:房型分类(表单选择)\n- bed_type:床型(表单选择)\n- window_type:窗户类型(表单选择)\n- bathroom_type:卫浴类型(表单选择)\n- room_facility:房间设施(表单多选)") + @PutMapping("/room-type/{roomTypeId}") + public Result updateRoomType( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -58,14 +58,14 @@ public class RoomTypeController { + return Result.success(roomTypeService.updateRoomType(roomTypeId, request, adminId)); + } + +- @ApiOperation("删除房型") ++ @ApiOperation(value = "删除房型", notes = "软删除房型及其价格日历数据。") + @DeleteMapping("/room-type/{roomTypeId}") + public Result deleteRoomType(@ApiParam("房型ID") @PathVariable Long roomTypeId) { + roomTypeService.deleteRoomType(roomTypeId); + return Result.success(); + } + +- @ApiOperation("启用/禁用房型") ++ @ApiOperation(value = "启用/禁用房型", notes = "直接修改房型状态(跳过审批)。status=0禁用,status=1启用。禁用后该房型不会出现在C端展示中。") + @PutMapping("/room-type/{roomTypeId}/status") + public Result updateRoomTypeStatus( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -74,7 +74,7 @@ public class RoomTypeController { + return Result.success(); + } + +- @ApiOperation("提交房型启用/禁用审批") ++ @ApiOperation(value = "提交房型启用/禁用审批", notes = "向企微OA提交房型启用/禁用审批。审批流程与住宿共享同一模板。返回审批单号spNo。") + @PostMapping("/room-type/{roomTypeId}/submit-approval") + public Result> submitRoomTypeApproval( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java +index 41d485f..df17f5c 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; + /** + * C端餐厅内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序餐厅(Feign调用)") ++@Api(tags = "【内部接口】小程序餐厅(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/restaurant") + @RequiredArgsConstructor +@@ -22,7 +22,7 @@ public class InternalMpRestaurantController { + + private final RestaurantService restaurantService; + +- @ApiOperation("C端餐厅列表") ++ @ApiOperation(value = "C端餐厅列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架餐厅,支持分页和筛选。C端用户通过小程序间接访问。\n\n**关联字典**:\n- restaurant_category(餐厅分类,返回字段categoryCode):CHINESE=中餐, WESTERN=西餐, BBQ=烧烤, HOTPOT=火锅, LOCAL=当地特色") + @GetMapping("/list") + public Result> listRestaurants(RestaurantQueryRequest query) { + // Force status=1 for C-side (only show published restaurants) +@@ -30,7 +30,7 @@ public class InternalMpRestaurantController { + return Result.success(restaurantService.listRestaurants(query)); + } + +- @ApiOperation("C端餐厅详情") ++ @ApiOperation(value = "C端餐厅详情", notes = "【仅限内部Feign调用】供mp-service获取餐厅完整详情,包含封面、轮播图、标签、地址、富文本介绍等。注意:不限制status,由BFF层校验是否展示。\n\n**关联字典**:\n- restaurant_category(餐厅分类,返回字段categoryCode):CHINESE=中餐, WESTERN=西餐, BBQ=烧烤, HOTPOT=火锅, LOCAL=当地特色") + @GetMapping("/{restaurantId}") + public Result getRestaurantDetail(@PathVariable Long restaurantId) { + RestaurantVO vo = restaurantService.getRestaurant(restaurantId); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java +index ac8e4db..a87aaea 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】餐厅(Feign调用)") ++@Api(tags = "【内部接口】餐厅(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/restaurant") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalRestaurantController { + + private final RestaurantService restaurantService; + +- @ApiOperation("\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f") ++ @ApiOperation(value = "\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f", notes = "\u3010\u4ec5\u9650\u5185\u90e8Feign\u8c03\u7528\u3011\u4f9b\u4ea7\u54c1\u670d\u52a1\u83b7\u53d6\u5355\u4e2a\u9910\u5385\u7684\u7b80\u8981\u4fe1\u606f\uff0c\u8fd4\u56deID\u3001\u540d\u79f0\u3001\u5206\u7c7b\u7f16\u7801\u3001\u57ce\u5e02\u3001\u72b6\u6001\u3002\u4e0d\u5b58\u5728\u65f6\u8fd4\u56de\u9519\u8bef\u3002\n\n**\u5173\u8054\u5b57\u5178**\uff1a\n- restaurant_category\uff08\u9910\u5385\u5206\u7c7b\uff0c\u8fd4\u56de\u5b57\u6bb5categoryCode\uff09\uff1aCHINESE=\u4e2d\u9910, WESTERN=\u897f\u9910, BBQ=\u70e7\u70e4, HOTPOT=\u706b\u9505, LOCAL=\u5f53\u5730\u7279\u8272\n- common_status\uff08\u72b6\u6001\uff0c\u8fd4\u56de\u5b57\u6bb5status\uff09\uff1aACTIVE=\u542f\u7528, INACTIVE=\u505c\u7528") + @GetMapping("/item/{restaurantId}") + public Result> getRestaurantBrief(@PathVariable Long restaurantId) { + Restaurant restaurant = restaurantService.getRestaurantEntity(restaurantId); +@@ -41,7 +41,7 @@ public class InternalRestaurantController { + return Result.success(brief); + } + +- @ApiOperation("\u6279\u91cf\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f") ++ @ApiOperation(value = "\u6279\u91cf\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f", notes = "\u3010\u4ec5\u9650\u5185\u90e8Feign\u8c03\u7528\u3011\u6279\u91cf\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f\uff0c\u6700\u591a500\u4e2aID\u3002\u4e0d\u5b58\u5728\u7684ID\u81ea\u52a8\u8fc7\u6ee4\u3002\u4f9b\u4ea7\u54c1\u670d\u52a1\u6279\u91cf\u67e5\u8be2\u884c\u7a0b\u8282\u70b9\u7ed1\u5b9a\u7684\u9910\u5385\u8d44\u6e90\u3002\n\n**\u5173\u8054\u5b57\u5178**\uff1a\n- restaurant_category\uff08\u9910\u5385\u5206\u7c7b\uff0c\u8fd4\u56de\u5b57\u6bb5categoryCode\uff09\uff1aCHINESE=\u4e2d\u9910, WESTERN=\u897f\u9910, BBQ=\u70e7\u70e4, HOTPOT=\u706b\u9505, LOCAL=\u5f53\u5730\u7279\u8272\n- common_status\uff08\u72b6\u6001\uff0c\u8fd4\u56de\u5b57\u6bb5status\uff09\uff1aACTIVE=\u542f\u7528, INACTIVE=\u505c\u7528") + @GetMapping("/items/batch") + public Result>> getRestaurantsBatch(@RequestParam @Size(max = 500) List restaurantIds) { + List> results = restaurantIds.stream() +@@ -61,9 +61,9 @@ public class InternalRestaurantController { + return Result.success(results); + } + +- @ApiOperation("\u5904\u7406\u5ba1\u6279\u56de\u8c03\u7ed3\u679c") ++ @ApiOperation(value = "\u5904\u7406\u5ba1\u6279\u56de\u8c03\u7ed3\u679c", notes = "\u3010\u4ec5\u9650\u5185\u90e8Feign\u8c03\u7528\u3011\u63a5\u6536\u4f01\u5faeOA\u5ba1\u6279\u56de\u8c03\uff0c\u6309thirdNo\u5339\u914d\u9910\u5385\u5e76\u66f4\u65b0\u542f\u7528/\u7981\u7528\u72b6\u6001\u3002\u7531hl-callback-service\u901a\u8fc7MQ\u6d88\u8d39\u540e\u8c03\u7528\uff0c\u5e42\u7b49\u5904\u7406\u3002\n\n**\u5173\u8054\u5b57\u5178**\uff1a\n- approval_sp_status\uff08\u5ba1\u6279\u72b6\u6001\uff0c\u8bf7\u6c42\u5b57\u6bb5spStatus\uff09") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + restaurantService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java +index eb8164c..7c8961f 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java +@@ -26,7 +26,7 @@ public class RestaurantController { + + private final RestaurantService restaurantService; + +- @ApiOperation("创建餐厅") ++ @ApiOperation(value = "创建餐厅", notes = "新建餐厅资源,初始状态为草稿(status=0)。餐厅没有价格日历,费用通过产品报价中的费用项管理。需走企微审批流程上架。\n\n**关联字典**:\n- restaurant_category:餐厅分类(表单选择)\n- cuisine_type:菜系类型(表单多选)\n- environment_type:环境类型(表单多选)\n- restaurant_facility:餐厅设施(表单多选)\n\n**纯文本字段**:\n- cityName:城市名称(手动输入,如「拉萨」「海拉尔」)") + @PostMapping("/item") + public Result createRestaurant( + @ApiParam("餐厅创建请求") @Valid @RequestBody RestaurantCreateRequest request, +@@ -35,19 +35,19 @@ public class RestaurantController { + return Result.success(restaurantService.createRestaurant(request, adminId)); + } + +- @ApiOperation("餐厅列表") ++ @ApiOperation(value = "餐厅列表", notes = "分页查询餐厅列表,支持按名称、状态、分类、城市等条件筛选。\n\n**关联字典**:\n- restaurant_category:餐厅分类(筛选+列表显示)\n- cuisine_type:菜系类型(列表显示)\n- environment_type:环境类型(列表显示)\n- restaurant_facility:餐厅设施(列表显示)") + @GetMapping("/items") + public Result> listRestaurants(@ApiParam("餐厅查询请求") @Valid RestaurantQueryRequest query) { + return Result.success(restaurantService.listRestaurants(query)); + } + +- @ApiOperation("餐厅详情") ++ @ApiOperation(value = "餐厅详情", notes = "获取餐厅完整信息,包含素材URL、标签、富文本介绍等。\n\n**关联字典**:\n- restaurant_category:餐厅分类(详情显示)\n- cuisine_type:菜系类型(详情显示)\n- environment_type:环境类型(详情显示)\n- restaurant_facility:餐厅设施(详情显示)") + @GetMapping("/item/{restaurantId}") + public Result getRestaurant(@ApiParam("餐厅ID") @PathVariable Long restaurantId) { + return Result.success(restaurantService.getRestaurant(restaurantId)); + } + +- @ApiOperation("更新餐厅") ++ @ApiOperation(value = "更新餐厅", notes = "更新餐厅基本信息,不改变当前状态。\n\n**关联字典**:\n- restaurant_category:餐厅分类(表单选择)\n- cuisine_type:菜系类型(表单多选)\n- environment_type:环境类型(表单多选)\n- restaurant_facility:餐厅设施(表单多选)\n\n**纯文本字段**:\n- cityName:城市名称(手动输入)") + @PutMapping("/item/{restaurantId}") + public Result updateRestaurant( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -57,7 +57,7 @@ public class RestaurantController { + return Result.success(restaurantService.updateRestaurant(restaurantId, request, adminId)); + } + +- @ApiOperation("删除餐厅") ++ @ApiOperation(value = "删除餐厅", notes = "软删除餐厅。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/item/{restaurantId}") + public Result deleteRestaurant( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -68,7 +68,7 @@ public class RestaurantController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{restaurantId}/submit-approval") + public Result> submitApproval( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -80,7 +80,7 @@ public class RestaurantController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("上下架切换") ++ @ApiOperation(value = "上下架切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{restaurantId}/status") + public Result updateStatus( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -91,7 +91,7 @@ public class RestaurantController { + return Result.success(); + } + +- @ApiOperation("批量上下架") ++ @ApiOperation(value = "批量上下架", notes = "批量修改多个餐厅的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("餐厅状态请求") @Valid @RequestBody RestaurantStatusRequest request, +@@ -103,7 +103,7 @@ public class RestaurantController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个餐厅。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java +index 05b1056..7f96d5a 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java +@@ -27,7 +27,7 @@ public class RestaurantTagController { + + private final RestaurantTagService tagService; + +- @ApiOperation("\u83b7\u53d6\u7ba1\u7406\u6807\u7b7e\u5217\u8868\uff08\u5206\u9875\uff09") ++ @ApiOperation(value = "\u83b7\u53d6\u7ba1\u7406\u6807\u7b7e\u5217\u8868\uff08\u5206\u9875\uff09", notes = "\u5206\u9875\u67e5\u8be2\u9910\u5385\u6807\u7b7e\u5e93\uff0c\u652f\u6301\u6309\u5173\u952e\u8bcd\u641c\u7d22\u3002\u5305\u542b\u9884\u8bbe\u6807\u7b7e\u548c\u81ea\u5b9a\u4e49\u6807\u7b7e\u3002") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("\u9875\u7801") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class RestaurantTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("\u83b7\u53d6\u5168\u90e8\u6807\u7b7e") ++ @ApiOperation(value = "\u83b7\u53d6\u5168\u90e8\u6807\u7b7e", notes = "\u4e0d\u5206\u9875\u8fd4\u56de\u6240\u6709\u6807\u7b7e\uff0c\u7528\u4e8e\u9910\u5385\u7f16\u8f91\u65f6\u7684\u6807\u7b7e\u9009\u62e9\u4e0b\u62c9\u3002") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("\u521b\u5efa\u7ba1\u7406\u6807\u7b7e") ++ @ApiOperation(value = "\u521b\u5efa\u7ba1\u7406\u6807\u7b7e", notes = "\u521b\u5efa\u9884\u8bbe\u6807\u7b7e\uff0c\u6807\u7b7e\u540d\u4e0d\u53ef\u91cd\u590d\u3002\u53ef\u6307\u5b9a\u989c\u8272(tagColor)\uff0c\u9ed8\u8ba4#409EFF\u3002") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class RestaurantTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("\u89e3\u6790\u81ea\u5b9a\u4e49\u6807\u7b7e") ++ @ApiOperation(value = "\u89e3\u6790\u81ea\u5b9a\u4e49\u6807\u7b7e", notes = "\u6309\u540d\u79f0\u67e5\u627e\u6216\u81ea\u52a8\u521b\u5efa\u6807\u7b7e\u3002\u7528\u4e8e\u9910\u5385\u7f16\u8f91\u65f6\u5feb\u901f\u8f93\u5165\u65b0\u6807\u7b7e\u3002") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class RestaurantTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("\u7f16\u8f91\u6807\u7b7e") ++ @ApiOperation(value = "\u7f16\u8f91\u6807\u7b7e", notes = "\u4fee\u6539\u6807\u7b7e\u540d\u79f0\u6216\u989c\u8272\uff0c\u6240\u6709\u5173\u8054\u9910\u5385\u81ea\u52a8\u751f\u6548\u3002") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class RestaurantTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("\u5220\u9664\u6807\u7b7e") ++ @ApiOperation(value = "\u5220\u9664\u6807\u7b7e", notes = "\u5220\u9664\u6807\u7b7e\u5e76\u89e3\u9664\u6240\u6709\u9910\u5385\u4e0e\u8be5\u6807\u7b7e\u7684\u5173\u8054\u3002") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("\u66f4\u65b0\u9910\u5385\u6807\u7b7e") ++ @ApiOperation(value = "\u66f4\u65b0\u9910\u5385\u6807\u7b7e", notes = "\u5168\u91cf\u66ff\u6362\u6307\u5b9a\u9910\u5385\u7684\u6807\u7b7e\u5217\u8868\u3002\u4f20\u5165tagIds\u4e3a\u6700\u7ec8\u5173\u8054\u7684\u6807\u7b7eID\u5217\u8868\uff0c\u4e3a\u7a7a\u5219\u6e05\u9664\u6240\u6709\u6807\u7b7e\u3002") + @PutMapping("/item/{restaurantId}/tags") + public Result updateRestaurantTags( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -87,7 +87,7 @@ public class RestaurantTagController { + return Result.success(); + } + +- @ApiOperation("\u6279\u91cf\u6253\u6807\u7b7e") ++ @ApiOperation(value = "\u6279\u91cf\u6253\u6807\u7b7e", notes = "\u5bf9\u591a\u4e2a\u9910\u5385\u6279\u91cf\u6dfb\u52a0/\u79fb\u9664\u6807\u7b7e\u3002\u589e\u91cf\u64cd\u4f5c\uff0c\u4e0d\u5f71\u54cd\u672a\u6307\u5b9a\u7684\u6807\u7b7e\u3002") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java +index dbe9f19..a28ef38 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java +@@ -17,7 +17,7 @@ import java.util.List; + /** + * C端景区内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序景区(Feign调用)") ++@Api(tags = "【内部接口】小程序景区(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/scenic") + @RequiredArgsConstructor +@@ -25,21 +25,21 @@ public class InternalMpScenicController { + + private final ScenicSpotService scenicSpotService; + +- @ApiOperation("C端景区列表") ++ @ApiOperation(value = "C端景区列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架景区,支持分页、城市筛选和关键词搜索。C端用户通过小程序间接访问。\n\ncityName为纯文本筛选字段,非字典。") + @GetMapping("/list") + public Result> listScenic(ScenicSpotQueryRequest query) { + query.setStatus(1); + return Result.success(scenicSpotService.listSpots(query)); + } + +- @ApiOperation("C端景区详情") ++ @ApiOperation(value = "C端景区详情", notes = "【仅限内部Feign调用】供mp-service获取景区完整详情,包含封面、轮播图、标签、季节内容、富文本介绍、坐标等。注意:不限制status,由BFF层校验是否展示。") + @GetMapping("/{scenicId}") + public Result getScenicDetail(@PathVariable Long scenicId) { + ScenicSpotVO vo = scenicSpotService.getSpot(scenicId); + return Result.success(vo); + } + +- @ApiOperation("C端附近景区") ++ @ApiOperation(value = "C端附近景区", notes = "【仅限内部Feign调用】根据指定景区的坐标查询附近的景区列表。radius为搜索半径(km,默认50),limit为最大返回数(默认10)。按距离排序,返回名称、封面、距离等信息。") + @GetMapping("/{scenicId}/nearby") + public Result> getNearbyScenic( + @PathVariable Long scenicId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java +index a902ee1..9f47695 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java +@@ -22,7 +22,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】景区(Feign调用)") ++@Api(tags = "【内部接口】景区(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/scenic") + @RequiredArgsConstructor +@@ -31,7 +31,7 @@ public class InternalScenicController { + private final ScenicSpotService spotService; + private final ScenicPriceCalendarService priceService; + +- @ApiOperation("获取景区简要信息") ++ @ApiOperation(value = "获取景区简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个景区的简要信息,返回ID、名称、荣誉称号、城市、状态。不存在时返回错误。\n\n**关联字典**:\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/spot/{scenicId}") + public Result> getSpotBrief(@PathVariable Long scenicId) { + ScenicSpot spot = spotService.getSpotEntity(scenicId); +@@ -47,7 +47,7 @@ public class InternalScenicController { + return Result.success(brief); + } + +- @ApiOperation("批量获取景区简要信息") ++ @ApiOperation(value = "批量获取景区简要信息", notes = "【仅限内部Feign调用】批量获取景区简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询行程节点绑定的景区资源。\n\n**关联字典**:\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/spots/batch") + public Result>> getSpotsBatch(@RequestParam @Size(max = 500) List scenicIds) { + List> results = scenicIds.stream() +@@ -67,7 +67,7 @@ public class InternalScenicController { + return Result.success(results); + } + +- @ApiOperation("查询某日价格") ++ @ApiOperation(value = "查询某日价格", notes = "【仅限内部Feign调用】查询景区指定日期的价格日历信息,包含成本价、售价、库存、状态。date格式为yyyy-MM-dd。供产品服务报价计算和库存校验使用。") + @GetMapping("/spot/{scenicId}/price/{date}") + public Result getPriceForDate( + @PathVariable Long scenicId, +@@ -76,7 +76,7 @@ public class InternalScenicController { + return Result.success(price); + } + +- @ApiOperation("判断某日是否可售") ++ @ApiOperation(value = "判断某日是否可售", notes = "【仅限内部Feign调用】判断景区指定日期是否可售(价格日历存在且状态为启用且库存>0)。供订单服务下单前校验使用。") + @GetMapping("/spot/{scenicId}/available/{date}") + public Result isAvailable( + @PathVariable Long scenicId, +@@ -84,7 +84,7 @@ public class InternalScenicController { + return Result.success(priceService.isAvailable(scenicId, LocalDate.parse(date))); + } + +- @ApiOperation("扣减库存") ++ @ApiOperation(value = "扣减库存", notes = "【仅限内部Feign调用】扣减景区指定日期的库存数量。下单成功时由订单服务调用。库存不足时返回false。使用乐观锁防止超卖。") + @PutMapping("/spot/{scenicId}/stock/deduct") + public Result deductStock( + @PathVariable Long scenicId, +@@ -94,7 +94,7 @@ public class InternalScenicController { + return Result.success(success); + } + +- @ApiOperation("恢复库存") ++ @ApiOperation(value = "恢复库存", notes = "【仅限内部Feign调用】恢复景区指定日期的库存数量。订单取消或退款时由订单服务调用,将之前扣减的库存加回。") + @PutMapping("/spot/{scenicId}/stock/restore") + public Result restoreStock( + @PathVariable Long scenicId, +@@ -104,9 +104,9 @@ public class InternalScenicController { + return Result.success(); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配景区并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + spotService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java +index 8e2b1cb..62d7de0 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java +@@ -25,7 +25,7 @@ public class ScenicPriceCalendarController { + + private final ScenicPriceCalendarService priceService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询景区的每日价格和可售状态。返回指定年月中所有已设置价格的日期,未设置的日期不返回。用于前端日历组件渲染。") + @GetMapping("/spot/{scenicId}/prices") + public Result getPriceCalendar( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -34,7 +34,7 @@ public class ScenicPriceCalendarController { + return Result.success(priceService.getPriceCalendar(scenicId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置成本价、库存和可售状态。支持weekdayOnly/weekendOnly/selectedWeekdays过滤特定星期,支持excludeDates排除特定日期。已有价格的日期会被覆盖更新。") + @PutMapping("/spot/{scenicId}/prices") + public Result batchSetPrices( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -43,7 +43,7 @@ public class ScenicPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改可售状态") ++ @ApiOperation(value = "批量修改可售状态", notes = "批量修改指定日期范围内的可售状态,不影响价格和库存。status=0不可售,status=1可售。用于临时关闭/开放某些日期的售卖。") + @PutMapping("/spot/{scenicId}/prices/status") + public Result batchUpdateStatus( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -52,7 +52,7 @@ public class ScenicPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量清除价格") ++ @ApiOperation(value = "批量清除价格", notes = "删除指定日期范围内的所有价格记录。删除后该日期范围将显示为未设置状态。日期格式:yyyy-MM-dd。") + @DeleteMapping("/spot/{scenicId}/prices") + public Result deletePrices( + @ApiParam("景区ID") @PathVariable Long scenicId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java +index 8933ec2..ab7ad78 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java +@@ -22,13 +22,13 @@ public class ScenicSeasonController { + + private final ScenicSeasonService seasonService; + +- @ApiOperation("获取景区全部季节内容") ++ @ApiOperation(value = "获取景区全部季节内容", notes = "返回景区的所有季节内容列表(春/夏/秋/冬)。季节内容是景区独有功能,其他资源类型没有此概念。每个季节可设置独立的封面、轮播图、亮点描述和游玩攻略。") + @GetMapping("/spot/{scenicId}/seasons") + public Result> getSeasons(@ApiParam("景区ID") @PathVariable Long scenicId) { + return Result.success(seasonService.getSeasons(scenicId)); + } + +- @ApiOperation("保存/更新季节内容") ++ @ApiOperation(value = "保存/更新季节内容", notes = "创建或更新指定景区的季节内容。seasonType为季节标识(如spring/summer/autumn/winter)。如果该季节已存在则更新,不存在则创建。支持设置季节别名(如「樱花季」)、月份范围、独立封面和轮播图。") + @PutMapping("/spot/{scenicId}/season/{seasonType}") + public Result saveSeason( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -39,7 +39,7 @@ public class ScenicSeasonController { + return Result.success(seasonService.saveSeason(scenicId, seasonType, request, adminId)); + } + +- @ApiOperation("删除季节内容") ++ @ApiOperation(value = "删除季节内容", notes = "删除指定景区的某个季节内容,同时清理关联的素材引用。") + @DeleteMapping("/spot/{scenicId}/season/{seasonType}") + public Result deleteSeason( + @ApiParam("景区ID") @PathVariable Long scenicId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java +index b8aff01..c2da355 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java +@@ -26,7 +26,7 @@ public class ScenicSpotController { + + private final ScenicSpotService spotService; + +- @ApiOperation("创建景区") ++ @ApiOperation(value = "创建景区", notes = "新建一个景区资源,初始状态为草稿(status=0)。创建后需通过「提交启用审批」接口走企微OA审批流程才能上架。支持富文本字段(featureIntro/detailContent等),素材ID从素材库获取。\n\n**关联字典**:\n- scenic_facility:景区设施(表单多选)\n- scenic_honor:景区荣誉(表单多选)") + @PostMapping("/spot") + public Result createSpot( + @ApiParam("景区创建请求") @Valid @RequestBody ScenicSpotCreateRequest request, +@@ -35,19 +35,19 @@ public class ScenicSpotController { + return Result.success(spotService.createSpot(request, adminId)); + } + +- @ApiOperation("景区列表") ++ @ApiOperation(value = "景区列表", notes = "分页查询景区列表,支持按名称关键词、状态(0草稿/1上架/2下架)、城市等条件筛选。返回列表摘要信息(不含富文本详情),按sortOrder倒序+创建时间倒序排列。\n\n**关联字典**:\n- scenic_facility:景区设施(列表显示)\n- scenic_honor:景区荣誉(列表显示)") + @GetMapping("/spots") + public Result> listSpots(@ApiParam("景区查询请求") @Valid ScenicSpotQueryRequest query) { + return Result.success(spotService.listSpots(query)); + } + +- @ApiOperation("景区详情") ++ @ApiOperation(value = "景区详情", notes = "获取景区完整信息,包含富文本内容、素材URL、标签列表、季节内容等。素材ID会自动解析为OSS访问地址。\n\n**关联字典**:\n- scenic_facility:景区设施(详情显示)\n- scenic_honor:景区荣誉(详情显示)") + @GetMapping("/spot/{scenicId}") + public Result getSpot(@ApiParam("景区ID") @PathVariable Long scenicId) { + return Result.success(spotService.getSpot(scenicId)); + } + +- @ApiOperation("更新景区") ++ @ApiOperation(value = "更新景区", notes = "更新景区基本信息和富文本内容。更新不会改变当前状态。如果景区已上架,修改后仍保持上架状态,无需重新审批。\n\n**关联字典**:\n- scenic_facility:景区设施(表单多选)\n- scenic_honor:景区荣誉(表单多选)") + @PutMapping("/spot/{scenicId}") + public Result updateSpot( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -57,7 +57,7 @@ public class ScenicSpotController { + return Result.success(spotService.updateSpot(scenicId, request, adminId)); + } + +- @ApiOperation("删除景区") ++ @ApiOperation(value = "删除景区", notes = "软删除景区(设置deleted_at)。仅SUPER_ADMIN角色或创建者本人可删除。已上架的景区需先下架再删除。删除后会同时清理关联的素材引用。") + @DeleteMapping("/spot/{scenicId}") + public Result deleteSpot( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -68,7 +68,7 @@ public class ScenicSpotController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批申请。targetStatus=1表示申请上架,targetStatus=2表示申请下架。提交后景区进入PENDING_APPROVAL状态,企微审批通过/拒绝后通过回调自动更新状态。返回企微审批单号spNo。同一景区不可重复提交未完成的审批。") + @PostMapping("/spot/{scenicId}/submit-approval") + public Result> submitApproval( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -80,7 +80,7 @@ public class ScenicSpotController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("上下架切换") ++ @ApiOperation(value = "上下架切换", notes = "直接修改景区状态(跳过审批流程),仅限SUPER_ADMIN使用。普通管理员应使用「提交启用/禁用审批」接口。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/spot/{scenicId}/status") + public Result updateStatus( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -91,7 +91,7 @@ public class ScenicSpotController { + return Result.success(); + } + +- @ApiOperation("批量上下架") ++ @ApiOperation(value = "批量上下架", notes = "批量修改多个景区的状态。scenicIds为景区ID列表(字符串格式),status为目标状态。跳过审批流程,适用于批量管理场景。") + @PutMapping("/spots/batch/status") + public Result batchUpdateStatus( + @ApiParam("景区状态请求") @Valid @RequestBody ScenicStatusRequest request, +@@ -103,7 +103,7 @@ public class ScenicSpotController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个景区。权限校验同单个删除:仅SUPER_ADMIN或创建者可操作。部分失败不影响其他景区的删除。") + @DeleteMapping("/spots/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java +index eda0e91..1410edc 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java +@@ -27,7 +27,7 @@ public class ScenicTagController { + + private final ScenicTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询景区标签库中的所有标签,支持按关键词搜索。标签分为预设标签(管理员创建)和自定义标签(adhoc接口创建),此接口返回全部类型。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class ScenicTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于景区编辑时的标签选择下拉列表。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。可指定颜色(tagColor),默认为#409EFF。预设标签在标签管理页面展示和维护。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class ScenicTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "输入标签名称,如果已存在则直接返回,不存在则自动创建。用于景区编辑时快速输入新标签,避免先到标签管理页面创建。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class ScenicTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色。修改后所有关联此标签的景区会自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class ScenicTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并自动解除所有景区与该标签的关联关系。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新景区标签") ++ @ApiOperation(value = "更新景区标签", notes = "全量替换指定景区的标签列表。传入tagIds为该景区最终要关联的标签ID列表,为空则清除所有标签。") + @PutMapping("/spot/{scenicId}/tags") + public Result updateScenicTags( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -87,7 +87,7 @@ public class ScenicTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个景区批量添加或移除标签。addTagIds为要添加的标签,removeTagIds为要移除的标签,两者可同时使用。增量操作,不影响未指定的标签。") + @PutMapping("/spots/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java +index 95c02bf..4125c0d 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】增值服务(Feign调用)") ++@Api(tags = "【内部接口】增值服务(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/service") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalServiceController { + + private final ServiceItemService serviceItemService; + +- @ApiOperation("获取服务简要信息") ++ @ApiOperation(value = "获取服务简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个增值服务的简要信息,返回ID、名称、分类编码、计费类型、是否收费、状态。不存在时返回错误。\n\n**关联字典**:\n- service_unit(计费单位,返回字段billingType):PER_PERSON=元/人, PER_TIME=元/次, PER_DAY=元/天, PER_VEHICLE=元/台, FIXED=固定金额\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{serviceId}") + public Result> getServiceBrief(@PathVariable Long serviceId) { + ServiceItem item = serviceItemService.getServiceItemEntity(serviceId); +@@ -42,7 +42,7 @@ public class InternalServiceController { + return Result.success(brief); + } + +- @ApiOperation("批量获取服务简要信息") ++ @ApiOperation(value = "批量获取服务简要信息", notes = "【仅限内部Feign调用】批量获取增值服务简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询产品关联的服务项。\n\n**关联字典**:\n- service_unit(计费单位,返回字段billingType):PER_PERSON=元/人, PER_TIME=元/次, PER_DAY=元/天, PER_VEHICLE=元/台, FIXED=固定金额\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getServiceBatch(@RequestParam @Size(max = 500) List serviceIds) { + List> results = serviceIds.stream() +@@ -63,9 +63,9 @@ public class InternalServiceController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配增值服务并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + serviceItemService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java +index 6750979..52e1bb9 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java +@@ -26,7 +26,7 @@ public class ServiceItemController { + + private final ServiceItemService serviceItemService; + +- @ApiOperation("创建服务") ++ @ApiOperation(value = "创建增值服务", notes = "新建增值服务项目(如保险、签证代办、接送机等),初始状态为草稿(status=0)。支持免费(isPaid=false)和付费两种模式,付费服务有独立的价格日历。需走企微审批上架。\n\n**关联字典**:\n- service_category:服务分类(表单选择)\n- billing_type_service:服务计费方式(表单选择)\n- service_unit:服务计量单位(表单选择)") + @PostMapping("/item") + public Result createServiceItem( + @ApiParam("服务创建请求") @Valid @RequestBody ServiceCreateRequest request, +@@ -35,19 +35,19 @@ public class ServiceItemController { + return Result.success(serviceItemService.createServiceItem(request, adminId)); + } + +- @ApiOperation("服务列表") ++ @ApiOperation(value = "增值服务列表", notes = "分页查询增值服务列表,支持按名称、状态、分类等条件筛选。\n\n**关联字典**:\n- service_category:服务分类(筛选+列表显示)\n- billing_type_service:服务计费方式(列表显示)\n- service_unit:服务计量单位(列表显示)") + @GetMapping("/items") + public Result> listServiceItems(@ApiParam("服务查询请求") @Valid ServiceQueryRequest query) { + return Result.success(serviceItemService.listServiceItems(query)); + } + +- @ApiOperation("服务详情") ++ @ApiOperation(value = "增值服务详情", notes = "获取增值服务完整信息,包含素材URL、标签、计费方式等。\n\n**关联字典**:\n- service_category:服务分类(详情显示)\n- billing_type_service:服务计费方式(详情显示)\n- service_unit:服务计量单位(详情显示)") + @GetMapping("/item/{serviceId}") + public Result getServiceItem(@ApiParam("服务ID") @PathVariable Long serviceId) { + return Result.success(serviceItemService.getServiceItem(serviceId)); + } + +- @ApiOperation("更新服务") ++ @ApiOperation(value = "更新增值服务", notes = "更新增值服务基本信息,不改变当前状态。\n\n**关联字典**:\n- service_category:服务分类(表单选择)\n- billing_type_service:服务计费方式(表单选择)\n- service_unit:服务计量单位(表单选择)") + @PutMapping("/item/{serviceId}") + public Result updateServiceItem( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -57,7 +57,7 @@ public class ServiceItemController { + return Result.success(serviceItemService.updateServiceItem(serviceId, request, adminId)); + } + +- @ApiOperation("删除服务") ++ @ApiOperation(value = "删除增值服务", notes = "软删除增值服务。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/item/{serviceId}") + public Result deleteServiceItem( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -68,7 +68,7 @@ public class ServiceItemController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{serviceId}/submit-approval") + public Result> submitApproval( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -80,7 +80,7 @@ public class ServiceItemController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("启用/禁用切换") ++ @ApiOperation(value = "启用/禁用切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{serviceId}/status") + public Result updateStatus( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -91,7 +91,7 @@ public class ServiceItemController { + return Result.success(); + } + +- @ApiOperation("批量启用/禁用") ++ @ApiOperation(value = "批量启用/禁用", notes = "批量修改多个增值服务的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("服务状态请求") @Valid @RequestBody ServiceStatusRequest request, +@@ -103,7 +103,7 @@ public class ServiceItemController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个增值服务。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java +index e96654d..a2f52d3 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java +@@ -25,7 +25,7 @@ public class ServicePriceCalendarController { + + private final ServicePriceCalendarService priceService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询增值服务的每日价格和可售状态。仅付费服务(isPaid=true)需要设置价格日历。") + @GetMapping("/item/{serviceId}/prices") + public Result getPriceCalendar( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -34,7 +34,7 @@ public class ServicePriceCalendarController { + return Result.success(priceService.getPriceCalendar(serviceId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置服务的成本价和可售状态。") + @PutMapping("/item/{serviceId}/prices") + public Result batchSetPrices( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -43,7 +43,7 @@ public class ServicePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改可售状态") ++ @ApiOperation(value = "批量修改可售状态", notes = "批量修改日期范围内的可售状态,不影响价格。") + @PutMapping("/item/{serviceId}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -52,7 +52,7 @@ public class ServicePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量清除价格") ++ @ApiOperation(value = "批量清除价格", notes = "删除指定日期范围内的价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/item/{serviceId}/prices") + public Result deletePrices( + @ApiParam("服务ID") @PathVariable Long serviceId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java +index cf3865a..5dca328 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java +@@ -27,7 +27,7 @@ public class ServiceTagController { + + private final ServiceTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询增值服务标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class ServiceTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于服务编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class ServiceTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class ServiceTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色,所有关联服务自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class ServiceTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有服务与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新服务标签") ++ @ApiOperation(value = "更新服务标签", notes = "全量替换指定服务的标签列表。") + @PutMapping("/item/{serviceId}/tags") + public Result updateServiceTags( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -87,7 +87,7 @@ public class ServiceTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个服务批量添加/移除标签。增量操作。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java +index 7c8bb51..ce700da 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java +@@ -19,7 +19,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】服务人员(Feign调用)") ++@Api(tags = "【内部接口】服务人员(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/staff") + @RequiredArgsConstructor +@@ -28,7 +28,7 @@ public class InternalStaffController { + private final StaffService staffService; + private final StaffMapper staffMapper; + +- @ApiOperation("获取人员简要信息") ++ @ApiOperation(value = "获取人员简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个服务人员的简要信息,返回ID、姓名、人员类型、手机号、状态。不存在时返回错误。\n\n**关联字典**:\n- staff_type(人员类型,返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/{staffId}") + public Result> getStaffBrief(@PathVariable Long staffId) { + Staff staff = staffService.getStaffEntity(staffId); +@@ -44,7 +44,7 @@ public class InternalStaffController { + return Result.success(brief); + } + +- @ApiOperation("批量获取人员简要信息") ++ @ApiOperation(value = "批量获取人员简要信息", notes = "【仅限内部Feign调用】批量获取服务人员简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询团批关联的服务人员。\n\n**关联字典**:\n- staff_type(人员类型,返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/batch") + public Result>> getStaffBatch(@RequestParam @Size(max = 500) List staffIds) { + List> results = staffIds.stream() +@@ -64,7 +64,7 @@ public class InternalStaffController { + return Result.success(results); + } + +- @ApiOperation("按人员类型查询") ++ @ApiOperation(value = "按人员类型查询", notes = "【仅限内部Feign调用】按staffType查询第一个匹配的服务人员。staffType如:GUIDE(导游)、DRIVER(司机)、PHOTOGRAPHER(摄影师)等。未找到时返回null。\n\n**关联字典**:\n- staff_type(人员类型,请求参数+返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/by-type/{staffType}") + public Result> getStaffByType(@PathVariable String staffType) { + Staff staff = staffService.getStaffByType(staffType); +@@ -80,9 +80,9 @@ public class InternalStaffController { + return Result.success(brief); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配服务人员并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + staffService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +@@ -91,7 +91,7 @@ public class InternalStaffController { + /** + * Batch get staff basic info by comma-separated IDs (for product-service batch staff snapshot). + */ +- @ApiOperation("批量获取人员基本信息(逗号分隔ID)") ++ @ApiOperation(value = "批量获取人员基本信息(逗号分隔ID)", notes = "【仅限内部Feign调用】通过逗号分隔的ID字符串批量获取人员基本信息(含staffId、name、phone、staffType、coverMaterialId)。供产品服务团批人员快照使用。与/batch接口不同,此接口接收逗号分隔字符串而非数组。\n\n**关联字典**:\n- staff_type(人员类型,返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师") + @GetMapping("/batch-basic") + public Result>> batchGetStaffBasic(@RequestParam String staffIds) { + List ids = Arrays.stream(staffIds.split(",")) +@@ -122,7 +122,7 @@ public class InternalStaffController { + * List available staff (status=1), optionally filter by staffType. + * Used by admin batch staff selection dropdown. + */ +- @ApiOperation("列出可用人员(用于下拉选择)") ++ @ApiOperation(value = "列出可用人员(用于下拉选择)", notes = "【仅限内部Feign调用】列出所有status=1的可用服务人员,可按staffType筛选。按sortOrder和staffId排序。供管理后台团批分配人员的下拉选择框使用。\n\n**关联字典**:\n- staff_type(人员类型,请求参数+返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师") + @GetMapping("/list-available") + public Result>> listAvailableStaff( + @RequestParam(required = false) String staffType) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java +index f90638f..be01710 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java +@@ -24,7 +24,7 @@ public class StaffController { + + private final StaffService staffService; + +- @ApiOperation("创建服务人员") ++ @ApiOperation(value = "创建服务人员", notes = "新建服务人员(导游/领队/摄影师/助理等)。人员类型(staffType)决定了其在价格日历中的归类。需走企微审批上架后才能被产品引用。\n\n**关联字典**:\n- staff_type:人员类型(表单选择)\n- guide_level:导游等级(表单选择)\n- driver_license_type:驾照类型(表单选择)\n- language:语言能力(表单多选)\n- guide_specialty:导游专长(表单多选)\n- guide_service_area:服务区域(表单多选)") + @PostMapping + public Result createStaff(@ApiParam("服务人员创建请求") @Valid @RequestBody StaffCreateRequest request, + HttpServletRequest httpRequest) { +@@ -32,19 +32,19 @@ public class StaffController { + return Result.success(staffService.createStaff(request, adminId)); + } + +- @ApiOperation("服务人员列表") ++ @ApiOperation(value = "服务人员列表", notes = "分页查询服务人员列表,支持按姓名、状态、人员类型等条件筛选。\n\n**关联字典**:\n- staff_type:人员类型(筛选+列表显示)\n- guide_level:导游等级(列表显示)\n- driver_license_type:驾照类型(列表显示)\n- language:语言能力(列表显示)\n- guide_specialty:导游专长(列表显示)\n- guide_service_area:服务区域(列表显示)") + @GetMapping("/list") + public Result> listStaff(@ApiParam("服务人员查询请求") @Valid StaffQueryRequest query) { + return Result.success(staffService.listStaff(query)); + } + +- @ApiOperation("服务人员详情") ++ @ApiOperation(value = "服务人员详情", notes = "获取服务人员完整信息,包含素材URL、标签、技能描述等。\n\n**关联字典**:\n- staff_type:人员类型(详情显示)\n- guide_level:导游等级(详情显示)\n- driver_license_type:驾照类型(详情显示)\n- language:语言能力(详情显示)\n- guide_specialty:导游专长(详情显示)\n- guide_service_area:服务区域(详情显示)") + @GetMapping("/{staffId}") + public Result getStaff(@ApiParam("人员ID") @PathVariable Long staffId) { + return Result.success(staffService.getStaff(staffId)); + } + +- @ApiOperation("更新服务人员") ++ @ApiOperation(value = "更新服务人员", notes = "更新服务人员基本信息,不改变当前状态。\n\n**关联字典**:\n- staff_type:人员类型(表单选择)\n- guide_level:导游等级(表单选择)\n- driver_license_type:驾照类型(表单选择)\n- language:语言能力(表单多选)\n- guide_specialty:导游专长(表单多选)\n- guide_service_area:服务区域(表单多选)") + @PutMapping("/{staffId}") + public Result updateStaff(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("服务人员更新请求") @Valid @RequestBody StaffUpdateRequest request, +@@ -53,7 +53,7 @@ public class StaffController { + return Result.success(staffService.updateStaff(staffId, request, adminId)); + } + +- @ApiOperation("删除服务人员") ++ @ApiOperation(value = "删除服务人员", notes = "软删除服务人员。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/{staffId}") + public Result deleteStaff(@ApiParam("人员ID") @PathVariable Long staffId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -62,7 +62,7 @@ public class StaffController { + return Result.success(); + } + +- @ApiOperation("提交审批") ++ @ApiOperation(value = "提交审批", notes = "向企微OA提交人员启用/禁用审批。targetStatus=1申请启用,targetStatus=2申请禁用。返回审批单号spNo。") + @PostMapping("/{staffId}/submit-approval") + public Result> submitApproval(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("审批提交请求体") @Valid @RequestBody ApprovalSubmitRequest request, +@@ -72,7 +72,7 @@ public class StaffController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("更新状态") ++ @ApiOperation(value = "更新状态", notes = "直接修改人员状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=启用,2=禁用。") + @PutMapping("/{staffId}/status") + public Result updateStatus(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("状态请求体") @Valid @RequestBody StaffStatusRequest request, +@@ -82,14 +82,14 @@ public class StaffController { + return Result.success(); + } + +- @ApiOperation("批量更新状态") ++ @ApiOperation(value = "批量更新状态", notes = "批量修改多个服务人员的状态,跳过审批流程。") + @PutMapping("/batch/status") + public Result batchUpdateStatus(@ApiParam("批量状态请求体") @Valid @RequestBody StaffStatusRequest request) { + staffService.batchUpdateStatus(request.getStaffIds(), request.getStatus()); + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个服务人员。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/batch") + public Result batchDelete(@ApiParam("批量删除请求体") @Valid @RequestBody StaffBatchDeleteRequest request, + HttpServletRequest httpRequest) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java +index 2993bef..a762de1 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java +@@ -27,7 +27,7 @@ public class StaffPriceCalendarController { + + private final StaffPriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历(按人员类型)") ++ @ApiOperation(value = "查询价格日历(按人员类型)", notes = "按月查询指定人员类型的每日服务费用和可调度状态。注意:价格日历按人员类型维度管理,非按个人维度。同一类型的所有人员共享同一套价格。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @GetMapping("/type/{staffType}/prices") + public Result getPriceCalendar( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +@@ -36,7 +36,7 @@ public class StaffPriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(staffType, year, month)); + } + +- @ApiOperation("批量设置价格(按人员类型)") ++ @ApiOperation(value = "批量设置价格(按人员类型)", notes = "在指定日期范围内批量设置该类型人员的服务成本价和可调度状态。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @PutMapping("/type/{staffType}/prices") + public Result batchSetPrices( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +@@ -45,7 +45,7 @@ public class StaffPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改调度状态(按人员类型)") ++ @ApiOperation(value = "批量修改调度状态(按人员类型)", notes = "批量修改日期范围内的可调度状态,不影响价格。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @PutMapping("/type/{staffType}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +@@ -54,7 +54,7 @@ public class StaffPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("清除价格日历(按人员类型)") ++ @ApiOperation(value = "清除价格日历(按人员类型)", notes = "删除指定日期范围内该类型人员的价格记录。日期格式:yyyy-MM-dd。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @DeleteMapping("/type/{staffType}/prices") + public Result deletePrices( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java +index beceb5f..ff68d2c 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java +@@ -26,7 +26,7 @@ public class StaffTagController { + + private final StaffTagService tagService; + +- @ApiOperation("预设标签列表(分页)") ++ @ApiOperation(value = "预设标签列表(分页)", notes = "分页查询服务人员标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,13 +35,13 @@ public class StaffTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("全部标签列表") ++ @ApiOperation(value = "全部标签列表", notes = "不分页返回所有标签,用于人员编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag(@ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -49,7 +49,7 @@ public class StaffTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag(@ApiParam("标签名称请求体") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -57,21 +57,21 @@ public class StaffTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", notes = "修改标签名称或颜色。") + @PutMapping("/tag/{tagId}") + public Result updateTag(@ApiParam("标签ID") @PathVariable Long tagId, + @ApiParam("标签更新请求") @Valid @RequestBody TagUpdateRequest request) { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有人员与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("设置人员标签") ++ @ApiOperation(value = "设置人员标签", notes = "全量替换指定人员的标签列表。") + @PutMapping("/{staffId}/tags") + public Result updateStaffTags(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("标签ID列表请求") @Valid @RequestBody StaffTagUpdateRequest request) { +@@ -79,7 +79,7 @@ public class StaffTagController { + return Result.success(); + } + +- @ApiOperation("批量添加/移除标签") ++ @ApiOperation(value = "批量添加/移除标签", notes = "对多个人员批量添加/移除标签。增量操作。") + @PutMapping("/batch/tags") + public Result batchUpdateTags(@ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { + tagService.batchUpdateTags(request.getStaffIds(), request.getAddTagIds(), request.getRemoveTagIds()); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java +index 5467d19..e827b51 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】备品(Feign调用)") ++@Api(tags = "【内部接口】备品(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/supplies") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalSuppliesController { + + private final SuppliesService suppliesService; + +- @ApiOperation("获取备品简要信息") ++ @ApiOperation(value = "获取备品简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个备品的简要信息,返回ID、名称、分类编码、计费类型、状态。不存在时返回错误。\n\n**关联字典**:\n- supplies_category(备品分类,返回字段categoryCode):CAMPING=露营, CLOTHING=服装, EQUIPMENT=装备, SAFETY=安全\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{suppliesId}") + public Result> getSuppliesBrief(@PathVariable Long suppliesId) { + SuppliesItem item = suppliesService.getSuppliesEntity(suppliesId); +@@ -41,7 +41,7 @@ public class InternalSuppliesController { + return Result.success(brief); + } + +- @ApiOperation("批量获取备品简要信息") ++ @ApiOperation(value = "批量获取备品简要信息", notes = "【仅限内部Feign调用】批量获取备品简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询产品关联的备品资源。\n\n**关联字典**:\n- supplies_category(备品分类,返回字段categoryCode):CAMPING=露营, CLOTHING=服装, EQUIPMENT=装备, SAFETY=安全\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getSuppliesBatch(@RequestParam @Size(max = 500) List suppliesIds) { + List> results = suppliesIds.stream() +@@ -61,9 +61,9 @@ public class InternalSuppliesController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配备品并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + suppliesService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java +index 435f28b..964e6fc 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java +@@ -26,7 +26,7 @@ public class SuppliesController { + + private final SuppliesService suppliesService; + +- @ApiOperation("创建备品") ++ @ApiOperation(value = "创建备品", notes = "新建备品资源(帐篷、睡袋、炊具等物资),初始状态为草稿(status=0)。需走企微审批上架。支持按件(PER_ITEM)和按人(PER_PERSON)计费。\n\n**关联字典**:\n- supplies_category:备品分类(表单选择)\n- billing_type:计费方式(表单选择)") + @PostMapping("/item") + public Result createSupplies( + @ApiParam("备品创建请求") @Valid @RequestBody SuppliesCreateRequest request, +@@ -35,19 +35,19 @@ public class SuppliesController { + return Result.success(suppliesService.createSupplies(request, adminId)); + } + +- @ApiOperation("备品列表") ++ @ApiOperation(value = "备品列表", notes = "分页查询备品列表,支持按名称、状态、分类等条件筛选。\n\n**关联字典**:\n- supplies_category:备品分类(筛选+列表显示)\n- billing_type:计费方式(列表显示)") + @GetMapping("/items") + public Result> listSupplies(@ApiParam("备品查询请求") @Valid SuppliesQueryRequest query) { + return Result.success(suppliesService.listSupplies(query)); + } + +- @ApiOperation("备品详情") ++ @ApiOperation(value = "备品详情", notes = "获取备品完整信息,包含素材URL、标签等。\n\n**关联字典**:\n- supplies_category:备品分类(详情显示)\n- billing_type:计费方式(详情显示)") + @GetMapping("/item/{suppliesId}") + public Result getSupplies(@ApiParam("备品ID") @PathVariable Long suppliesId) { + return Result.success(suppliesService.getSupplies(suppliesId)); + } + +- @ApiOperation("更新备品") ++ @ApiOperation(value = "更新备品", notes = "更新备品基本信息,不改变当前状态。\n\n**关联字典**:\n- supplies_category:备品分类(表单选择)\n- billing_type:计费方式(表单选择)") + @PutMapping("/item/{suppliesId}") + public Result updateSupplies( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -57,7 +57,7 @@ public class SuppliesController { + return Result.success(suppliesService.updateSupplies(suppliesId, request, adminId)); + } + +- @ApiOperation("删除备品") ++ @ApiOperation(value = "删除备品", notes = "软删除备品。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/item/{suppliesId}") + public Result deleteSupplies( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -68,7 +68,7 @@ public class SuppliesController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{suppliesId}/submit-approval") + public Result> submitApproval( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -80,7 +80,7 @@ public class SuppliesController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("上下架切换") ++ @ApiOperation(value = "上下架切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{suppliesId}/status") + public Result updateStatus( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -91,7 +91,7 @@ public class SuppliesController { + return Result.success(); + } + +- @ApiOperation("批量上下架") ++ @ApiOperation(value = "批量上下架", notes = "批量修改多个备品的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("备品状态请求") @Valid @RequestBody SuppliesStatusRequest request, +@@ -103,7 +103,7 @@ public class SuppliesController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个备品。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java +index 7529058..8095ade 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java +@@ -27,7 +27,7 @@ public class SuppliesTagController { + + private final SuppliesTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询备品标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class SuppliesTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于备品编辑时的标签选择下拉。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class SuppliesTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class SuppliesTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色,所有关联备品自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class SuppliesTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有备品与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新备品标签") ++ @ApiOperation(value = "更新备品标签", notes = "全量替换指定备品的标签列表。") + @PutMapping("/item/{suppliesId}/tags") + public Result updateSuppliesTags( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -87,7 +87,7 @@ public class SuppliesTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个备品批量添加/移除标签。增量操作。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java +index 4e672d1..a0dc396 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】车型(Feign调用)") ++@Api(tags = "【内部接口】车型(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/vehicle") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalVehicleController { + + private final VehicleModelService vehicleModelService; + +- @ApiOperation("获取车型简要信息") ++ @ApiOperation(value = "获取车型简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个车型的简要信息,返回ID、名称、车辆类型、品牌、座位数、状态。不存在时返回错误。\n\n**关联字典**:\n- vehicle_type(车辆类型,返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/model/{vehicleId}") + public Result> getVehicleBrief(@PathVariable Long vehicleId) { + VehicleModel model = vehicleModelService.getVehicleEntity(vehicleId); +@@ -42,7 +42,7 @@ public class InternalVehicleController { + return Result.success(brief); + } + +- @ApiOperation("批量获取车型简要信息") ++ @ApiOperation(value = "批量获取车型简要信息", notes = "【仅限内部Feign调用】批量获取车型简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询行程关联的车辆资源。\n\n**关联字典**:\n- vehicle_type(车辆类型,返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/models/batch") + public Result>> getVehicleBatch(@RequestParam @Size(max = 500) List vehicleIds) { + List> results = vehicleIds.stream() +@@ -63,7 +63,7 @@ public class InternalVehicleController { + return Result.success(results); + } + +- @ApiOperation("按车辆类型查询车辆") ++ @ApiOperation(value = "按车辆类型查询车辆", notes = "【仅限内部Feign调用】按vehicleType查询第一个匹配的车型。vehicleType如:SEDAN(轿车)、SUV、MPV、BUS(大巴)、MINIBUS(中巴)等。未找到时返回null。\n\n**关联字典**:\n- vehicle_type(车辆类型,请求参数+返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/model/by-type/{vehicleType}") + public Result> getVehicleByType(@PathVariable String vehicleType) { + VehicleModel model = vehicleModelService.getVehicleByType(vehicleType); +@@ -80,7 +80,7 @@ public class InternalVehicleController { + return Result.success(brief); + } + +- @ApiOperation("按名称查询车辆") ++ @ApiOperation(value = "按名称查询车辆", notes = "【仅限内部Feign调用】按车型名称精确查询车辆信息。未找到时返回null。供产品服务通过名称关联车型使用。\n\n**关联字典**:\n- vehicle_type(车辆类型,返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/model/by-name/{name}") + public Result> getVehicleByName(@PathVariable String name) { + VehicleModel model = vehicleModelService.getVehicleByName(name); +@@ -97,9 +97,9 @@ public class InternalVehicleController { + return Result.success(brief); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配车型并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + vehicleModelService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java +index de59d9f..37797fd 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java +@@ -25,7 +25,7 @@ public class VehicleModelController { + + private final VehicleModelService vehicleModelService; + +- @ApiOperation("创建车型") ++ @ApiOperation(value = "创建车型", notes = "新建车型资源(如7座商务车、14座中巴等),初始状态为草稿(status=0)。车型有独立的价格日历用于报价计算。需走企微审批上架。\n\n**关联字典**:\n- vehicle_type:车辆类型(表单选择)") + @PostMapping("/model") + public Result createVehicle(@ApiParam("车型创建请求") @Valid @RequestBody VehicleCreateRequest request, + HttpServletRequest httpRequest) { +@@ -33,26 +33,26 @@ public class VehicleModelController { + return Result.success(vehicleModelService.createVehicle(request, adminId)); + } + +- @ApiOperation("车型列表") ++ @ApiOperation(value = "车型列表", notes = "分页查询车型列表,支持按名称、状态、车辆类型等条件筛选。\n\n**关联字典**:\n- vehicle_type:车辆类型(筛选+列表显示)") + @GetMapping("/models") + public Result> listVehicles(@ApiParam("车型查询请求") @Valid VehicleQueryRequest query) { + return Result.success(vehicleModelService.listVehicles(query)); + } + +- @ApiOperation("车型全量列表(不分页,用于下拉选择)") ++ @ApiOperation(value = "车型全量列表(不分页,用于下拉选择)", notes = "返回所有车型列表,可选按状态筛选。适用于产品编排时选择车型的下拉选择框。不分页返回全部数据。\n\n**关联字典**:\n- vehicle_type:车辆类型(列表显示)") + @GetMapping("/models/all") + public Result> listAllVehicles( + @ApiParam("状态筛选:1=上架") @RequestParam(required = false) Integer status) { + return Result.success(vehicleModelService.listAllVehicles(status)); + } + +- @ApiOperation("车型详情") ++ @ApiOperation(value = "车型详情", notes = "获取车型完整信息,包含座位数、品牌、素材URL、标签等。\n\n**关联字典**:\n- vehicle_type:车辆类型(详情显示)") + @GetMapping("/model/{vehicleId}") + public Result getVehicle(@ApiParam("车型ID") @PathVariable Long vehicleId) { + return Result.success(vehicleModelService.getVehicle(vehicleId)); + } + +- @ApiOperation("更新车型") ++ @ApiOperation(value = "更新车型", notes = "更新车型基本信息,不改变当前状态。\n\n**关联字典**:\n- vehicle_type:车辆类型(表单选择)") + @PutMapping("/model/{vehicleId}") + public Result updateVehicle(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("车型更新请求") @Valid @RequestBody VehicleUpdateRequest request, +@@ -61,7 +61,7 @@ public class VehicleModelController { + return Result.success(vehicleModelService.updateVehicle(vehicleId, request, adminId)); + } + +- @ApiOperation("删除车型") ++ @ApiOperation(value = "删除车型", notes = "软删除车型。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/model/{vehicleId}") + public Result deleteVehicle(@ApiParam("车型ID") @PathVariable Long vehicleId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -70,7 +70,7 @@ public class VehicleModelController { + return Result.success(); + } + +- @ApiOperation("提交审批") ++ @ApiOperation(value = "提交审批", notes = "向企微OA提交车型启用/禁用审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/model/{vehicleId}/submit-approval") + public Result> submitApproval(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("审批提交请求体") @Valid @RequestBody ApprovalSubmitRequest request, +@@ -80,7 +80,7 @@ public class VehicleModelController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("更新状态") ++ @ApiOperation(value = "更新状态", notes = "直接修改车型状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/model/{vehicleId}/status") + public Result updateStatus(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("状态请求体") @Valid @RequestBody VehicleStatusRequest request, +@@ -90,7 +90,7 @@ public class VehicleModelController { + return Result.success(); + } + +- @ApiOperation("批量更新状态") ++ @ApiOperation(value = "批量更新状态", notes = "批量修改多个车型的状态,跳过审批流程。") + @PutMapping("/models/batch/status") + public Result batchUpdateStatus(@ApiParam("批量状态请求体") @Valid @RequestBody VehicleStatusRequest request, + HttpServletRequest httpRequest) { +@@ -98,7 +98,7 @@ public class VehicleModelController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个车型。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/models/batch") + public Result batchDelete(@ApiParam("批量删除请求体") @Valid @RequestBody VehicleBatchDeleteRequest request, + HttpServletRequest httpRequest) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java +index 52a68eb..c1bcfba 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java +@@ -27,7 +27,7 @@ public class VehiclePriceCalendarController { + + private final VehiclePriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询车型的每日租赁价格和可调度状态。") + @GetMapping("/model/{vehicleId}/prices") + public Result getPriceCalendar(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("年份") @RequestParam @Min(2020) @Max(2100) Integer year, +@@ -35,7 +35,7 @@ public class VehiclePriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(vehicleId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置车型的租赁成本价和可调度状态。") + @PutMapping("/model/{vehicleId}/prices") + public Result batchSetPrices(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("价格日历设置请求") @Valid @RequestBody PriceCalendarSetRequest request) { +@@ -43,7 +43,7 @@ public class VehiclePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改调度状态") ++ @ApiOperation(value = "批量修改调度状态", notes = "批量修改日期范围内车型的可调度状态,不影响价格。") + @PutMapping("/model/{vehicleId}/prices/batch-status") + public Result batchUpdateStatus(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("价格日历状态请求") @Valid @RequestBody PriceCalendarStatusRequest request) { +@@ -51,7 +51,7 @@ public class VehiclePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("清除价格日历") ++ @ApiOperation(value = "清除价格日历", notes = "删除指定日期范围内车型的价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/model/{vehicleId}/prices") + public Result deletePrices(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("开始日期") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java +index a7a1b49..b2ad988 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java +@@ -26,7 +26,7 @@ public class VehicleTagController { + + private final VehicleTagService tagService; + +- @ApiOperation("预设标签列表(分页)") ++ @ApiOperation(value = "预设标签列表(分页)", notes = "分页查询车型标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,13 +35,13 @@ public class VehicleTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("全部标签列表") ++ @ApiOperation(value = "全部标签列表", notes = "不分页返回所有标签,用于车型编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag(@ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -49,7 +49,7 @@ public class VehicleTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag(@ApiParam("标签名称请求体") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -57,21 +57,21 @@ public class VehicleTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", notes = "修改标签名称或颜色。") + @PutMapping("/tag/{tagId}") + public Result updateTag(@ApiParam("标签ID") @PathVariable Long tagId, + @ApiParam("标签更新请求") @Valid @RequestBody TagUpdateRequest request) { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有车型与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("设置车型标签") ++ @ApiOperation(value = "设置车型标签", notes = "全量替换指定车型的标签列表。") + @PutMapping("/model/{vehicleId}/tags") + public Result updateVehicleTags(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("标签ID列表请求") @Valid @RequestBody VehicleTagUpdateRequest request) { +@@ -79,7 +79,7 @@ public class VehicleTagController { + return Result.success(); + } + +- @ApiOperation("批量添加/移除标签") ++ @ApiOperation(value = "批量添加/移除标签", notes = "对多个车型批量添加/移除标签。增量操作。") + @PutMapping("/models/batch/tags") + public Result batchUpdateTags(@ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { + tagService.batchUpdateTags(request.getVehicleIds(), request.getAddTagIds(), request.getRemoveTagIds()); +``` + +### `hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java b/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java +index 1781646..ad503eb 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java +@@ -25,19 +25,19 @@ public class AdminReviewController { + + private final ReviewService reviewService; + +- @ApiOperation("评价列表(支持好中差评/有图/有视频筛选)") ++ @ApiOperation(value = "评价列表(支持好中差评/有图/有视频筛选)", notes = "分页查询全部评价(含待审核/已通过/已拒绝),支持按评价等级、是否有图/视频、目标类型筛选\n\n**关联字典**:\n- review_status:评价审核状态(列表筛选+显示)\n- rating_level:评价等级(列表筛选+显示)") + @GetMapping("/list") + public Result> listReviews(@ApiParam("评价查询条件") ReviewQueryRequest request) { + return Result.success(reviewService.listReviews(request)); + } + +- @ApiOperation("评价详情") ++ @ApiOperation(value = "评价详情", notes = "**关联字典**:\n- review_status:评价审核状态(显示)\n- rating_level:评价等级(显示)") + @GetMapping("/{reviewId}") + public Result getReviewDetail(@ApiParam("评价ID") @PathVariable Long reviewId) { + return Result.success(reviewService.getReviewDetail(reviewId)); + } + +- @ApiOperation("通过评价") ++ @ApiOperation(value = "通过评价", notes = "审核通过评价,通过后评价在小程序端公开展示。状态流转:PENDING_REVIEW → APPROVED") + @PostMapping("/{reviewId}/approve") + public Result approve(@ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -47,7 +47,7 @@ public class AdminReviewController { + return Result.success(); + } + +- @ApiOperation("拒绝评价") ++ @ApiOperation(value = "拒绝评价", notes = "审核拒绝评价,需填写拒绝原因。拒绝后评价不公开展示。状态流转:PENDING_REVIEW → REJECTED") + @PostMapping("/{reviewId}/reject") + public Result reject(@ApiParam("评价ID") @PathVariable Long reviewId, + @ApiParam("拒绝请求") @Valid @RequestBody RejectRequest body, +@@ -59,7 +59,7 @@ public class AdminReviewController { + return Result.success(); + } + +- @ApiOperation("覆盖通过(机器拒绝的)") ++ @ApiOperation(value = "覆盖通过(机器拒绝的)", notes = "对阿里云内容审核自动拒绝的评价进行人工覆盖通过。状态流转:AUTO_REJECTED → APPROVED") + @PostMapping("/{reviewId}/override-approve") + public Result overrideApprove(@ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -69,7 +69,8 @@ public class AdminReviewController { + return Result.success(); + } + +- @ApiOperation("回复评价(每条评价仅可回复一次)") ++ @ApiOperation(value = "回复评价(每条评价仅可回复一次)", ++ notes = "管理员回复用户评价,回复内容在小程序端公开展示。每条评价仅允许回复一次,不可修改。\n\n**权限**:需管理员登录。") + @PostMapping("/{reviewId}/reply") + public Result adminReply(@ApiParam("评价ID") @PathVariable Long reviewId, + @ApiParam("回复内容") @Valid @RequestBody AdminReplyRequest body, +``` + +### `hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java +index b3dd6a3..62fb7d0 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java +@@ -19,7 +19,7 @@ import javax.validation.Valid; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】小程序评价(Feign调用)") ++@Api(tags = "【内部接口】小程序评价(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/review") + @RequiredArgsConstructor +@@ -27,7 +27,7 @@ public class InternalMpReviewController { + + private final ReviewService reviewService; + +- @ApiOperation("创建评价(仅针对产品,每个订单仅可评价一次)") ++ @ApiOperation(value = "创建评价(仅针对产品,每个订单仅可评价一次)", notes = "**关联字典**:\n- review_status:评价审核状态(返回字段)\n- rating_level:评价等级(返回字段)") + @PostMapping("/create") + public Result createReview(@Valid @RequestBody CreateReviewRequest body, + HttpServletRequest request) { +@@ -35,13 +35,14 @@ public class InternalMpReviewController { + return Result.success(reviewService.createReview(userId, body)); + } + +- @ApiOperation("检查订单是否已评价") ++ @ApiOperation(value = "检查订单是否已评价", ++ notes = "内部服务间调用。检查指定订单是否已有评价记录,用于小程序端订单详情页控制评价入口的显示。") + @GetMapping("/order/{orderId}/reviewed") + public Result isOrderReviewed(@PathVariable Long orderId) { + return Result.success(reviewService.isOrderReviewed(orderId)); + } + +- @ApiOperation("我的评价列表") ++ @ApiOperation(value = "我的评价列表", notes = "**关联字典**:\n- review_status:评价审核状态(显示)\n- rating_level:评价等级(显示)") + @GetMapping("/my") + public Result> getMyReviews(MpReviewQueryRequest query, + HttpServletRequest request) { +@@ -49,13 +50,13 @@ public class InternalMpReviewController { + return Result.success(reviewService.getMyReviews(userId, query)); + } + +- @ApiOperation("某目标的已通过评价(公开,支持好中差评/有图/有视频筛选)") ++ @ApiOperation(value = "某目标的已通过评价(公开,支持好中差评/有图/有视频筛选)", notes = "**关联字典**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/target") + public Result> getTargetReviews(@Valid TargetReviewQueryRequest query) { + return Result.success(reviewService.getTargetReviews(query)); + } + +- @ApiOperation("关键词搜索评价(公开)") ++ @ApiOperation(value = "关键词搜索评价(公开)", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/search") + public Result> searchReviews( + @ApiParam("搜索关键词") @RequestParam String keyword, +@@ -66,14 +67,15 @@ public class InternalMpReviewController { + return Result.success(reviewService.searchReviews(keyword, targetType, targetId, page, pageSize)); + } + +- @ApiOperation("首页精选评价") ++ @ApiOperation(value = "首页精选评价", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/featured") + public Result> getFeaturedReviews( + @ApiParam("数量限制") @RequestParam(defaultValue = "5") Integer limit) { + return Result.success(reviewService.getFeaturedReviews(limit)); + } + +- @ApiOperation("订单可评价目标列表") ++ @ApiOperation(value = "订单可评价目标列表", ++ notes = "内部服务间调用。返回订单关联的可评价目标(产品、定制师等),用于评价页面选择评价对象。已评价的目标不会重复出现。") + @GetMapping("/order/{orderId}/reviewable-targets") + public Result>> getReviewableTargets( + @PathVariable Long orderId, HttpServletRequest request) { +@@ -81,7 +83,8 @@ public class InternalMpReviewController { + return Result.success(reviewService.getReviewableTargets(orderId, userId)); + } + +- @ApiOperation("点赞/取消点赞评价") ++ @ApiOperation(value = "点赞/取消点赞评价", ++ notes = "内部服务间调用。切换当前用户对评价的点赞状态(toggle),返回最新点赞状态和点赞总数。") + @PostMapping("/{reviewId}/like") + public Result> toggleLike(@PathVariable Long reviewId, + HttpServletRequest request) { +@@ -89,7 +92,8 @@ public class InternalMpReviewController { + return Result.success(reviewService.toggleLike(reviewId, userId)); + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "内部服务间调用。检查当前用户是否已对指定评价点赞,用于小程序端渲染点赞按钮状态。") + @GetMapping("/{reviewId}/like/check") + public Result checkLiked(@PathVariable Long reviewId, + HttpServletRequest request) { +@@ -97,7 +101,8 @@ public class InternalMpReviewController { + return Result.success(reviewService.checkLiked(reviewId, userId)); + } + +- @ApiOperation("同步评价点赞数(供通用点赞服务回调)") ++ @ApiOperation(value = "同步评价点赞数(供通用点赞服务回调)", ++ notes = "内部服务间调用。通用点赞服务(user-service)发生点赞变化后回调此接口,同步更新评价表的点赞计数字段。") + @PostMapping("/{reviewId}/sync-like-count") + public Result syncLikeCount(@PathVariable Long reviewId, + @RequestParam int likeCount) { +``` + +### `hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java +index 0567412..7e5f1cb 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java +@@ -21,7 +21,7 @@ import java.util.List; + import java.util.Map; + import java.util.stream.Collectors; + +-@Api(tags = "【内部接口】评价统计(Feign调用)") ++@Api(tags = "【内部接口】评价统计(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/review") + @RequiredArgsConstructor +@@ -29,14 +29,14 @@ public class InternalReviewController { + + private final ReviewService reviewService; + +- @ApiOperation("目标评价统计(平均分,数量)") ++ @ApiOperation(value = "目标评价统计(平均分,数量)", notes = "**关联字典**:\n- rating_level:评价等级(统计维度)") + @GetMapping("/target-stats") + public Result getTargetStats(@RequestParam String targetType, + @RequestParam Long targetId) { + return Result.success(reviewService.getTargetStats(targetType, targetId)); + } + +- @ApiOperation("目标已通过评价列表") ++ @ApiOperation(value = "目标已通过评价列表", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/target-list") + public Result> getTargetReviews( + @RequestParam String targetType, +@@ -46,7 +46,7 @@ public class InternalReviewController { + return Result.success(reviewService.getTargetReviewsInternal(targetType, targetId, page, pageSize)); + } + +- @ApiOperation("批量目标评价统计(聚合多个targetId)") ++ @ApiOperation(value = "批量目标评价统计(聚合多个targetId)", notes = "**关联字典**:\n- rating_level:评价等级(统计维度)") + @GetMapping("/stats-by-targets") + public Result getStatsByTargetIds( + @RequestParam String targetType, +@@ -55,7 +55,7 @@ public class InternalReviewController { + return Result.success(reviewService.getStatsByTargetIds(targetType, ids)); + } + +- @ApiOperation("批量目标已通过评价列表(聚合多个targetId)") ++ @ApiOperation(value = "批量目标已通过评价列表(聚合多个targetId)", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/reviews-by-targets") + public Result> getReviewsByTargetIds( + @RequestParam String targetType, +@@ -66,13 +66,13 @@ public class InternalReviewController { + return Result.success(reviewService.getReviewsByTargetIds(targetType, ids, page, pageSize)); + } + +- @ApiOperation("产品精选评价(最高评分+最高点赞+统计)") ++ @ApiOperation(value = "产品精选评价(最高评分+最高点赞+统计)", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/product-highlights") + public Result> getProductHighlights(@RequestParam Long productId) { + return Result.success(reviewService.getProductHighlightReviews(productId)); + } + +- @ApiOperation("定制师已通过评价列表") ++ @ApiOperation(value = "定制师已通过评价列表", notes = "**关联字典**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/customizer-reviews") + public Result> getCustomizerReviews( + @RequestParam Long customizerId, +@@ -82,7 +82,8 @@ public class InternalReviewController { + return Result.success(reviewService.getCustomizerReviews(customizerId, page, pageSize, ratingLevel)); + } + +- @ApiOperation("定制师评价统计(总数/平均分/好评率)") ++ @ApiOperation(value = "定制师评价统计(总数/平均分/好评率)", ++ notes = "内部服务间调用。返回指定定制师的评价汇总统计:总评价数、平均评分、好评率等。用于定制师主页展示服务评价。") + @GetMapping("/customizer-review-stats") + public Result> getCustomizerReviewStats( + @RequestParam Long customizerId) { +``` + +### `hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java b/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java +index 75b6a7a..0629ed1 100644 +--- a/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java ++++ b/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java +@@ -33,7 +33,7 @@ public class BoardController { + + // ======================= Board CRUD ======================= + +- @ApiOperation("获取可见看板列表") ++ @ApiOperation(value = "获取可见看板列表", notes = "返回当前管理员可见的看板列表:超级管理员可见所有看板,普通管理员仅可见自己创建的或作为成员的看板") + @GetMapping("/boards") + public Result> getBoards(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -41,7 +41,7 @@ public class BoardController { + return Result.success(boardService.getVisibleBoards(adminId, role)); + } + +- @ApiOperation("看板详情") ++ @ApiOperation(value = "看板详情", notes = "返回看板基本信息(名称、描述、创建者),不含任务数据。查看任务请使用「获取看板任务」接口") + @GetMapping("/board/{boardId}") + public Result getBoardDetail(@ApiParam("看板ID") @PathVariable Long boardId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -49,7 +49,8 @@ public class BoardController { + return Result.success(boardService.getBoardDetail(boardId, adminId, role)); + } + +- @ApiOperation("创建自定义看板") ++ @ApiOperation(value = "创建自定义看板", ++ notes = "创建自定义看板,自动添加创建者为看板成员,并创建默认状态列(待办、进行中、已完成)。\n\n**权限**:需管理员登录。") + @OperationLog(value = "创建看板", module = "任务看板") + @PostMapping("/board") + public Result createBoard(@ApiParam("创建看板请求") @Valid @RequestBody CreateBoardRequest req, HttpServletRequest request) { +@@ -57,7 +58,8 @@ public class BoardController { + return Result.success(boardService.createBoard(req, adminId)); + } + +- @ApiOperation("更新看板") ++ @ApiOperation(value = "更新看板", ++ notes = "更新看板的名称和描述。仅看板创建者或超级管理员可操作。\n\n**权限**:需管理员登录,且为看板创建者或超级管理员。") + @OperationLog(value = "编辑看板", module = "任务看板") + @PutMapping("/board/{boardId}") + public Result updateBoard(@ApiParam("看板ID") @PathVariable Long boardId, +@@ -68,7 +70,7 @@ public class BoardController { + return Result.success(boardService.updateBoard(boardId, req, adminId, role)); + } + +- @ApiOperation("删除看板") ++ @ApiOperation(value = "删除看板", notes = "删除看板及其下所有状态列和任务(级联删除)。仅看板创建者或超级管理员可操作") + @OperationLog(value = "删除看板", module = "任务看板") + @DeleteMapping("/board/{boardId}") + public Result deleteBoard(@ApiParam("看板ID") @PathVariable Long boardId, HttpServletRequest request) { +@@ -80,13 +82,14 @@ public class BoardController { + + // ======================= Status columns ======================= + +- @ApiOperation("获取看板状态列") ++ @ApiOperation(value = "获取看板状态列", notes = "返回看板的所有状态列(如待办、进行中、已完成),按排序字段升序排列。拖拽任务到不同状态列实现状态流转") + @GetMapping("/board/{boardId}/statuses") + public Result> getStatuses(@ApiParam("看板ID") @PathVariable Long boardId) { + return Result.success(boardStatusService.getStatuses(boardId)); + } + +- @ApiOperation("创建状态列") ++ @ApiOperation(value = "创建状态列", ++ notes = "在看板中创建新的状态列(如测试中、待发布等),自动排到末尾。任务通过拖拽在不同状态列间流转。\n\n**权限**:需管理员登录且为看板成员。") + @OperationLog(value = "新增状态列", module = "任务看板") + @PostMapping("/board/{boardId}/status") + public Result createStatus(@ApiParam("看板ID") @PathVariable Long boardId, +@@ -97,7 +100,8 @@ public class BoardController { + return Result.success(boardStatusService.createStatus(boardId, req, adminId, role)); + } + +- @ApiOperation("更新状态列") ++ @ApiOperation(value = "更新状态列", ++ notes = "更新状态列的名称和颜色。\n\n**权限**:需管理员登录且为看板成员。") + @OperationLog(value = "编辑状态列", module = "任务看板") + @PutMapping("/status/{statusId}") + public Result updateStatus(@ApiParam("状态列ID") @PathVariable Long statusId, +@@ -108,7 +112,7 @@ public class BoardController { + return Result.success(boardStatusService.updateStatus(statusId, req, adminId, role)); + } + +- @ApiOperation("删除状态列") ++ @ApiOperation(value = "删除状态列", notes = "删除看板的状态列。如果状态列下有任务则不允许删除,需先移动或删除任务") + @OperationLog(value = "删除状态列", module = "任务看板") + @DeleteMapping("/status/{statusId}") + public Result deleteStatus(@ApiParam("状态列ID") @PathVariable Long statusId, +@@ -119,7 +123,7 @@ public class BoardController { + return Result.success(); + } + +- @ApiOperation("状态列排序") ++ @ApiOperation(value = "状态列排序", notes = "批量更新状态列的排序顺序。传入状态列ID数组,数组下标即为新的排序值。操作完成后通过WebSocket推送STATUS_REORDERED事件") + @PutMapping("/board/{boardId}/status/sort") + public Result sortStatuses(@ApiParam("看板ID") @PathVariable Long boardId, + @ApiParam("状态列排序请求") @Valid @RequestBody StatusSortRequest req, +@@ -133,13 +137,14 @@ public class BoardController { + + // ======================= Board Members ======================= + +- @ApiOperation("获取看板成员") ++ @ApiOperation(value = "获取看板成员", notes = "返回看板的所有成员列表,包含成员的管理员ID和姓名") + @GetMapping("/board/{boardId}/members") + public Result> getMembers(@ApiParam("看板ID") @PathVariable Long boardId) { + return Result.success(boardMemberService.getMembers(boardId)); + } + +- @ApiOperation("添加成员") ++ @ApiOperation(value = "添加成员", ++ notes = "批量添加管理员为看板成员,成为成员后可以查看看板、创建和操作任务。\n\n**权限**:需管理员登录,且为看板创建者或超级管理员。") + @OperationLog(value = "添加看板成员", module = "任务看板") + @PostMapping("/board/{boardId}/members") + public Result addMembers(@ApiParam("看板ID") @PathVariable Long boardId, +@@ -151,7 +156,7 @@ public class BoardController { + return Result.success(); + } + +- @ApiOperation("移除成员") ++ @ApiOperation(value = "移除成员", notes = "从看板中移除指定成员。仅看板创建者或超级管理员可操作,不能移除创建者自己") + @OperationLog(value = "移除看板成员", module = "任务看板") + @DeleteMapping("/board/{boardId}/member/{targetAdminId}") + public Result removeMember(@ApiParam("看板ID") @PathVariable Long boardId, +``` + +### `hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java b/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java +index 8593e4d..c85aeca 100644 +--- a/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java ++++ b/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java +@@ -31,7 +31,7 @@ public class TaskController { + + // ======================= Tasks ======================= + +- @ApiOperation("获取看板任务(按状态分组)") ++ @ApiOperation(value = "获取看板任务(按状态分组)", notes = "返回看板下所有任务,按状态列分组。支持按优先级(HIGH/MEDIUM/LOW)和负责人筛选,每组内按排序值升序排列\n\n**关联字典**:\n- task_priority:任务优先级(列表筛选+显示)") + @GetMapping("/board/{boardId}/tasks") + public Result> getBoardTasks(@ApiParam("看板ID") @PathVariable Long boardId, + @ApiParam("优先级") @RequestParam(required = false) String priority, +@@ -42,7 +42,7 @@ public class TaskController { + return Result.success(taskService.getBoardTasks(boardId, adminId, role, priority, assigneeId)); + } + +- @ApiOperation("任务详情") ++ @ApiOperation(value = "任务详情", notes = "返回任务完整信息,包含子任务列表、负责人信息、附件列表等\n\n**关联字典**:\n- task_priority:任务优先级(显示)") + @GetMapping("/{taskId}") + public Result getTaskDetail(@ApiParam("任务ID") @PathVariable Long taskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -50,7 +50,7 @@ public class TaskController { + return Result.success(taskService.getTaskDetail(taskId, adminId, role)); + } + +- @ApiOperation("创建任务") ++ @ApiOperation(value = "创建任务", notes = "在指定看板和状态列下创建任务。创建成功后通过WebSocket推送TASK_CREATED事件,并通知被分配的负责人\n\n**关联字典**:\n- task_priority:任务优先级(创建时选择)") + @OperationLog(value = "创建任务", module = "任务看板") + @PostMapping + public Result createTask(@ApiParam("创建任务请求") @Valid @RequestBody CreateTaskRequest req, HttpServletRequest request) { +@@ -62,7 +62,8 @@ public class TaskController { + return Result.success(vo); + } + +- @ApiOperation("更新任务") ++ @ApiOperation(value = "更新任务", ++ notes = "更新任务的标题、描述、优先级、截止日期、负责人等信息。更新后通过WebSocket推送TASK_UPDATED事件,如果修改了负责人则额外通知新负责人。\n\n**权限**:需管理员登录且为看板成员。\n\n**关联字典**:\n- task_priority:任务优先级(编辑时选择)") + @OperationLog(value = "编辑任务", module = "任务看板") + @PutMapping("/{taskId}") + public Result updateTask(@ApiParam("任务ID") @PathVariable Long taskId, +@@ -78,7 +79,7 @@ public class TaskController { + return Result.success(vo); + } + +- @ApiOperation("变更任务状态") ++ @ApiOperation(value = "变更任务状态", notes = "将任务移动到指定状态列(拖拽操作),自动记录状态变更到时间线,并通过WebSocket推送TASK_STATUS_CHANGED事件") + @PutMapping("/{taskId}/status") + public Result changeStatus(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("变更状态请求") @Valid @RequestBody ChangeStatusRequest req, +@@ -91,7 +92,7 @@ public class TaskController { + return Result.success(); + } + +- @ApiOperation("任务排序") ++ @ApiOperation(value = "任务排序", notes = "更新任务在同一状态列内的排序位置,用于拖拽排序") + @PutMapping("/{taskId}/sort") + public Result sortTasks(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("任务排序请求") @Valid @RequestBody TaskSortRequest req, +@@ -102,7 +103,8 @@ public class TaskController { + return Result.success(); + } + +- @ApiOperation("删除任务") ++ @ApiOperation(value = "删除任务", ++ notes = "删除任务及其所有子任务、评论和时间线记录(级联删除)。删除后通过WebSocket推送TASK_DELETED事件。\n\n**权限**:需管理员登录且为看板成员。") + @OperationLog(value = "删除任务", module = "任务看板") + @DeleteMapping("/{taskId}") + public Result deleteTask(@ApiParam("任务ID") @PathVariable Long taskId, HttpServletRequest request) { +@@ -117,7 +119,8 @@ public class TaskController { + + // ======================= Subtasks ======================= + +- @ApiOperation("创建子任务") ++ @ApiOperation(value = "创建子任务", ++ notes = "在指定任务下创建子任务(待办项),用于拆分任务的执行步骤。子任务默认为未完成状态。\n\n**权限**:需管理员登录且为看板成员。") + @PostMapping("/{taskId}/subtask") + public Result createSubtask(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("创建子任务请求") @Valid @RequestBody CreateSubtaskRequest req, +@@ -128,7 +131,7 @@ public class TaskController { + return Result.success(vo); + } + +- @ApiOperation("切换子任务完成状态") ++ @ApiOperation(value = "切换子任务完成状态", notes = "切换子任务的完成/未完成状态(toggle),完成状态切换会自动记录到任务时间线") + @PutMapping("/subtask/{subtaskId}/toggle") + public Result toggleSubtask(@ApiParam("子任务ID") @PathVariable Long subtaskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -137,7 +140,8 @@ public class TaskController { + return Result.success(); + } + +- @ApiOperation("删除子任务") ++ @ApiOperation(value = "删除子任务", ++ notes = "删除指定子任务。\n\n**权限**:需管理员登录且为看板成员。") + @DeleteMapping("/subtask/{subtaskId}") + public Result deleteSubtask(@ApiParam("子任务ID") @PathVariable Long subtaskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -148,7 +152,7 @@ public class TaskController { + + // ======================= Timeline (comments + activities) ======================= + +- @ApiOperation("获取任务时间线") ++ @ApiOperation(value = "获取任务时间线", notes = "返回任务的完整操作记录,包含评论和系统自动记录的状态变更、人员分配等活动,按时间正序排列") + @GetMapping("/{taskId}/timeline") + public Result> getTimeline(@ApiParam("任务ID") @PathVariable Long taskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -156,7 +160,7 @@ public class TaskController { + return Result.success(commentService.getTimeline(taskId, adminId, role)); + } + +- @ApiOperation("添加评论") ++ @ApiOperation(value = "添加评论", notes = "在任务时间线中添加评论,添加后自动通知任务负责人") + @PostMapping("/{taskId}/comment") + public Result addComment(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("创建评论请求") @Valid @RequestBody CreateCommentRequest req, +@@ -168,7 +172,7 @@ public class TaskController { + return Result.success(item); + } + +- @ApiOperation("删除评论") ++ @ApiOperation(value = "删除评论", notes = "仅评论作者本人可删除自己的评论,系统自动生成的活动记录不可删除") + @DeleteMapping("/comment/{commentId}") + public Result deleteComment(@ApiParam("评论ID") @PathVariable Long commentId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java +index 10fe201..c012fce 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java +@@ -22,7 +22,9 @@ public class AdminAgreementController { + + private final AgreementService agreementService; + +- @ApiOperation("协议列表") ++ @ApiOperation(value = "协议列表", notes = "分页查询用户协议列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listAgreements( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,20 +34,30 @@ public class AdminAgreementController { + return Result.success(agreementService.listAgreements(page, pageSize, keyword, status)); + } + +- @ApiOperation("协议详情") ++ @ApiOperation(value = "协议详情", ++ notes = "获取指定用户协议的详细信息,包括标题、内容(富文本)、版本号等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getAgreement(@ApiParam("协议ID") @PathVariable Long id) { + return Result.success(agreementService.getAgreement(id)); + } + +- @ApiOperation("新增协议") ++ @ApiOperation(value = "新增协议", ++ notes = "创建新的用户协议,如用户服务协议、隐私政策等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:协议类型(type)需唯一,同一类型不能重复创建。内容支持富文本。") + @OperationLog(value = "新增协议", module = "用户协议管理") + @PostMapping + public Result createAgreement(@Valid @RequestBody AgreementRequest request) { + return Result.success(agreementService.createAgreement(request)); + } + +- @ApiOperation("编辑协议") ++ @ApiOperation(value = "编辑协议", ++ notes = "更新指定用户协议的标题、内容、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:修改后小程序端会实时展示新内容。") + @OperationLog(value = "编辑协议", module = "用户协议管理") + @PutMapping("/{id}") + public Result updateAgreement(@ApiParam("协议ID") @PathVariable Long id, +@@ -53,7 +65,10 @@ public class AdminAgreementController { + return Result.success(agreementService.updateAgreement(id, request)); + } + +- @ApiOperation("删除协议") ++ @ApiOperation(value = "删除协议", ++ notes = "删除指定的用户协议记录(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序端将无法查看该协议。") + @OperationLog(value = "删除协议", module = "用户协议管理") + @DeleteMapping("/{id}") + public Result deleteAgreement(@ApiParam("协议ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java +index 5c47fa0..eec06ab 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java +@@ -23,7 +23,9 @@ public class AdminBannerController { + + private final BannerService bannerService; + +- @ApiOperation("Banner列表") ++ @ApiOperation(value = "Banner列表", notes = "分页查询Banner列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listBanners( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -34,13 +36,20 @@ public class AdminBannerController { + return Result.success(result); + } + +- @ApiOperation("Banner详情") ++ @ApiOperation(value = "Banner详情", ++ notes = "获取指定Banner的详细信息,包括标题、图片、跳转链接、排序等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getBanner(@ApiParam("轮播图ID") @PathVariable Long id) { + return Result.success(bannerService.getBanner(id)); + } + +- @ApiOperation("创建Banner") ++ @ApiOperation(value = "创建Banner", ++ notes = "创建新的首页轮播图,包括标题、封面图、跳转链接、排序等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:创建后默认为启用状态,小程序端将按排序展示。") + @OperationLog(value = "创建Banner", module = "Banner管理") + @PostMapping + public Result createBanner(@ApiParam("轮播图创建请求") @Valid @RequestBody BannerRequest request, +@@ -49,7 +58,9 @@ public class AdminBannerController { + return Result.success(bannerService.createBanner(request, adminId)); + } + +- @ApiOperation("更新Banner") ++ @ApiOperation(value = "更新Banner", ++ notes = "更新指定Banner的标题、封面图、跳转链接、排序、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新Banner", module = "Banner管理") + @PutMapping("/{id}") + public Result updateBanner(@ApiParam("轮播图ID") @PathVariable Long id, +@@ -57,7 +68,10 @@ public class AdminBannerController { + return Result.success(bannerService.updateBanner(id, request)); + } + +- @ApiOperation("删除Banner") ++ @ApiOperation(value = "删除Banner", ++ notes = "删除指定的Banner记录(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序首页将不再展示该Banner。") + @OperationLog(value = "删除Banner", module = "Banner管理") + @DeleteMapping("/{id}") + public Result deleteBanner(@ApiParam("轮播图ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java +index 6080439..786b6ad 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java +@@ -22,7 +22,10 @@ public class AdminContactController { + + private final ContactService contactService; + +- @ApiOperation("联系方式列表") ++ @ApiOperation(value = "联系方式列表", notes = "分页查询联系方式列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):返回字段channelType(PHONE=电话, WECHAT=微信, EMAIL=邮箱等)\n" ++ + "- common_status(通用状态):请求参数status和返回字段status") + @GetMapping + public Result> listContacts( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -33,20 +36,27 @@ public class AdminContactController { + return Result.success(result); + } + +- @ApiOperation("联系方式详情") ++ @ApiOperation(value = "联系方式详情", notes = "获取指定联系方式的详细信息。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):返回字段channelType\n" ++ + "- common_status(通用状态):返回字段status") + @GetMapping("/{id}") + public Result getContact(@ApiParam("联系方式ID") @PathVariable Long id) { + return Result.success(contactService.getContact(id)); + } + +- @ApiOperation("创建联系方式") ++ @ApiOperation(value = "创建联系方式", notes = "新增一条联系方式记录。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):请求字段channelType") + @OperationLog(value = "创建联系方式", module = "联系我们管理") + @PostMapping + public Result createContact(@ApiParam("联系方式创建请求") @Valid @RequestBody ContactRequest request) { + return Result.success(contactService.createContact(request)); + } + +- @ApiOperation("更新联系方式") ++ @ApiOperation(value = "更新联系方式", notes = "更新指定联系方式记录。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):请求字段channelType") + @OperationLog(value = "更新联系方式", module = "联系我们管理") + @PutMapping("/{id}") + public Result updateContact(@ApiParam("联系方式ID") @PathVariable Long id, +@@ -54,7 +64,10 @@ public class AdminContactController { + return Result.success(contactService.updateContact(id, request)); + } + +- @ApiOperation("删除联系方式") ++ @ApiOperation(value = "删除联系方式", ++ notes = "删除指定的联系方式记录(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序端将不再展示该联系方式。") + @OperationLog(value = "删除联系方式", module = "联系我们管理") + @DeleteMapping("/{id}") + public Result deleteContact(@ApiParam("联系方式ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java +index 23ad20d..b5b5983 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java +@@ -19,7 +19,14 @@ public class AdminCustomerController { + + private final UserService userService; + +- @ApiOperation("客户列表") ++ @ApiOperation(value = "客户列表", notes = "分页查询小程序注册的C端用户(客户)列表。" ++ + "支持按昵称/手机号/真实姓名关键词搜索,按状态筛选。" ++ + "status取值:ACTIVE=正常 BANNED=已封禁。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- user_status(用户状态):请求参数status和返回字段status(ACTIVE=正常, BANNED=已封禁)\n" ++ + "- gender(性别):返回字段gender(0=女, 1=男)\n" ++ + "- id_card_type(证件类型):返回字段idCardType") + @GetMapping + public Result> listCustomers( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -30,14 +37,21 @@ public class AdminCustomerController { + return Result.success(result); + } + +- @ApiOperation("客户详情") ++ @ApiOperation(value = "客户详情", notes = "获取指定客户的详细信息。" ++ + "\n\n**关联字典**:\n" ++ + "- user_status(用户状态):返回字段status\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType") + @GetMapping("/{userId}") + public Result getCustomer(@ApiParam("用户ID") @PathVariable Long userId) { + CustomerVO customer = userService.getCustomerDetail(userId); + return Result.success(customer); + } + +- @ApiOperation("封禁客户") ++ @ApiOperation(value = "封禁客户", notes = "封禁指定的C端用户,状态变为BANNED。" ++ + "封禁后该用户无法登录小程序,已有的Token将失效。" ++ + "封禁操作不会删除用户数据,可通过[解封客户]接口恢复。" ++ + "需要管理员认证。") + @OperationLog(value = "封禁客户", module = "客户管理") + @PostMapping("/{userId}/ban") + public Result banCustomer(@ApiParam("用户ID") @PathVariable Long userId) { +@@ -45,7 +59,9 @@ public class AdminCustomerController { + return Result.success(); + } + +- @ApiOperation("解封客户") ++ @ApiOperation(value = "解封客户", notes = "解封已封禁的C端用户,状态恢复为ACTIVE。" ++ + "解封后用户可正常登录小程序。" ++ + "需要管理员认证。") + @OperationLog(value = "解封客户", module = "客户管理") + @PostMapping("/{userId}/unban") + public Result unbanCustomer(@ApiParam("用户ID") @PathVariable Long userId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java +index 5dfa05d..c76c659 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java +@@ -30,14 +30,18 @@ public class AdminDesignerController { + private final DesignerProfileService designerProfileService; + private final DesignerDashboardService designerDashboardService; + +- @ApiOperation("获取我的个人资料(已废弃,请使用 /admin/profile/me)") ++ @ApiOperation(value = "获取我的个人资料(已废弃,请使用 /admin/profile/me)", notes = "已废弃接口。" ++ + "\n\n**关联字典**:\n" ++ + "- designer_cert_level(认证等级):返回字段certLevel(none/bronze/silver/gold/diamond)") + @GetMapping("/profile") + public Result getMyProfile(HttpServletRequest request) { + Long adminId = getAdminId(request); + return Result.success(designerProfileService.getMyProfile(adminId)); + } + +- @ApiOperation("更新我的个人资料(已废弃,请使用 PUT /admin/profile/me)") ++ @ApiOperation(value = "更新我的个人资料(已废弃,请使用 PUT /admin/profile/me)", ++ notes = "已废弃接口,请迁移至 PUT /admin/profile/me。\n\n" ++ + "**权限**:需要管理员登录。") + @PutMapping("/profile") + public Result updateMyProfile(HttpServletRequest request, + @Valid @RequestBody UpdateDesignerProfileRequest body) { +@@ -45,14 +49,18 @@ public class AdminDesignerController { + return Result.success(designerProfileService.updateMyProfile(adminId, body)); + } + +- @ApiOperation("工作台概览(已废弃,请使用 /admin/profile/dashboard)") ++ @ApiOperation(value = "工作台概览(已废弃,请使用 /admin/profile/dashboard)", ++ notes = "已废弃接口,请迁移至 GET /admin/profile/dashboard。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/dashboard") + public Result getDashboard(HttpServletRequest request) { + Long adminId = getAdminId(request); + return Result.success(designerDashboardService.getDashboard(adminId, "today")); + } + +- @ApiOperation("我的订单列表(已废弃,请使用 /admin/profile/orders)") ++ @ApiOperation(value = "我的订单列表(已废弃,请使用 /admin/profile/orders)", notes = "已废弃接口。" ++ + "\n\n**关联字典**:\n" ++ + "- order_status(订单状态):请求参数status和返回字段status") + @GetMapping("/orders") + public Result>> getMyOrders( + HttpServletRequest request, +@@ -64,7 +72,9 @@ public class AdminDesignerController { + return Result.success(designerDashboardService.getMyOrders(adminId, page, pageSize, status, keyword)); + } + +- @ApiOperation("我的产品列表(已废弃,请使用 /admin/profile/products)") ++ @ApiOperation(value = "我的产品列表(已废弃,请使用 /admin/profile/products)", notes = "已废弃接口。" ++ + "\n\n**关联字典**:\n" ++ + "- product_status(产品状态):请求参数status和返回字段status") + @GetMapping("/products") + public Result>> getMyProducts( + HttpServletRequest request, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java +index ebe2d88..f6fe95a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java +@@ -24,7 +24,9 @@ public class AdminExploreCategoryController { + + private final ExploreCategoryService exploreCategoryService; + +- @ApiOperation("探索分类列表") ++ @ApiOperation(value = "探索分类列表", notes = "分页查询探索分类列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listCategories( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,13 +37,20 @@ public class AdminExploreCategoryController { + return Result.success(result); + } + +- @ApiOperation("探索分类详情") ++ @ApiOperation(value = "探索分类详情", ++ notes = "获取指定探索分类的详细信息,包括标题、封面图、描述、关联的景区资源列表等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getCategory(@ApiParam("分类ID") @PathVariable Long id) { + return Result.success(exploreCategoryService.getCategory(id)); + } + +- @ApiOperation("创建探索分类") ++ @ApiOperation(value = "创建探索分类", ++ notes = "创建新的探索分类,用于小程序探索页面的分类展示。\n" ++ + "可关联多个景区资源,设置封面图和描述文字。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "创建探索分类", module = "探索管理") + @PostMapping + public Result createCategory(@ApiParam("分类创建请求") @Valid @RequestBody ExploreCategoryRequest request, +@@ -51,7 +60,9 @@ public class AdminExploreCategoryController { + return Result.success(); + } + +- @ApiOperation("更新探索分类") ++ @ApiOperation(value = "更新探索分类", ++ notes = "更新指定探索分类的标题、封面图、描述、关联资源、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新探索分类", module = "探索管理") + @PutMapping("/{id}") + public Result updateCategory(@ApiParam("分类ID") @PathVariable Long id, +@@ -60,7 +71,10 @@ public class AdminExploreCategoryController { + return Result.success(); + } + +- @ApiOperation("删除探索分类") ++ @ApiOperation(value = "删除探索分类", ++ notes = "删除指定的探索分类(软删除),同时清除关联的资源绑定关系。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序探索页面将不再展示该分类。") + @OperationLog(value = "删除探索分类", module = "探索管理") + @DeleteMapping("/{id}") + public Result deleteCategory(@ApiParam("分类ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java +index 61a2dbb..11e1fdd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java +@@ -26,20 +26,28 @@ public class AdminFaqController { + + // ==================== 分类 ==================== + +- @ApiOperation("分类列表") ++ @ApiOperation(value = "分类列表", ++ notes = "获取所有FAQ分类的完整列表(不分页)。\n" ++ + "每个分类包含名称、排序号、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/categories") + public Result> listCategories() { + return Result.success(faqService.listCategories()); + } + +- @ApiOperation("创建分类") ++ @ApiOperation(value = "创建分类", ++ notes = "创建新的FAQ分类,用于对常见问题进行归类。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:分类名称不能重复。") + @OperationLog(value = "创建FAQ分类", module = "常见问题管理") + @PostMapping("/categories") + public Result createCategory(@Valid @RequestBody FaqCategoryRequest request) { + return Result.success(faqService.createCategory(request)); + } + +- @ApiOperation("更新分类") ++ @ApiOperation(value = "更新分类", ++ notes = "更新指定FAQ分类的名称、排序号、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新FAQ分类", module = "常见问题管理") + @PutMapping("/categories/{id}") + public Result updateCategory(@ApiParam("分类ID") @PathVariable Long id, +@@ -47,7 +55,10 @@ public class AdminFaqController { + return Result.success(faqService.updateCategory(id, request)); + } + +- @ApiOperation("删除分类") ++ @ApiOperation(value = "删除分类", ++ notes = "删除指定的FAQ分类(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除分类不会删除其下的条目,但条目将变为无分类状态。") + @OperationLog(value = "删除FAQ分类", module = "常见问题管理") + @DeleteMapping("/categories/{id}") + public Result deleteCategory(@ApiParam("分类ID") @PathVariable Long id) { +@@ -57,21 +68,29 @@ public class AdminFaqController { + + // ==================== 条目 ==================== + +- @ApiOperation("条目列表") ++ @ApiOperation(value = "条目列表", ++ notes = "查询FAQ条目列表,支持按分类ID筛选。\n" ++ + "返回问题标题、回答内容(富文本)、排序号等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/items") + public Result> listItems( + @ApiParam("分类ID(可选)") @RequestParam(required = false) Long categoryId) { + return Result.success(faqService.listItems(categoryId)); + } + +- @ApiOperation("创建条目") ++ @ApiOperation(value = "创建条目", ++ notes = "创建一条常见问题,包含问题标题和回答(支持富文本)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:需指定所属分类ID,排序号越小越靠前。") + @OperationLog(value = "创建FAQ条目", module = "常见问题管理") + @PostMapping("/items") + public Result createItem(@Valid @RequestBody FaqItemRequest request) { + return Result.success(faqService.createItem(request)); + } + +- @ApiOperation("更新条目") ++ @ApiOperation(value = "更新条目", ++ notes = "更新指定FAQ条目的问题标题、回答内容、排序号等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新FAQ条目", module = "常见问题管理") + @PutMapping("/items/{id}") + public Result updateItem(@ApiParam("条目ID") @PathVariable Long id, +@@ -79,7 +98,10 @@ public class AdminFaqController { + return Result.success(faqService.updateItem(id, request)); + } + +- @ApiOperation("删除条目") ++ @ApiOperation(value = "删除条目", ++ notes = "删除指定的FAQ条目(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序FAQ页面将不再展示该条目。") + @OperationLog(value = "删除FAQ条目", module = "常见问题管理") + @DeleteMapping("/items/{id}") + public Result deleteItem(@ApiParam("条目ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java +index e81218e..5f5117b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java +@@ -24,7 +24,9 @@ public class AdminFrontendConfigController { + + private final FrontendConfigService frontendConfigService; + +- @ApiOperation("配置列表") ++ @ApiOperation(value = "配置列表", notes = "分页查询前端配置列表,支持按关键词、分组和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listConfigs( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,7 +37,10 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.listConfigs(page, pageSize, keyword, configGroup, status)); + } + +- @ApiOperation("配置列表(不分页)") ++ @ApiOperation(value = "配置列表(不分页)", ++ notes = "获取所有前端配置项的完整列表(不分页),支持按分组和状态筛选。\n" ++ + "适用于需要一次性加载全部配置的场景。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/all") + public Result> listAllConfigs( + @ApiParam("配置分组") @RequestParam(required = false) String configGroup, +@@ -43,25 +48,37 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.listAllConfigs(configGroup, status)); + } + +- @ApiOperation("配置详情") ++ @ApiOperation(value = "配置详情", ++ notes = "根据配置ID获取指定前端配置项的详细信息,包括key、value、分组、描述等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/{id}") + public Result getConfig(@ApiParam("配置ID") @PathVariable Long id) { + return Result.success(frontendConfigService.getConfig(id)); + } + +- @ApiOperation("按key查询配置") ++ @ApiOperation(value = "按key查询配置", ++ notes = "根据配置键(configKey)获取指定的前端配置项。\n" ++ + "configKey为全局唯一标识,如 app_name、primary_color 等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/by-key/{key}") + public Result getConfigByKey(@ApiParam("配置键") @PathVariable String key) { + return Result.success(frontendConfigService.getConfigByKey(key)); + } + +- @ApiOperation("获取所有分组") ++ @ApiOperation(value = "获取所有分组", ++ notes = "获取前端配置中所有已使用的分组名称列表。\n" ++ + "用于配置管理页面的分组筛选下拉框。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/groups") + public Result> listGroups() { + return Result.success(frontendConfigService.listGroups()); + } + +- @ApiOperation("创建配置") ++ @ApiOperation(value = "创建配置", ++ notes = "创建新的前端配置项,用于控制前端页面的展示和行为。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:configKey 必须全局唯一,不能与已有配置重复。" ++ + "可通过 sensitive 字段标记是否为敏感配置(敏感配置不会通过公开接口暴露给小程序)。") + @OperationLog(value = "创建前端配置", module = "前端配置管理") + @PostMapping + public Result createConfig( +@@ -71,7 +88,10 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.createConfig(request, adminId)); + } + +- @ApiOperation("更新配置") ++ @ApiOperation(value = "更新配置", ++ notes = "更新指定前端配置项的值、分组、描述、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:修改后前端会实时使用新值(如有缓存需等待刷新)。") + @OperationLog(value = "更新前端配置", module = "前端配置管理") + @PutMapping("/{id}") + public Result updateConfig( +@@ -80,7 +100,10 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.updateConfig(id, request)); + } + +- @ApiOperation("删除配置") ++ @ApiOperation(value = "删除配置", ++ notes = "删除指定的前端配置项(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后前端将无法获取该配置,可能影响页面展示,请确认无引用后再删除。") + @OperationLog(value = "删除前端配置", module = "前端配置管理") + @DeleteMapping("/{id}") + public Result deleteConfig(@ApiParam("配置ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java +index e174243..6558bc2 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java +@@ -29,7 +29,12 @@ public class AdminProfileController { + private final FinanceDashboardService financeDashboardService; + private final MaterialDashboardService materialDashboardService; + +- @ApiOperation("获取我的个人资料") ++ @ApiOperation(value = "获取我的个人资料", ++ notes = "获取当前登录管理员的个人资料,根据角色返回不同的资料内容。\n" ++ + "定制师角色会返回认证等级、个人简介、擅长领域等附加信息。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- designer_cert_level(认证等级):返回字段certLevel(none/bronze/silver/gold/diamond)") + @GetMapping("/me") + public Result getMyProfile(HttpServletRequest request) { + Long adminId = getAdminId(request); +@@ -37,7 +42,10 @@ public class AdminProfileController { + return Result.success(profileService.getProfile(adminId, role)); + } + +- @ApiOperation("更新我的个人资料") ++ @ApiOperation(value = "更新我的个人资料", ++ notes = "更新当前登录管理员的个人资料,支持修改昵称、头像、个人简介等。\n" ++ + "定制师角色可额外更新擅长领域、服务区域等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @PutMapping("/me") + public Result updateMyProfile(HttpServletRequest request, + @Valid @RequestBody UpdateDesignerProfileRequest body) { +@@ -46,9 +54,19 @@ public class AdminProfileController { + return Result.success(profileService.updateProfile(adminId, role, body)); + } + +- @ApiOperation("工作台仪表盘(角色分发,支持时间范围)") ++ @ApiOperation(value = "工作台仪表盘(角色分发,支持时间范围)", notes = "根据当前管理员角色返回不同的仪表盘数据。" ++ + "CUSTOMIZER(定制师):待处理订单数、产品数、评价统计等。" ++ + "SUPER_ADMIN/ADMIN:全局概览(订单、收入、用户增长等)。" ++ + "ROOM_MANAGER(客房管理):房间分配概览。" ++ + "VEHICLE_MANAGER(车辆管理):车辆调度概览。" ++ + "FINANCE(财务):收支统计。" ++ + "MATERIAL_ADMIN(素材管理):素材库概览。" ++ + "period取值:today=今日 week=本周 month=本月。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- order_status(订单状态):仪表盘中订单统计按状态分组展示") + @GetMapping("/dashboard") +- public Result getDashboard( ++ public Result getDashboard( + HttpServletRequest request, + @ApiParam("时间范围: today/week/month") @RequestParam(defaultValue = "today") String period) { + Long adminId = getAdminId(request); +@@ -72,7 +90,9 @@ public class AdminProfileController { + } + } + +- @ApiOperation("我的评价列表") ++ @ApiOperation(value = "我的评价列表", notes = "查询当前定制师收到的评价列表,支持按评价等级筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- rating_level(评价等级):GOOD=好评, MEDIUM=中评, BAD=差评(筛选条件+列表展示)\n") + @GetMapping("/reviews") + public Result>> getReviews( + HttpServletRequest request, +@@ -83,7 +103,9 @@ public class AdminProfileController { + return Result.success(designerDashboardService.getMyReviews(adminId, page, pageSize, ratingLevel)); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "查询当前定制师的订单列表,支持按状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- order_status(订单状态):请求参数status和返回字段status") + @GetMapping("/orders") + public Result>> getOrders( + HttpServletRequest request, +@@ -95,7 +117,9 @@ public class AdminProfileController { + return Result.success(designerDashboardService.getMyOrders(adminId, page, pageSize, status, keyword)); + } + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", notes = "查询当前定制师的产品列表,支持按状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- product_status(产品状态):请求参数status和返回字段status") + @GetMapping("/products") + public Result>> getProducts( + HttpServletRequest request, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java +index 7d2e9bc..e6766e3 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java +@@ -23,7 +23,9 @@ public class AdminTopicController { + + private final TopicService topicService; + +- @ApiOperation("专题列表") ++ @ApiOperation(value = "专题列表", notes = "分页查询探索专题列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listTopics( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -34,13 +36,20 @@ public class AdminTopicController { + return Result.success(result); + } + +- @ApiOperation("专题详情") ++ @ApiOperation(value = "专题详情", ++ notes = "获取指定探索专题的详细信息,包括标题、封面图、描述、关联资源等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getTopic(@ApiParam("专题ID") @PathVariable Long id) { + return Result.success(topicService.getTopic(id)); + } + +- @ApiOperation("创建专题") ++ @ApiOperation(value = "创建专题", ++ notes = "创建新的探索专题,用于小程序探索页面展示主题推荐内容。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:创建时需设置标题、封面图等基本信息。") + @OperationLog(value = "创建专题", module = "探索专题管理") + @PostMapping + public Result createTopic(@ApiParam("专题创建请求") @Valid @RequestBody TopicRequest request, +@@ -49,7 +58,9 @@ public class AdminTopicController { + return Result.success(topicService.createTopic(request, adminId)); + } + +- @ApiOperation("更新专题") ++ @ApiOperation(value = "更新专题", ++ notes = "更新指定探索专题的标题、封面图、描述、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新专题", module = "探索专题管理") + @PutMapping("/{id}") + public Result updateTopic(@ApiParam("专题ID") @PathVariable Long id, +@@ -57,7 +68,10 @@ public class AdminTopicController { + return Result.success(topicService.updateTopic(id, request)); + } + +- @ApiOperation("删除专题") ++ @ApiOperation(value = "删除专题", ++ notes = "删除指定的探索专题(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序探索页面将不再展示该专题。") + @OperationLog(value = "删除专题", module = "探索专题管理") + @DeleteMapping("/{id}") + public Result deleteTopic(@ApiParam("专题ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java +index 2b3f74a..0344258 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java +@@ -26,7 +26,12 @@ public class AdminUserController { + + private final AdminUserService adminUserService; + +- @ApiOperation("创建管理员") ++ @ApiOperation(value = "创建管理员", notes = "创建新的后台管理员账号。" ++ + "默认密码为Admin@123456,管理员首次登录后建议修改密码。" ++ + "可通过roleIds分配多个角色,也兼容旧的单角色roleId参数。" ++ + "需要SUPER_ADMIN或ADMIN角色。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用\n") + @OperationLog(value = "创建管理员", module = "管理员管理") + @PostMapping + public Result createAdmin(@ApiParam("创建管理员请求") @Valid @RequestBody CreateAdminRequest request) { +@@ -34,7 +39,9 @@ public class AdminUserController { + return Result.success(admin); + } + +- @ApiOperation("更新管理员") ++ @ApiOperation(value = "更新管理员", notes = "更新管理员信息,包括用户名、状态、角色分配等。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用\n") + @OperationLog(value = "更新管理员", module = "管理员管理") + @PutMapping("/{adminId}") + public Result updateAdmin(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -43,7 +50,10 @@ public class AdminUserController { + return Result.success(admin); + } + +- @ApiOperation("删除管理员") ++ @ApiOperation(value = "删除管理员", notes = "删除指定管理员账号(软删除)。" ++ + "不能删除自己的账号,不能删除SUPER_ADMIN角色的账号(除非操作者也是SUPER_ADMIN)。" ++ + "删除后该管理员的登录状态自动失效。" ++ + "需要SUPER_ADMIN或ADMIN角色。") + @OperationLog(value = "删除管理员", module = "管理员管理") + @DeleteMapping("/{adminId}") + public Result deleteAdmin(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -54,7 +64,9 @@ public class AdminUserController { + return Result.success(); + } + +- @ApiOperation("解锁管理员") ++ @ApiOperation(value = "解锁管理员", notes = "解锁因登录失败次数过多而被锁定的管理员账号。" ++ + "管理员连续5次登录失败后账号自动锁定30分钟,此接口可立即解锁。" ++ + "需要SUPER_ADMIN或ADMIN角色。") + @OperationLog(value = "解锁管理员", module = "管理员管理") + @PostMapping("/{adminId}/unlock") + public Result unlockAdmin(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -65,7 +77,10 @@ public class AdminUserController { + return Result.success(); + } + +- @ApiOperation("重置密码") ++ @ApiOperation(value = "重置密码", notes = "将指定管理员的密码重置为默认密码(Admin@123456)。" ++ + "用于管理员忘记密码时由上级管理员操作重置。" ++ + "重置后管理员可用默认密码登录,建议立即修改。" ++ + "需要SUPER_ADMIN或ADMIN角色。") + @OperationLog(value = "重置密码", module = "管理员管理") + @PostMapping("/{adminId}/reset-password") + public Result resetPassword(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -76,7 +91,10 @@ public class AdminUserController { + return Result.success(); + } + +- @ApiOperation("修改企业微信绑定(支持换绑)") ++ @ApiOperation(value = "修改企业微信绑定(支持换绑)", notes = "为管理员绑定或更换企业微信账号。" ++ + "绑定后管理员可通过企业微信扫码登录,并可接收审批通知。" ++ + "如果目标企微ID已被其他管理员绑定,需设置forceRebind=true强制换绑。" ++ + "需要管理员认证。") + @OperationLog(value = "修改企业微信绑定", module = "管理员管理") + @PutMapping("/{adminId}/wechat-binding") + public Result> updateWechatBinding( +@@ -92,14 +110,21 @@ public class AdminUserController { + return Result.success(result); + } + +- @ApiOperation("获取管理员详情") ++ @ApiOperation(value = "获取管理员详情", notes = "获取指定管理员的完整信息。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用\n") + @GetMapping("/{adminId}") + public Result getAdmin(@ApiParam("管理员ID") @PathVariable Long adminId) { + AdminUser admin = adminUserService.getAdminById(adminId); + return Result.success(admin); + } + +- @ApiOperation("管理员列表") ++ @ApiOperation(value = "管理员列表", notes = "分页查询管理员列表,支持按角色、状态、企微绑定状态筛选。" ++ + "status取值:ACTIVE=正常 LOCKED=已锁定 DISABLED=已禁用。" ++ + "wechatBound:true=已绑定企业微信 false=未绑定。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用(筛选条件+列表展示)\n") + @GetMapping + public Result> listAdmins( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java +index bf6beb1..84bf6c9 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java +@@ -30,7 +30,10 @@ public class AuthController { + @Value("${auth.2fa-confirm-enabled:false}") + private boolean twoFaConfirmEnabled; + +- @ApiOperation("管理员登录") ++ @ApiOperation(value = "管理员登录", notes = "管理员通过用户名+密码登录后台管理系统。" ++ + "首次在新设备登录时需要进行企业微信扫码二次验证(2FA),返回needTwoFa=true。" ++ + "登录失败5次后账号将被锁定30分钟。" ++ + "无需认证即可调用。") + @PostMapping("/login") + public Result login(@ApiParam("管理员登录请求") @Valid @RequestBody AdminLoginRequest request, + HttpServletRequest httpRequest) { +@@ -41,7 +44,10 @@ public class AuthController { + return Result.success(response); + } + +- @ApiOperation("2FA验证") ++ @ApiOperation(value = "2FA验证", notes = "新设备登录时的企业微信二次验证。" ++ + "管理员登录返回needTwoFa=true后,前端调用此接口提交验证码完成登录。" ++ + "验证通过后设备将被标记为可信设备,后续登录不再需要2FA。" ++ + "无需认证即可调用。") + @PostMapping("/wechat/verify-2fa") + public Result verifyTwoFa(@ApiParam("管理员ID") @RequestParam Long adminId, + @ApiParam("2FA验证请求") @Valid @RequestBody TwoFaVerifyRequest request, +@@ -53,7 +59,10 @@ public class AuthController { + return Result.success(response); + } + +- @ApiOperation("修改密码") ++ @ApiOperation(value = "修改密码", notes = "管理员修改自己的登录密码。" ++ + "需验证旧密码正确后才能设置新密码,新密码须满足复杂度要求(8-128位,含大小写字母和数字)。" ++ + "修改成功后当前Token仍然有效,无需重新登录。" ++ + "需要管理员认证(Token中的adminId)。") + @OperationLog(value = "修改密码", module = "认证管理") + @PutMapping("/password") + public Result changePassword(HttpServletRequest request, +@@ -63,7 +72,9 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("管理员登出") ++ @ApiOperation(value = "管理员登出", notes = "清除管理员的登录状态并使当前Token失效。" ++ + "前端应在登出后清除本地存储的Token和用户信息。" ++ + "需要管理员认证。") + @PostMapping("/logout") + public Result logout(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -71,14 +82,20 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("生成2FA扫码会话") ++ @ApiOperation(value = "生成2FA扫码会话", notes = "生成企业微信扫码二维码的会话信息,用于新设备二次验证。" ++ + "返回包含qrcodeUrl(二维码链接)和state(会话标识)。" ++ + "前端展示二维码后通过轮询 /2fa/check 接口检查扫码状态。" ++ + "无需认证即可调用(登录流程中使用)。") + @GetMapping("/2fa/qrcode") + public Result> generate2FaQrcode(@ApiParam("管理员ID") @RequestParam Long adminId) { + Map data = adminAuthService.generate2FaQrSession(adminId); + return Result.success(data); + } + +- @ApiOperation("2FA企微扫码回调") ++ @ApiOperation(value = "2FA企微扫码回调", notes = "企业微信OAuth回调地址,用户扫码授权后微信服务器回调此接口。" ++ + "此接口由微信服务器调用,非前端直接调用。" ++ + "回调成功后将state对应的会话标记为已扫码,前端轮询 /2fa/check 即可获取结果。" ++ + "返回HTML页面(成功/失败提示),不返回JSON。") + @GetMapping(value = "/2fa/callback", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String handle2FaCallback(@ApiParam("授权码") @RequestParam String code, @ApiParam("会话状态") @RequestParam String state) { +@@ -120,14 +137,19 @@ public class AuthController { + + // ==================== WeChat QR Direct Login ==================== + +- @ApiOperation("生成企业微信扫码登录会话") ++ @ApiOperation(value = "生成企业微信扫码登录会话", notes = "生成企业微信扫码直接登录的会话信息(非2FA验证,而是扫码替代密码登录)。" ++ + "返回包含qrcodeUrl和state。前端展示二维码后通过轮询 /wechat-qr/status 检查登录状态。" ++ + "无需认证即可调用。") + @GetMapping("/wechat-qr") + public Result> generateWechatLoginQr() { + Map data = adminAuthService.generateWechatLoginQrSession(); + return Result.success(data); + } + +- @ApiOperation("企业微信扫码登录回调") ++ @ApiOperation(value = "企业微信扫码登录回调", notes = "企业微信OAuth回调地址,扫码登录授权后微信服务器回调此接口。" ++ + "此接口由微信服务器调用,非前端直接调用。" ++ + "回调后标记会话为已扫码,前端通过轮询 /wechat-qr/status 获取登录结果。" ++ + "返回HTML页面,不返回JSON。") + @GetMapping(value = "/wechat-qr/callback", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String handleWechatLoginCallback(@ApiParam("授权码") @RequestParam String code, @ApiParam("会话状态") @RequestParam String state) { +@@ -167,7 +189,10 @@ public class AuthController { + } + } + +- @ApiOperation("查询企业微信扫码登录状态") ++ @ApiOperation(value = "查询企业微信扫码登录状态", notes = "前端轮询此接口检查扫码登录是否完成。" ++ + "返回status字段:PENDING=等待扫码,SCANNED=已扫码登录成功(附带token和用户信息)。" ++ + "建议轮询间隔2秒,超过5分钟未扫码会话自动失效。" ++ + "无需认证即可调用。") + @GetMapping("/wechat-qr/status") + public Result> checkWechatLoginStatus(@ApiParam("会话状态") @RequestParam String state, + HttpServletRequest httpRequest) { +@@ -178,7 +203,11 @@ public class AuthController { + return Result.success(data); + } + +- @ApiOperation("手动确认扫码(内网穿透环境workaround,默认关闭)") ++ @ApiOperation(value = "手动确认扫码(内网穿透环境workaround,默认关闭)", ++ notes = "在内网穿透环境下,企微回调可能无法正常到达,此接口作为手动替代方案。\n" ++ + "需在Nacos配置中开启 auth.2fa-confirm-enabled=true 才可使用。\n\n" ++ + "**权限**:无需认证(登录流程中使用)。\n" ++ + "**注意**:生产环境应保持关闭,仅限开发/测试时使用。") + @PostMapping("/2fa/confirm") + public Result confirm2FaScan(@ApiParam("会话状态") @RequestParam String state, + @ApiParam("管理员ID") @RequestParam String adminId, +@@ -195,7 +224,10 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("查询2FA扫码状态") ++ @ApiOperation(value = "查询2FA扫码状态", notes = "前端轮询此接口检查2FA扫码验证是否完成。" ++ + "返回status字段:PENDING=等待扫码,SCANNED=已完成验证(附带token和用户信息)。" ++ + "建议轮询间隔2秒,超过5分钟未扫码会话自动失效。" ++ + "无需认证即可调用(登录流程中使用)。") + @GetMapping("/2fa/check") + public Result> check2FaStatus(@ApiParam("会话状态") @RequestParam String state, + HttpServletRequest httpRequest) { +@@ -206,7 +238,10 @@ public class AuthController { + return Result.success(data); + } + +- @ApiOperation("切换当前角色") ++ @ApiOperation(value = "切换当前角色", notes = "多角色管理员切换当前活跃角色。" ++ + "切换后返回新的Token和角色对应的菜单权限,前端需更新本地Token并刷新菜单。" ++ + "只能切换到该管理员已分配的角色,否则报错。" ++ + "需要管理员认证。") + @OperationLog(value = "切换角色", module = "认证管理") + @PostMapping("/switch-role") + public Result switchRole(HttpServletRequest request, +@@ -216,7 +251,10 @@ public class AuthController { + return Result.success(response); + } + +- @ApiOperation("更新头像") ++ @ApiOperation(value = "更新头像", notes = "管理员更新自己的头像。" ++ + "需先通过文件服务上传图片获取OSS URL和fileId,再调用此接口绑定。" ++ + "旧头像的文件引用会自动解绑。" ++ + "需要管理员认证。") + @OperationLog(value = "更新头像", module = "认证管理") + @PutMapping("/avatar") + public Result updateAvatar(HttpServletRequest request, +@@ -226,7 +264,9 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("获取当前管理员信息") ++ @ApiOperation(value = "获取当前管理员信息", notes = "获取当前登录管理员的完整信息,包括用户名、头像、角色列表、当前角色、菜单权限等。" ++ + "前端页面初始化时调用此接口获取用户信息和权限数据。" ++ + "需要管理员认证。") + @GetMapping("/info") + public Result getAdminInfo(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java +index 0b374f0..79a06b4 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java +@@ -22,7 +22,12 @@ public class FavoriteController { + + private final FavoriteService favoriteService; + +- @ApiOperation("添加收藏") ++ @ApiOperation(value = "添加收藏", notes = "将指定资源添加到当前用户的收藏列表。" ++ + "同一用户对同一资源不可重复收藏,重复收藏会报错。" ++ + "targetType取值:SCENIC_SPOT/ACTIVITY/HOTEL/PRODUCT/EXPLORE等。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索(请求参数targetType)\n") + @PostMapping + public Result addFavorite(HttpServletRequest request, + @ApiParam("收藏请求") @Valid @RequestBody FavoriteRequest favoriteRequest) { +@@ -31,7 +36,11 @@ public class FavoriteController { + return Result.success(favorite); + } + +- @ApiOperation("收藏列表") ++ @ApiOperation(value = "收藏列表", notes = "分页查询当前用户的所有收藏记录,按收藏时间倒序排列。" ++ + "返回收藏记录的基础信息(不包含资源详情),需前端根据targetType和targetId再查详情。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):返回字段targetType,前端据此判断跳转到哪种资源详情页\n") + @GetMapping + public Result> listFavorites(HttpServletRequest request, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -41,7 +50,9 @@ public class FavoriteController { + return Result.success(result); + } + +- @ApiOperation("删除收藏") ++ @ApiOperation(value = "删除收藏", notes = "根据收藏记录ID取消收藏。" ++ + "只能删除自己的收藏记录,删除他人的收藏会报权限错误。" ++ + "需要小程序用户认证。") + @DeleteMapping("/{favoriteId}") + public Result deleteFavorite(HttpServletRequest request, + @ApiParam("收藏ID") @PathVariable Long favoriteId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java +index 2616fdc..a24102e 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java +@@ -22,7 +22,13 @@ public class FootprintController { + + private final FootprintService footprintService; + +- @ApiOperation("添加足迹") ++ @ApiOperation(value = "添加足迹", notes = "记录用户浏览资源的足迹。" ++ + "同一用户对同一资源多次浏览只保留最新一条记录(更新时间)。" ++ + "resourceType取值:SCENIC_SPOT/ACTIVITY/HOTEL/PRODUCT等。" ++ + "通常由前端在进入资源详情页时自动调用。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品(请求参数resourceType)\n") + @PostMapping + public Result addFootprint(HttpServletRequest request, + @ApiParam("足迹请求") @Valid @RequestBody FootprintRequest footprintRequest) { +@@ -31,7 +37,10 @@ public class FootprintController { + return Result.success(footprint); + } + +- @ApiOperation("足迹列表") ++ @ApiOperation(value = "足迹列表", notes = "分页查询当前用户的浏览足迹,按浏览时间倒序排列。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):返回字段resourceType,前端据此判断跳转到哪种资源详情页\n") + @GetMapping + public Result> listFootprints(HttpServletRequest request, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -41,7 +50,9 @@ public class FootprintController { + return Result.success(result); + } + +- @ApiOperation("删除足迹") ++ @ApiOperation(value = "删除足迹", notes = "根据足迹记录ID删除单条浏览足迹。" ++ + "只能删除自己的足迹记录。" ++ + "需要小程序用户认证。") + @DeleteMapping("/{footprintId}") + public Result deleteFootprint(HttpServletRequest request, + @ApiParam("足迹ID") @PathVariable Long footprintId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java +index 37a5069..bdd7f6d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java +@@ -22,7 +22,7 @@ import java.util.*; + * Called by other services via Feign (not exposed via gateway). + */ + @Slf4j +-@Api(tags = "【内部接口】审批(Feign调用)") ++@Api(tags = "【内部接口】审批(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/wechat") + @RequiredArgsConstructor +@@ -129,7 +129,11 @@ public class InternalApprovalController { + @Value("${approval.product.control-ids.reason:}") + private String controlIdProductReason; + +- @ApiOperation("Submit approval to enterprise WeChat OA") ++ @ApiOperation(value = "提交企业微信OA审批", notes = "内部接口,由其他服务通过Feign调用提交企微审批申请。" ++ + "根据templateId自动路由到对应的审批模板(资源上下架/产品上下架/退款申请/退款申诉)。" ++ + "需提供adminId(管理员提交)或wechatUserId(代理提交)。" ++ + "返回企微审批单号spNo,用于后续查询审批状态。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/submit-approval") + public Result submitApproval(@RequestBody ApprovalSubmitDTO dto) { + if (dto.getTemplateId() == null || dto.getTemplateId().isEmpty()) { +@@ -183,7 +187,10 @@ public class InternalApprovalController { + return Result.success(result); + } + +- @ApiOperation("Revoke a pending approval in enterprise WeChat OA") ++ @ApiOperation(value = "撤销企业微信OA审批", notes = "内部接口,撤销一个待审批的企微OA审批申请。" ++ + "仅PENDING状态的审批可以撤销,已审批的无法撤销。" ++ + "撤销失败不会抛异常(降级处理),业务侧需自行处理状态。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/revoke-approval/{spNo}") + public Result revokeApproval(@PathVariable String spNo) { + if (spNo == null || spNo.isEmpty()) { +@@ -200,7 +207,12 @@ public class InternalApprovalController { + return Result.success(); + } + +- @ApiOperation("Get approval status from enterprise WeChat OA") ++ @ApiOperation(value = "查询企业微信OA审批状态", notes = "内部接口,根据审批单号查询企微审批的详细状态。" ++ + "返回审批状态(spStatus:1=审批中 2=已通过 3=已驳回 4=已撤销)、申请人、表单数据等。" ++ + "用于审批轮询兜底方案(ApprovalPollingService)。" ++ + "不经过Gateway,仅服务间调用。" ++ + "\n\n**关联字典**:\n" ++ + "- approval_sp_status(审批状态):返回字段spStatus(1=审批中, 2=已通过, 3=已驳回, 4=已撤销)") + @GetMapping("/approval-status/{spNo}") + @SuppressWarnings("unchecked") + public Result> getApprovalStatus(@PathVariable String spNo) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java +index c2204f9..df482d7 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java +@@ -13,7 +13,7 @@ import java.util.Map; + * 徽章内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/badge") + @RequiredArgsConstructor +@@ -21,7 +21,10 @@ public class InternalBadgeController { + + private final BadgeService badgeService; + +- @ApiOperation("获取用户徽章数据") ++ @ApiOperation(value = "获取用户徽章数据", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取指定用户的各类未读数和待处理徽章数据(如未读消息数、待付款订单数等)。\n" ++ + "用于小程序个人中心页面的红点/数字徽章展示。") + @GetMapping + public Result> getUserBadgeData(@RequestParam Long userId) { + return Result.success(badgeService.getUserBadgeData(userId)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java +index 4df5705..b339c1f 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java +@@ -16,7 +16,7 @@ import java.util.List; + * Banner内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/banner") + @RequiredArgsConstructor +@@ -24,7 +24,9 @@ public class InternalBannerController { + + private final BannerService bannerService; + +- @ApiOperation("获取当前有效Banner列表") ++ @ApiOperation(value = "获取当前有效Banner列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取所有状态为启用的Banner列表,按排序号排列,用于小程序首页轮播展示。") + @GetMapping("/active") + public Result> listActiveBanners() { + return Result.success(bannerService.listActiveBanners()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java +index d38d4a3..dc412e7 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java +@@ -16,7 +16,7 @@ import java.util.List; + * 联系我们内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/contact") + @RequiredArgsConstructor +@@ -24,7 +24,10 @@ public class InternalContactController { + + private final ContactService contactService; + +- @ApiOperation("获取当前有效联系方式列表") ++ @ApiOperation(value = "获取当前有效联系方式列表", notes = "内部接口,获取所有状态为上线的联系方式。" ++ + "不经过Gateway,仅服务间调用。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):返回字段channelType(ABOUT=关于我们, ONLINE_CS=在线客服, PHONE=电话咨询)\n") + @GetMapping("/active") + public Result> listActiveContacts() { + return Result.success(contactService.listActiveContacts()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java +index 969a9d2..f96ec05 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java +@@ -14,7 +14,7 @@ import java.util.List; + * C端定制师内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/designer") + @RequiredArgsConstructor +@@ -22,20 +22,28 @@ public class InternalDesignerController { + + private final DesignerService designerService; + +- @ApiOperation("定制师列表") ++ @ApiOperation(value = "定制师列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "分页获取已上线的定制师列表,用于小程序定制师展示页面。\n" ++ + "返回定制师头像、昵称、认证等级、擅长领域等信息。") + @GetMapping + public Result> listDesigners(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int limit) { + return Result.success(designerService.listDesigners(page, limit)); + } + +- @ApiOperation("推荐定制师") ++ @ApiOperation(value = "推荐定制师", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取一位推荐定制师,用于小程序首页推荐位展示。\n" ++ + "推荐逻辑由后端按权重排序选取。") + @GetMapping("/featured") + public Result getFeaturedDesigner() { + return Result.success(designerService.getFeaturedDesigner()); + } + +- @ApiOperation("定制师详情") ++ @ApiOperation(value = "定制师详情", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取指定定制师的详细信息,包括个人简介、擅长领域、服务案例等。") + @GetMapping("/{id}") + public Result getDesignerDetail(@PathVariable Long id) { + return Result.success(designerService.getDesignerDetail(id)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java +index 1e7bf8d..02ea651 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java +@@ -26,7 +26,7 @@ import java.util.stream.Collectors; + * 探索分类内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "探索分类小程序接口") ++@Api(tags = "探索分类小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/explore") + @RequiredArgsConstructor +@@ -38,7 +38,10 @@ public class InternalExploreCategoryController { + private final FavoriteService favoriteService; + private final UserLikeService userLikeService; + +- @ApiOperation("获取上线探索分类列表") ++ @ApiOperation(value = "获取上线探索分类列表", notes = "内部接口,获取已上线的探索分类列表,支持排序。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):仅返回status=1(启用)的分类\n" ++ + "- explore_sort_type(排序方式):请求参数sortType(comprehensive=综合, newest=最新, hottest=最热)") + @GetMapping("/active") + public Result> listActive( + @ApiParam("排序方式:comprehensive=综合 newest=最新 hottest=最热") @RequestParam(defaultValue = "comprehensive") String sortType, +@@ -47,7 +50,10 @@ public class InternalExploreCategoryController { + return Result.success(exploreCategoryService.listActive(sortType, page, pageSize)); + } + +- @ApiOperation("获取探索分类详情(自动增加浏览量)") ++ @ApiOperation(value = "获取探索分类详情(自动增加浏览量)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取指定分类的详细信息,同时自动增加浏览量计数。\n" ++ + "如果传入 X-User-Id 请求头,还会返回当前用户的点赞和收藏状态。") + @GetMapping("/{id}") + public Result getActiveDetail( + @ApiParam("分类ID") @PathVariable Long id, +@@ -65,14 +71,19 @@ public class InternalExploreCategoryController { + return Result.success(exploreCategoryService.getActiveDetail(id, isLiked, isFavorited)); + } + +- @ApiOperation("增加浏览量") ++ @ApiOperation(value = "增加浏览量", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "手动增加指定探索分类的浏览量计数(+1)。") + @PostMapping("/{id}/view") + public Result incrementViewCount(@ApiParam("分类ID") @PathVariable Long id) { + exploreCategoryService.incrementViewCount(id); + return Result.success(); + } + +- @ApiOperation("切换收藏状态") ++ @ApiOperation(value = "切换收藏状态", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "切换用户对指定探索分类的收藏状态:已收藏则取消,未收藏则添加。\n" ++ + "返回 true=已收藏,false=已取消收藏。同时更新分类的收藏计数。") + @PostMapping("/{id}/favorite") + public Result toggleFavorite( + @ApiParam("分类ID") @PathVariable Long id, +@@ -101,7 +112,9 @@ public class InternalExploreCategoryController { + } + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "检查用户是否已收藏指定的探索分类,返回 true/false。") + @GetMapping("/{id}/favorite/check") + public Result checkFavorite( + @ApiParam("分类ID") @PathVariable Long id, +@@ -109,7 +122,10 @@ public class InternalExploreCategoryController { + return Result.success(favoriteService.checkFavorite(userId, TARGET_TYPE_EXPLORE, id)); + } + +- @ApiOperation("切换点赞状态") ++ @ApiOperation(value = "切换点赞状态", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "切换用户对指定探索分类的点赞状态:已点赞则取消,未点赞则添加。\n" ++ + "返回 true=已点赞,false=已取消。同时更新分类的点赞计数。") + @PostMapping("/{id}/like") + public Result toggleLike( + @ApiParam("分类ID") @PathVariable Long id, +@@ -119,7 +135,9 @@ public class InternalExploreCategoryController { + return Result.success(liked); + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "检查用户是否已点赞指定的探索分类,返回 true/false。") + @GetMapping("/{id}/like/check") + public Result checkLike( + @ApiParam("分类ID") @PathVariable Long id, +@@ -127,7 +145,10 @@ public class InternalExploreCategoryController { + return Result.success(userLikeService.checkLike(userId, TARGET_TYPE_EXPLORE, id)); + } + +- @ApiOperation("获取同分类的景区资源列表") ++ @ApiOperation(value = "获取同分类的景区资源列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据景区ID查找与其同一探索分类下的其他景区资源,用于'相关推荐'展示。\n" ++ + "返回资源ID、名称、描述、封面图等基本信息。") + @GetMapping("/related-scenic") + public Result>> getRelatedScenic( + @ApiParam("景区ID") @RequestParam Long scenicId, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java +index 90d24df..e00222c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController; + + import java.util.List; + +-@Api(tags = "【内部接口】常见问题(Feign调用)") ++@Api(tags = "【内部接口】常见问题(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/faq") + @RequiredArgsConstructor +@@ -20,7 +20,9 @@ public class InternalFaqController { + + private final FaqService faqService; + +- @ApiOperation("获取所有启用的FAQ(含分类和条目)") ++ @ApiOperation(value = "获取所有启用的FAQ(含分类和条目)", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "获取所有状态为启用的FAQ分类及其下属条目,按排序号排列。") + @GetMapping("/all") + public Result> getAllActiveFaq() { + return Result.success(faqService.getAllActiveFaq()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java +index 1f32c3b..4976f91 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java +@@ -14,7 +14,7 @@ import java.util.List; + * 前端配置内部接口(仅供其他服务通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】前端配置(Feign调用)") ++@Api(tags = "【内部接口】前端配置(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/frontend-config") + @RequiredArgsConstructor +@@ -22,32 +22,42 @@ public class InternalFrontendConfigController { + + private final FrontendConfigService frontendConfigService; + +- @ApiOperation("获取所有启用的前端配置") ++ @ApiOperation(value = "获取所有启用的前端配置", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "获取所有状态为启用的前端配置项列表(含敏感配置)。") + @GetMapping("/all") + public Result> listAllActiveConfigs() { + return Result.success(frontendConfigService.listAllActiveConfigs()); + } + +- @ApiOperation("按分组获取启用的配置") ++ @ApiOperation(value = "按分组获取启用的配置", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "按配置分组名获取该分组下所有已启用的配置项。") + @GetMapping("/group/{group}") + public Result> listActiveConfigsByGroup(@PathVariable String group) { + return Result.success(frontendConfigService.listActiveConfigsByGroup(group)); + } + +- @ApiOperation("按key获取单个配置") ++ @ApiOperation(value = "按key获取单个配置", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "根据 configKey 获取单个已启用的配置项,不存在则返回错误。") + @GetMapping("/key/{key}") + public Result getActiveConfigByKey(@PathVariable String key) { + FrontendConfigVO vo = frontendConfigService.getActiveConfigByKey(key); + return vo != null ? Result.success(vo) : Result.error("配置项不存在"); + } + +- @ApiOperation("获取所有非敏感的前端配置(供小程序使用)") ++ @ApiOperation(value = "获取所有非敏感的前端配置(供小程序使用)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取所有已启用且非敏感(sensitive=false)的配置项,安全地暴露给小程序C端。") + @GetMapping("/public") + public Result> listPublicConfigs() { + return Result.success(frontendConfigService.listPublicConfigs()); + } + +- @ApiOperation("按分组获取非敏感配置(供小程序使用)") ++ @ApiOperation(value = "按分组获取非敏感配置(供小程序使用)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "按分组获取非敏感配置,过滤掉标记为敏感的配置项。") + @GetMapping("/public/group/{group}") + public Result> listPublicConfigsByGroup(@PathVariable String group) { + return Result.success(frontendConfigService.listPublicConfigsByGroup(group)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java +index aba407f..a14b558 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java +@@ -14,7 +14,7 @@ import java.util.*; + * 通用点赞内部接口(供 hl-mp-service BFF 通过 Feign 调用) + * 支持任意资源类型:REVIEW, EXPLORE, GUIDE 等 + */ +-@Api(tags = "【内部接口】通用点赞(Feign调用)") ++@Api(tags = "【内部接口】通用点赞(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/like") + @RequiredArgsConstructor +@@ -22,7 +22,9 @@ public class InternalLikeController { + + private final UserLikeService userLikeService; + +- @ApiOperation("切换点赞状态(通用)") ++ @ApiOperation(value = "切换点赞状态(通用)", notes = "内部接口,切换用户对指定资源的点赞状态。" ++ + "\n\n**关联字典**:\n" ++ + "- like_target_type(点赞目标类型):请求参数targetType(REVIEW=评价, EXPLORE=探索, GUIDE=攻略)") + @PostMapping("/toggle") + public Result> toggleLike( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -36,7 +38,9 @@ public class InternalLikeController { + return Result.success(data); + } + +- @ApiOperation("检查是否已点赞(通用)") ++ @ApiOperation(value = "检查是否已点赞(通用)", notes = "内部接口,检查用户是否已点赞指定资源。" ++ + "\n\n**关联字典**:\n" ++ + "- like_target_type(点赞目标类型):请求参数targetType(REVIEW=评价, EXPLORE=探索, GUIDE=攻略)") + @GetMapping("/check") + public Result checkLike( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -45,7 +49,9 @@ public class InternalLikeController { + return Result.success(userLikeService.checkLike(userId, targetType, targetId)); + } + +- @ApiOperation("批量检查是否已点赞(接受字符串ID,避免JS大数精度丢失)") ++ @ApiOperation(value = "批量检查是否已点赞(接受字符串ID,避免JS大数精度丢失)", notes = "内部接口,批量检查用户是否已点赞指定资源列表。" ++ + "\n\n**关联字典**:\n" ++ + "- like_target_type(点赞目标类型):请求参数targetType(REVIEW=评价, EXPLORE=探索, GUIDE=攻略)") + @PostMapping("/batch-check") + public Result> batchCheckLiked( + @ApiParam("目标类型") @RequestParam String targetType, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java +index 124fb4f..179904b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java +@@ -24,7 +24,7 @@ import java.util.stream.Collectors; + * Internal endpoint for monitor-service to query login logs. + * NOT exposed via gateway. + */ +-@Api(tags = "【内部接口】登录日志(Feign调用)") ++@Api(tags = "【内部接口】登录日志(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal") + @RequiredArgsConstructor +@@ -35,7 +35,14 @@ public class InternalLoginLogController { + + private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + +- @ApiOperation("Query login logs") ++ @ApiOperation(value = "查询登录日志", notes = "内部接口,供hl-monitor-service通过Feign查询管理员登录日志。" ++ + "支持按管理员ID、登录状态、时间范围筛选。" ++ + "status取值:SUCCESS=登录成功 FAILED=登录失败。" ++ + "时间格式:yyyy-MM-dd HH:mm:ss。" ++ + "不经过Gateway,仅服务间调用。" ++ + "\n\n**关联字典**:\n" ++ + "- login_status(登录状态):请求参数status和返回字段status(SUCCESS=成功, FAILED=失败)\n" ++ + "- login_method(登录方式):返回字段loginMethod(PASSWORD=密码, WECHAT_QR=企微扫码, TWO_FA=二次验证)") + @GetMapping("/login-logs") + public Result> queryLoginLogs( + @RequestParam(defaultValue = "1") int page, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java +index a8f1de8..8e53118 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/common") + @RequiredArgsConstructor +@@ -19,19 +19,26 @@ public class InternalMpCommonController { + + private final CommonService commonService; + +- @ApiOperation("应用配置") ++ @ApiOperation(value = "应用配置", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "获取小程序应用的基础配置信息,如版本号、客服电话等。") + @GetMapping("/config") + public Result> getConfig() { + return Result.success(commonService.getConfig()); + } + +- @ApiOperation("FAQ列表") ++ @ApiOperation(value = "FAQ列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "获取所有启用的FAQ分类及其条目,用于小程序帮助中心页面展示。") + @GetMapping("/faq") + public Result>> listFaq() { + return Result.success(commonService.listFaq()); + } + +- @ApiOperation("提交反馈") ++ @ApiOperation(value = "提交反馈", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "提交用户反馈意见,包括反馈内容、联系方式等。\n" ++ + "需传入 userId 参数标识提交反馈的用户。") + @PostMapping("/feedback") + public Result submitFeedback(@RequestParam Long userId, + @RequestBody UserFeedback feedback) { +@@ -39,13 +46,18 @@ public class InternalMpCommonController { + return Result.success(null); + } + +- @ApiOperation("获取协议文本") ++ @ApiOperation(value = "获取协议文本", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "根据协议类型(如 user_agreement、privacy_policy)获取协议的富文本内容。\n" ++ + "用于小程序协议详情页面展示。") + @GetMapping("/agreement/{type}") + public Result> getAgreement(@PathVariable String type) { + return Result.success(commonService.getAgreement(type)); + } + +- @ApiOperation("获取所有已上线协议列表") ++ @ApiOperation(value = "获取所有已上线协议列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "获取所有状态为启用的协议列表,用于小程序注册/登录时展示需要同意的协议链接。") + @GetMapping("/agreement/list") + public Result>> listActiveAgreements() { + return Result.success(commonService.listActiveAgreements()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java +index e634ded..6028ac3 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java +@@ -19,7 +19,7 @@ import java.util.stream.Collectors; + * C端字典内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/dict") + @RequiredArgsConstructor +@@ -27,7 +27,9 @@ public class InternalMpDictController { + + private final SysDictService sysDictService; + +- @ApiOperation("获取所有字典数据(C端小程序)") ++ @ApiOperation(value = "获取所有字典数据(C端小程序)", notes = "内部接口,供hl-mp-service通过Feign获取小程序可用的字典数据。" ++ + "返回格式:[{dictType, dictName, dataList}],与管理端字典数据格式一致。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/all") + public Result>> getAllDict() { + List dictList = sysDictService.getAllDictForMiniApp(); +@@ -44,7 +46,8 @@ public class InternalMpDictController { + return Result.success(result); + } + +- @ApiOperation("按字典类型获取字典数据列表") ++ @ApiOperation(value = "按字典类型获取字典数据列表", notes = "内部接口,根据字典类型编码(如order_status)获取该类型下的所有字典数据项。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/type/{dictType}") + public Result> getDictDataByType( + @ApiParam("字典类型编码") @PathVariable String dictType) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java +index 4921435..f32737c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java +@@ -14,7 +14,7 @@ import java.util.HashMap; + import java.util.List; + import java.util.Map; + +-@Api(tags = "小程序消息接口") ++@Api(tags = "小程序消息接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/message") + @RequiredArgsConstructor +@@ -22,19 +22,32 @@ public class InternalMpMessageController { + + private final UserMessageService userMessageService; + +- @ApiOperation("消息分类列表(含未读数和最新消息预览)") ++ @ApiOperation(value = "消息分类列表(含未读数和最新消息预览)", notes = "获取用户的消息分类汇总信息。" ++ + "每个分类返回:分类名称、未读消息数、最新一条消息的标题和时间。" ++ + "用于消息中心首页展示各分类入口。" ++ + "内部接口,由hl-mp-service通过Feign调用。" ++ + "\n\n**关联字典**:\n" ++ + "- message_category(消息分类):返回字段code(ORDER=订单消息, TRIP=行程消息, SYSTEM=系统消息, PROMO=营销消息)") + @GetMapping("/categories") + public Result> getCategories(@RequestParam("userId") Long userId) { + return Result.success(userMessageService.getCategorySummaries(userId)); + } + +- @ApiOperation("消息摘要(兼容旧接口)") ++ @ApiOperation(value = "消息摘要(兼容旧接口)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "功能同 /categories 接口,保留用于向后兼容旧版本小程序。") + @GetMapping("/summary") + public Result> getSummary(@RequestParam("userId") Long userId) { + return Result.success(userMessageService.getCategorySummaries(userId)); + } + +- @ApiOperation("分类内消息列表(进入后自动标记已读)") ++ @ApiOperation(value = "分类内消息列表(进入后自动标记已读)", notes = "分页查询指定分类下的消息列表,按时间倒序排列。" ++ + "进入该分类后自动将该分类的所有消息标记为已读。" ++ + "categoryCode参数支持旧参数名category(向后兼容)。" ++ + "内部接口,由hl-mp-service通过Feign调用。" ++ + "\n\n**关联字典**:\n" ++ + "- message_category(消息分类):请求参数categoryCode(ORDER=订单消息, TRIP=行程消息, SYSTEM=系统消息, PROMO=营销消息)\n" ++ + "- message_biz_type(关联业务类型):返回字段bizType(ORDER=订单, REFUND=退款, CONTRACT=合同)") + @GetMapping("/list") + public Result> listMessages( + @RequestParam("userId") Long userId, +@@ -47,7 +60,9 @@ public class InternalMpMessageController { + return Result.success(userMessageService.listMessages(userId, code, page, pageSize)); + } + +- @ApiOperation("获取总未读数") ++ @ApiOperation(value = "获取总未读数", notes = "获取用户所有分类的未读消息总数。" ++ + "返回{count: N}格式,用于小程序Tab栏消息角标显示。" ++ + "内部接口,由hl-mp-service通过Feign调用。") + @GetMapping("/unread-count") + public Result> getUnreadCount(@RequestParam("userId") Long userId) { + Map result = new HashMap<>(); +@@ -55,7 +70,10 @@ public class InternalMpMessageController { + return Result.success(result); + } + +- @ApiOperation("全部标记已读") ++ @ApiOperation(value = "全部标记已读", notes = "将消息标记为已读。" ++ + "如果传入categoryCode,则只标记该分类下的消息为已读。" ++ + "如果不传categoryCode,则标记所有消息为已读。" ++ + "内部接口,由hl-mp-service通过Feign调用。") + @PutMapping("/read-all") + public Result markAllRead( + @RequestParam("userId") Long userId, +@@ -70,7 +88,9 @@ public class InternalMpMessageController { + return Result.success(null); + } + +- @ApiOperation("标记已读") ++ @ApiOperation(value = "标记已读", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "将单条消息标记为已读(兼容旧接口,实际已被分类级别标记替代)。") + @PutMapping("/{id}/read") + public Result markRead( + @RequestParam("userId") Long userId, +@@ -79,7 +99,9 @@ public class InternalMpMessageController { + return Result.success(null); + } + +- @ApiOperation("删除消息") ++ @ApiOperation(value = "删除消息", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "删除指定的用户消息记录,删除后不可恢复。") + @DeleteMapping("/{id}") + public Result deleteMessage( + @RequestParam("userId") Long userId, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java +index 69c0674..67190a9 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java +@@ -22,7 +22,7 @@ import java.util.Map; + * C端用户内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/user") + @RequiredArgsConstructor +@@ -37,26 +37,37 @@ public class InternalMpUserController { + + // ==================== Auth ==================== + +- @ApiOperation("发送短信验证码") ++ @ApiOperation(value = "发送短信验证码", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "向指定手机号发送6位数字短信验证码,有效期5分钟,60秒内不可重复发送。") + @PostMapping("/sms/send") + public Result sendSmsCode(@Valid @RequestBody SendSmsRequest request) { + smsService.sendVerificationCode(request.getPhone()); + return Result.success(); + } + +- @ApiOperation("短信登录") ++ @ApiOperation(value = "短信登录", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "小程序用户通过手机号+短信验证码登录,首次登录自动注册。\n" ++ + "返回JWT Token和用户基本信息。") + @PostMapping("/login/sms") + public Result loginBySms(@Valid @RequestBody SmsLoginRequest request) { + return Result.success(userService.loginBySms(request)); + } + +- @ApiOperation("微信登录") ++ @ApiOperation(value = "微信登录", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "小程序用户通过微信授权码(wx.login获取的code)登录,首次登录自动注册。\n" ++ + "返回JWT Token和用户基本信息,含 needProfile 字段标识是否需要补全资料。") + @PostMapping("/login") + public Result login(@Valid @RequestBody LoginRequest request) { + return Result.success(userService.login(request)); + } + +- @ApiOperation("获取用户信息") ++ @ApiOperation(value = "获取用户信息", notes = "内部接口,获取用户个人资料,含真实手机号。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType") + @GetMapping("/profile") + public Result getProfile(@RequestParam Long userId) { + UserVO vo = userService.getProfile(userId); +@@ -65,21 +76,31 @@ public class InternalMpUserController { + return Result.success(vo); + } + +- @ApiOperation("更新用户信息") ++ @ApiOperation(value = "更新用户信息", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "更新用户个人资料,包括昵称、头像、性别、实名信息等。\n" ++ + "首次补全资料时 realName/idCardType/idCardNo 为必填。\n\n" ++ + "**关联字典**:\n" ++ + "- gender(性别):请求字段gender\n" ++ + "- id_card_type(证件类型):请求字段idCardType") + @PutMapping("/profile") + public Result updateProfile(@RequestParam Long userId, + @Valid @RequestBody UpdateProfileRequest request) { + return Result.success(userService.updateProfile(userId, request)); + } + +- @ApiOperation("用户登出") ++ @ApiOperation(value = "用户登出", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "清除指定用户的登录状态,使Token失效。") + @PostMapping("/logout") + public Result logout(@RequestParam Long userId) { + userService.logout(userId); + return Result.success(); + } + +- @ApiOperation("注销账号") ++ @ApiOperation(value = "注销账号", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "永久注销用户账号(软删除),注销后该手机号可重新注册。") + @DeleteMapping("/account") + public Result deleteAccount(@RequestParam Long userId) { + userService.deleteAccount(userId); +@@ -88,14 +109,18 @@ public class InternalMpUserController { + + // ==================== Favorite ==================== + +- @ApiOperation("添加收藏") ++ @ApiOperation(value = "添加收藏", notes = "内部接口,为用户添加收藏。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索)") + @PostMapping("/favorite") + public Result addFavorite(@RequestParam Long userId, + @Valid @RequestBody FavoriteRequest request) { + return Result.success(favoriteService.addFavorite(userId, request)); + } + +- @ApiOperation("收藏列表") ++ @ApiOperation(value = "收藏列表", notes = "内部接口,获取用户收藏列表。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType和返回字段targetType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索)") + @GetMapping("/favorite") + public Result> listFavorites(@RequestParam Long userId, + @RequestParam(required = false) String targetType, +@@ -104,7 +129,9 @@ public class InternalMpUserController { + return Result.success(favoriteService.listFavorites(userId, targetType, page, pageSize)); + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", notes = "内部接口,检查用户是否已收藏指定资源。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType") + @GetMapping("/favorite/check") + public Result checkFavorite(@RequestParam Long userId, + @RequestParam String targetType, +@@ -112,7 +139,9 @@ public class InternalMpUserController { + return Result.success(favoriteService.checkFavorite(userId, targetType, targetId)); + } + +- @ApiOperation("批量删除收藏") ++ @ApiOperation(value = "批量删除收藏", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据收藏记录ID列表批量删除用户的收藏记录。") + @DeleteMapping("/favorite/batch") + public Result batchDeleteFavorites(@RequestParam Long userId, + @RequestBody List ids) { +@@ -120,7 +149,9 @@ public class InternalMpUserController { + return Result.success(); + } + +- @ApiOperation("按目标取消收藏") ++ @ApiOperation(value = "按目标取消收藏", notes = "内部接口,按目标类型和ID取消收藏。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType") + @DeleteMapping("/favorite/by-target") + public Result deleteFavoriteByTarget(@RequestParam Long userId, + @RequestParam String targetType, +@@ -129,7 +160,9 @@ public class InternalMpUserController { + return Result.success(); + } + +- @ApiOperation("取消收藏") ++ @ApiOperation(value = "取消收藏", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据收藏记录ID删除单条收藏记录。") + @DeleteMapping("/favorite/{id}") + public Result deleteFavorite(@RequestParam Long userId, @PathVariable Long id) { + favoriteService.deleteFavorite(userId, id); +@@ -138,14 +171,18 @@ public class InternalMpUserController { + + // ==================== Footprint ==================== + +- @ApiOperation("记录足迹") ++ @ApiOperation(value = "记录足迹", notes = "内部接口,记录用户浏览足迹。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):请求参数resourceType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品)") + @PostMapping("/footprint") + public Result addFootprint(@RequestParam Long userId, + @Valid @RequestBody FootprintRequest request) { + return Result.success(footprintService.addFootprint(userId, request)); + } + +- @ApiOperation("足迹列表") ++ @ApiOperation(value = "足迹列表", notes = "内部接口,获取用户足迹列表。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):请求参数resourceType和返回字段resourceType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品)") + @GetMapping("/footprint") + public Result> listFootprints(@RequestParam Long userId, + @RequestParam(required = false) String resourceType, +@@ -154,7 +191,9 @@ public class InternalMpUserController { + return Result.success(footprintService.listFootprints(userId, resourceType, page, pageSize)); + } + +- @ApiOperation("批量删除足迹") ++ @ApiOperation(value = "批量删除足迹", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据足迹记录ID列表批量删除用户的浏览足迹。") + @DeleteMapping("/footprint/batch") + public Result batchDeleteFootprints(@RequestParam Long userId, + @RequestBody List ids) { +@@ -162,7 +201,9 @@ public class InternalMpUserController { + return Result.success(); + } + +- @ApiOperation("删除足迹") ++ @ApiOperation(value = "删除足迹", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据足迹记录ID删除单条浏览足迹。") + @DeleteMapping("/footprint/{id}") + public Result deleteFootprint(@RequestParam Long userId, @PathVariable Long id) { + footprintService.deleteFootprint(userId, id); +@@ -171,26 +212,45 @@ public class InternalMpUserController { + +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java +index df5bc72..581cc22 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java +@@ -17,7 +17,7 @@ import java.util.Map; + /** + * Internal API for order service + */ +-@Api(tags = "【内部接口】订单用户(Feign调用)") ++@Api(tags = "【内部接口】订单用户(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order/user") + @RequiredArgsConstructor +@@ -25,7 +25,10 @@ public class InternalOrderUserController { + + private final UserService userService; + +- @ApiOperation("获取用户基本信息(供订单服务查询使用)") ++ @ApiOperation(value = "获取用户基本信息(供订单服务查询使用)", ++ notes = "内部服务间调用接口,由 hl-order-service 通过 Feign 调用。\n" ++ + "根据 userId 获取用户基本信息(userId、realName、phone),用于订单详情展示。\n" ++ + "**注意**:返回的手机号为真实手机号(未脱敏)。") + @GetMapping("/info") + public Result> getUserInfo(@RequestParam Long userId) { + User user = userService.getById(userId); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java +index fba4363..e432e26 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java +@@ -16,7 +16,7 @@ import java.util.List; + * 探索专题内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/topic") + @RequiredArgsConstructor +@@ -24,7 +24,9 @@ public class InternalTopicController { + + private final TopicService topicService; + +- @ApiOperation("获取当前有效专题列表") ++ @ApiOperation(value = "获取当前有效专题列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取所有状态为启用的探索专题列表,按排序号排列,用于小程序探索页面展示。") + @GetMapping("/active") + public Result> listActiveTopics() { + return Result.success(topicService.listActiveTopics()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java +index 6e38f29..d41fb78 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java +@@ -29,7 +29,7 @@ import java.util.*; + import java.util.stream.Collectors; + + @Slf4j +-@Api(tags = "【内部接口】用户信息(Feign调用)") ++@Api(tags = "【内部接口】用户信息(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/user") + @RequiredArgsConstructor +@@ -44,7 +44,8 @@ public class InternalUserController { + private final WechatMiniAppClient wechatMiniAppClient; + private final UserService userService; + +- @ApiOperation("Get admin basic info by ID") ++ @ApiOperation(value = "根据ID获取管理员基本信息", notes = "内部接口,供其他服务通过Feign查询管理员基础信息(ID、用户名、头像、企微姓名)。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/admin/info/{adminId}") + public Result getAdminInfo(@PathVariable Long adminId) { + AdminUser admin = adminUserMapper.selectById(adminId); +@@ -55,7 +56,9 @@ public class InternalUserController { + return Result.success(toBasicDTO(admin, wechatNameMap)); + } + +- @ApiOperation("Batch get admin basic info") ++ @ApiOperation(value = "批量获取管理员基本信息", notes = "内部接口,批量查询多个管理员的基础信息。" ++ + "传入adminId列表,返回对应的管理员信息列表。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/admin/batch-info") + public Result> batchGetAdminInfo(@RequestBody List adminIds) { + if (adminIds == null || adminIds.isEmpty()) { +@@ -69,7 +72,9 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Get all departments") ++ @ApiOperation(value = "获取所有部门列表", notes = "内部接口,获取企业微信同步的所有部门数据。" ++ + "用于通知规则配置等场景中的部门选择。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/departments") + public Result> getDepartments() { + List depts = wechatDepartmentMapper.selectList(null); +@@ -85,7 +90,10 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Get admin IDs belonging to a department") ++ @ApiOperation(value = "获取部门下的管理员ID列表", notes = "内部接口,查询指定部门下所有活跃管理员的ID。" ++ + "通过企微用户的部门归属关联到管理员账号。" ++ + "用于通知规则引擎按部门发送通知。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/admin/dept-members/{deptId}") + public Result> getDeptAdminIds(@PathVariable Long deptId) { + // Find wechat users in this department using FIND_IN_SET for exact match +@@ -113,7 +121,9 @@ public class InternalUserController { + return Result.success(adminIds); + } + +- @ApiOperation("Get admins by role key") ++ @ApiOperation(value = "根据角色标识获取管理员列表", notes = "内部接口,根据角色标识(如CUSTOMIZER、FINANCE等)查询该角色下所有活跃管理员。" ++ + "用于通知规则引擎按角色发送通知。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/admin/by-role-key") + public Result> getAdminsByRoleKey(@RequestParam String roleKey) { + if (roleKey == null || roleKey.isBlank()) { +@@ -148,7 +158,10 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Find C-end user ID by phone number") ++ @ApiOperation(value = "根据手机号查找C端用户ID", notes = "内部接口,根据手机号查找活跃的小程序用户。" ++ + "用于订单绑定流程中通过联系人手机号匹配用户。" ++ + "找不到时返回null(不报错)。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/find-by-phone") + public Result findUserByPhone(@RequestParam String phone) { + if (phone == null || phone.isBlank()) { +@@ -162,7 +175,9 @@ public class InternalUserController { + return Result.success(user != null ? user.getUserId() : null); + } + +- @ApiOperation("Generate mini program URL Link for sharing") ++ @ApiOperation(value = "生成小程序URL Link", notes = "内部接口,生成小程序短链接用于分享。" ++ + "通过微信API生成URL Link,可在浏览器/短信中打开小程序指定页面。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/wechat/miniapp/generate-url-link") + public Result> generateUrlLink( + @RequestParam String path, @RequestParam String query) { +@@ -170,7 +185,10 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Send WeChat message to users") ++ @ApiOperation(value = "发送企业微信消息", notes = "内部接口,向指定的企微用户发送文本消息。" ++ + "toUserIds为企微用户ID列表,支持一次发送给多人。" ++ + "用于审批通知、订单提醒等场景。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/wechat/send-message") + public Result sendWechatMessage(@RequestBody WechatMessageDTO dto) { + if (dto.getToUserIds() == null || dto.getToUserIds().isEmpty()) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java +index e0d5a6d..d192b76 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java +@@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.*; + * No JWT auth required (excluded from TokenInterceptor via /internal/** pattern). + */ + @Slf4j +-@Api(tags = "【内部接口】企微同步(Feign调用)") ++@Api(tags = "【内部接口】企微同步(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/wechat") + @RequiredArgsConstructor +@@ -27,9 +27,11 @@ public class InternalWechatController { + private final WechatSyncService wechatSyncService; + private final ExternalContactNotifyService externalContactNotifyService; + +- @ApiOperation("Sync single user from callback") ++ @ApiOperation(value = "同步单个企微用户(回调触发)", notes = "内部接口,由hl-callback-service在收到企微通讯录变更回调时调用。" ++ + "将单个用户的信息同步到本地wechat_user表。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/user/sync") +- public Result syncUser(@RequestBody WechatUserSyncDTO dto) { ++ public Result syncUser(@RequestBody WechatUserSyncDTO dto) { + log.info("Internal: sync user userid={}", dto.getUserid()); + try { + wechatSyncService.syncSingleUserFromDto(dto); +@@ -40,9 +42,11 @@ public class InternalWechatController { + } + } + +- @ApiOperation("Delete single user from callback") ++ @ApiOperation(value = "删除单个企微用户(回调触发)", notes = "内部接口,由hl-callback-service在收到企微成员离职回调时调用。" ++ + "从本地wechat_user表中删除该用户记录。" ++ + "不经过Gateway,仅服务间调用。") + @DeleteMapping("/user/{userid}") +- public Result deleteUser(@PathVariable("userid") String userid) { ++ public Result deleteUser(@PathVariable("userid") String userid) { + log.info("Internal: delete user userid={}", userid); + try { + wechatSyncService.deleteSingleUser(userid); +@@ -53,9 +57,11 @@ public class InternalWechatController { + } + } + +- @ApiOperation("Sync single department from callback") ++ @ApiOperation(value = "同步单个企微部门(回调触发)", notes = "内部接口,由hl-callback-service在收到企微部门变更回调时调用。" ++ + "将单个部门的信息同步到本地wechat_department表。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/department/sync") +- public Result syncDepartment(@RequestBody WechatDeptSyncDTO dto) { ++ public Result syncDepartment(@RequestBody WechatDeptSyncDTO dto) { + log.info("Internal: sync department deptId={}", dto.getId()); + try { + wechatSyncService.syncSingleDepartmentFromDto(dto); +@@ -66,18 +72,22 @@ public class InternalWechatController { + } + } + +- @ApiOperation("Receive external contact change event") ++ @ApiOperation(value = "接收外部联系人变更事件", notes = "内部接口,由hl-callback-service在收到企微外部联系人变更回调时调用。" ++ + "处理客户添加/删除等事件,异步执行通知逻辑。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/external-contact/event") +- public Result handleExternalContactEvent(@RequestBody ExternalContactEventDTO dto) { ++ public Result handleExternalContactEvent(@RequestBody ExternalContactEventDTO dto) { + log.info("Internal: external contact event changeType={}, userId={}, externalUserId={}", + dto.getChangeType(), dto.getUserId(), dto.getExternalUserId()); + externalContactNotifyService.processEventAsync(dto); + return Result.success(); + } + +- @ApiOperation("Delete single department from callback") ++ @ApiOperation(value = "删除单个企微部门(回调触发)", notes = "内部接口,由hl-callback-service在收到企微部门删除回调时调用。" ++ + "从本地wechat_department表中删除该部门记录。" ++ + "不经过Gateway,仅服务间调用。") + @DeleteMapping("/department/{deptId}") +- public Result deleteDepartment(@PathVariable("deptId") Long deptId) { ++ public Result deleteDepartment(@PathVariable("deptId") Long deptId) { + log.info("Internal: delete department deptId={}", deptId); + try { + wechatSyncService.deleteSingleDepartment(deptId); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java +index 44641ef..e3cf403 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java +@@ -15,7 +15,7 @@ import java.util.Map; + * 祈愿内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/wish") + @RequiredArgsConstructor +@@ -23,13 +23,17 @@ public class InternalWishController { + + private final WishService wishService; + +- @ApiOperation("获取用户祈愿列表") ++ @ApiOperation(value = "获取用户祈愿列表", notes = "内部接口,获取用户的祈愿列表。" ++ + "\n\n**关联字典**:\n" ++ + "- wish_type(心愿类型):返回字段wishType(1=想去的地方, 2=想做的事, 3=其他)") + @GetMapping + public Result> listWishes(@RequestParam Long userId) { + return Result.success(wishService.listWishes(userId)); + } + +- @ApiOperation("创建祈愿") ++ @ApiOperation(value = "创建祈愿", notes = "内部接口,创建用户祈愿。" ++ + "\n\n**关联字典**:\n" ++ + "- wish_type(心愿类型):请求参数wishType(1=想去的地方, 2=想做的事, 3=其他)") + @PostMapping + public Result createWish(@RequestParam Long userId, + @RequestBody Map request) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java +index 5acc247..753577c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java +@@ -24,7 +24,7 @@ import java.util.Map; + @RestController + @RequestMapping("/oa/callback") + @RequiredArgsConstructor +-@Api(tags = "【回调接口】公众号回调") ++@Api(tags = "【回调接口】公众号回调", hidden = true) + public class OfficialAccountCallbackController { + + private final WechatOfficialAccountClient oaClient; +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java +index 6d1ec31..38f0ad6 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java +@@ -24,7 +24,12 @@ public class PublicDictController { + + private final SysDictService sysDictService; + +- @ApiOperation("获取所有字典数据") ++ @ApiOperation(value = "获取所有字典数据(公开接口)", notes = "获取系统全部字典类型及其字典数据,供小程序C端使用。" ++ + "无需认证即可调用。返回格式与管理端 /admin/dict/all 一致。" ++ + "\n\n**字典层级说明**:\n" ++ + "- 每个元素包含 dictType(编码)、dictName(名称)、dataList(字典数据列表)\n" ++ + "- 前端通过 dictType 匹配业务字段,用 dataList 中的 dictValue/dictLabel 做翻译展示\n" ++ + "- 常用字典:order_status、product_status、id_card_type、gender、traveler_type、favorite_resource_type、footprint_resource_type\n") + @GetMapping("/all") + public Result> getAllDict() { + return Result.success(sysDictService.getAllDictForPublic()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java +index 5be6ee7..260eadd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java +@@ -26,7 +26,14 @@ public class SysDictController { + + // ======================== All Dict ======================== + +- @ApiOperation("获取所有字典数据") ++ @ApiOperation(value = "获取所有字典数据", notes = "获取系统全部字典类型及其字典数据,按字典类型分组返回。" ++ + "用于后台管理系统初始化时一次性加载所有下拉选项。" ++ + "返回结果包含dictType编码、dictName名称、dataList数据列表。" ++ + "需要管理员认证。" ++ + "\n\n**字典层级说明**:\n" ++ + "- 字典类型(SysDictType):一级分类,如 admin_status、order_status、id_card_type 等\n" ++ + "- 字典数据(SysDictData):二级选项,归属于某个字典类型,如 admin_status 下的 ACTIVE/LOCKED/DISABLED\n" ++ + "- 前端通过 dictType 编码查找对应的 dataList,用 dictValue 匹配实际数据进行翻译展示\n") + @GetMapping("/all") + public Result> getAllDict() { + return Result.success(sysDictService.getAllDictForPublic()); +@@ -34,14 +41,21 @@ public class SysDictController { + + // ======================== Dict Type ======================== + +- @ApiOperation("创建字典类型") ++ @ApiOperation(value = "创建字典类型", notes = "新建一个字典类型(如:订单状态、证件类型等)。" ++ + "字典类型编码(dictType)全局唯一,创建后不可修改。" ++ + "需要管理员认证,建议仅SUPER_ADMIN/ADMIN角色操作。" ++ + "\n\n**已有字典类型示例**:\n" ++ + "- admin_status(管理员状态)、common_status(通用状态)、login_status(登录状态)\n" ++ + "- order_status(订单状态)、product_status(产品状态)、rating_level(评价等级)\n" ++ + "- id_card_type(证件类型)、gender(性别)、traveler_type(出行人类型)\n" ++ + "- contact_channel_type(联系方式渠道类型)、favorite_resource_type(收藏资源类型)、footprint_resource_type(足迹资源类型)\n") + @OperationLog(value = "创建字典类型", module = "字典管理") + @PostMapping("/type") + public Result createDictType(@ApiParam("创建字典类型请求") @Valid @RequestBody CreateDictTypeRequest request) { + return Result.success(sysDictService.createDictType(request)); + } + +- @ApiOperation("更新字典类型") ++ @ApiOperation(value = "更新字典类型", notes = "更新字典类型的名称、分类、备注等信息。字典类型编码(dictType)不可修改。") + @OperationLog(value = "更新字典类型", module = "字典管理") + @PutMapping("/type/{id}") + public Result updateDictType(@ApiParam("字典类型ID") @PathVariable Long id, +@@ -49,7 +63,9 @@ public class SysDictController { + return Result.success(sysDictService.updateDictType(id, request)); + } + +- @ApiOperation("删除字典类型") ++ @ApiOperation(value = "删除字典类型", notes = "删除字典类型及其下所有字典数据(软删除)。" ++ + "如果该字典类型已被业务引用,删除后不影响已有数据,但新的表单将无法选择该字典值。" ++ + "需要管理员认证。") + @OperationLog(value = "删除字典类型", module = "字典管理") + @DeleteMapping("/type/{id}") + public Result deleteDictType(@ApiParam("字典类型ID") @PathVariable Long id) { +@@ -57,7 +73,8 @@ public class SysDictController { + return Result.success(); + } + +- @ApiOperation("分页查询字典类型") ++ @ApiOperation(value = "分页查询字典类型", notes = "分页查询字典类型列表,支持按分类(category)筛选。" ++ + "字典类型是字典数据的上级分组,管理字典类型即管理有哪些可供前端使用的下拉选项组。") + @GetMapping("/type") + public Result> listDictTypes( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -66,7 +83,7 @@ public class SysDictController { + return Result.success(sysDictService.listDictTypes(page, pageSize, category)); + } + +- @ApiOperation("根据ID获取字典类型详情") ++ @ApiOperation(value = "根据ID获取字典类型详情", notes = "获取单个字典类型的详细信息,包括编码、名称、分类、状态等。") + @GetMapping("/type/{dictTypeId}") + public Result getDictTypeById(@ApiParam("字典类型ID") @PathVariable Long dictTypeId) { + return Result.success(sysDictService.getDictTypeById(dictTypeId)); +@@ -74,14 +91,16 @@ public class SysDictController { + + // ======================== Dict Data ======================== + +- @ApiOperation("创建字典数据") ++ @ApiOperation(value = "创建字典数据", notes = "在指定字典类型下新增一条字典数据项。" ++ + "dictValue为前端匹配的值(如ACTIVE),dictLabel为前端展示的标签(如'启用')。" ++ + "支持树形字典数据(通过parentId设置父级)。") + @OperationLog(value = "创建字典数据", module = "字典管理") + @PostMapping("/data") + public Result createDictData(@ApiParam("创建字典数据请求") @Valid @RequestBody CreateDictDataRequest request) { + return Result.success(sysDictService.createDictData(request)); + } + +- @ApiOperation("更新字典数据") ++ @ApiOperation(value = "更新字典数据", notes = "更新字典数据项的标签、样式类型、排序号等。dictValue建议不修改以免影响已有业务数据。") + @OperationLog(value = "更新字典数据", module = "字典管理") + @PutMapping("/data/{id}") + public Result updateDictData(@ApiParam("字典数据ID") @PathVariable Long id, +@@ -89,7 +108,7 @@ public class SysDictController { + return Result.success(sysDictService.updateDictData(id, request)); + } + +- @ApiOperation("删除字典数据") ++ @ApiOperation(value = "删除字典数据", notes = "删除指定字典数据项(软删除)。删除后不影响已引用该字典值的业务数据。") + @OperationLog(value = "删除字典数据", module = "字典管理") + @DeleteMapping("/data/{id}") + public Result deleteDictData(@ApiParam("字典数据ID") @PathVariable Long id) { +@@ -97,19 +116,23 @@ public class SysDictController { + return Result.success(); + } + +- @ApiOperation("根据ID获取字典数据详情") ++ @ApiOperation(value = "根据ID获取字典数据详情", notes = "获取单个字典数据项的详细信息,包括dictValue、dictLabel、cssClass等。") + @GetMapping("/data/detail/{dictDataId}") + public Result getDictDataById(@ApiParam("字典数据ID") @PathVariable Long dictDataId) { + return Result.success(sysDictService.getDictDataById(dictDataId)); + } + +- @ApiOperation("按类型查询字典数据(树形结构)") ++ @ApiOperation(value = "按类型查询字典数据(树形结构)", notes = "根据字典类型ID查询其下所有字典数据,以树形结构返回(支持父子级字典数据)。" ++ + "用于多级联动下拉框场景(如省市区)。" ++ + "需要管理员认证。") + @GetMapping("/data/tree/{dictTypeId}") + public Result> getDictDataTree(@ApiParam("字典类型ID") @PathVariable Long dictTypeId) { + return Result.success(sysDictService.getDictDataTree(dictTypeId)); + } + +- @ApiOperation("按类型查询字典数据") ++ @ApiOperation(value = "按类型查询字典数据", notes = "根据字典类型编码(如order_status)查询其下所有字典数据(平铺列表)。" ++ + "用于单层下拉框场景。" ++ + "需要管理员认证。") + @GetMapping("/data/{dictType}") + public Result> getDictDataByType(@ApiParam("字典类型编码") @PathVariable String dictType) { + return Result.success(sysDictService.getDictDataByType(dictType)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java +index 22b99cb..d58905e 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java +@@ -5,9 +5,9 @@ import com.hulalv.common.result.PageResult; + import com.hulalv.common.result.Result; + import com.hulalv.user.dto.CreateJobRequest; + import com.hulalv.user.dto.UpdateJobRequest; +-import com.hulalv.user.entity.SysJob; +-import com.hulalv.user.entity.SysJobLog; + import com.hulalv.user.service.SysJobService; ++import com.hulalv.user.vo.SysJobLogVO; ++import com.hulalv.user.vo.SysJobVO; + import io.swagger.annotations.Api; + import io.swagger.annotations.ApiOperation; + import io.swagger.annotations.ApiParam; +@@ -24,22 +24,39 @@ public class SysJobController { + + private final SysJobService sysJobService; + +- @ApiOperation("创建定时任务") ++ @ApiOperation(value = "创建定时任务", notes = "创建新的定时任务。" ++ + "invokeTarget格式为'Bean名称.方法名'(如wechatSyncService.syncAll),方法必须是无参公开方法。" ++ + "cronExpression为标准6位Cron表达式(秒 分 时 日 月 周)。" ++ + "创建后任务默认为暂停状态(PAUSED),需手动调用[恢复任务]接口启用。" ++ + "\n\n**关联字典**:\n" ++ + "- job_group(任务分组):DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步\n" ++ + "- job_misfire_policy(执行策略):DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发\n" ++ + "- job_status(任务状态):ACTIVE=启用, PAUSED=已暂停\n\n" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "创建定时任务", module = "定时任务") + @PostMapping +- public Result createJob(@ApiParam("创建定时任务请求") @Valid @RequestBody CreateJobRequest request) { ++ public Result createJob(@ApiParam("创建定时任务请求") @Valid @RequestBody CreateJobRequest request) { + return Result.success(sysJobService.createJob(request)); + } + +- @ApiOperation("更新定时任务") ++ @ApiOperation(value = "更新定时任务", ++ notes = "更新指定定时任务的名称、Cron表达式、调用目标等信息。\n" ++ + "修改Cron表达式后任务将按新的计划执行。\n\n" ++ + "**关联字典**:\n" ++ + "- job_group(任务分组):DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步\n" ++ + "- job_misfire_policy(执行策略):DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。") + @OperationLog(value = "更新定时任务", module = "定时任务") + @PutMapping("/{jobId}") +- public Result updateJob(@ApiParam("定时任务ID") @PathVariable Long jobId, ++ public Result updateJob(@ApiParam("定时任务ID") @PathVariable Long jobId, + @ApiParam("更新定时任务请求") @Valid @RequestBody UpdateJobRequest request) { + return Result.success(sysJobService.updateJob(jobId, request)); + } + +- @ApiOperation("删除定时任务") ++ @ApiOperation(value = "删除定时任务", ++ notes = "删除指定的定时任务(软删除),同时从调度器中移除该任务。\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。\n" ++ + "**注意**:删除后任务将不再执行,但历史执行日志仍可查看。") + @OperationLog(value = "删除定时任务", module = "定时任务") + @DeleteMapping("/{jobId}") + public Result deleteJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -47,15 +64,22 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("分页查询定时任务") ++ @ApiOperation(value = "分页查询定时任务", notes = "分页查询定时任务列表。" ++ + "\n\n**关联字典**:\n" ++ + "- job_group(任务分组):DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步\n" ++ + "- job_misfire_policy(执行策略):DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发\n" ++ + "- job_status(任务状态):ACTIVE=启用, PAUSED=已暂停") + @GetMapping +- public Result> listJobs( ++ public Result> listJobs( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, + @ApiParam("每页条数") @RequestParam(defaultValue = "20") int pageSize) { + return Result.success(sysJobService.listJobs(page, pageSize)); + } + +- @ApiOperation("暂停任务") ++ @ApiOperation(value = "暂停任务", notes = "暂停指定的定时任务,任务状态变为PAUSED。" ++ + "暂停后任务不再按Cron计划执行,但可通过[恢复任务]接口重新启用。" ++ + "\n\n**关联字典**:job_status(任务状态):ACTIVE=启用, PAUSED=已暂停\n\n" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "暂停任务", module = "定时任务") + @PostMapping("/{jobId}/pause") + public Result pauseJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -63,7 +87,10 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("恢复任务") ++ @ApiOperation(value = "恢复任务", notes = "恢复已暂停的定时任务,任务状态变为ACTIVE。" ++ + "恢复后任务按Cron计划继续执行。" ++ + "\n\n**关联字典**:job_status(任务状态):ACTIVE=启用, PAUSED=已暂停\n\n" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "恢复任务", module = "定时任务") + @PostMapping("/{jobId}/resume") + public Result resumeJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -71,7 +98,10 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("立即执行一次") ++ @ApiOperation(value = "立即执行一次", notes = "立即触发一次定时任务的执行,不影响原有的Cron计划。" ++ + "无论任务当前状态是ACTIVE还是PAUSED,都可以手动触发。" ++ + "执行结果可在任务日志中查看。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "立即执行任务", module = "定时任务") + @PostMapping("/{jobId}/trigger") + public Result triggerJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -79,9 +109,12 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("查询任务日志") ++ @ApiOperation(value = "查询任务日志", notes = "分页查询指定定时任务的执行日志,按执行时间倒序排列。" ++ + "日志包含执行状态(成功/失败)、执行耗时、异常信息等。" ++ + "\n\n**关联字典**:job_log_status(日志状态):SUCCESS=成功, FAIL=失败\n\n" ++ + "需要管理员认证。") + @GetMapping("/{jobId}/logs") +- public Result> listJobLogs( ++ public Result> listJobLogs( + @ApiParam("定时任务ID") @PathVariable Long jobId, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, + @ApiParam("每页条数") @RequestParam(defaultValue = "20") int pageSize) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java +index 46e8615..44e4293 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java +@@ -24,14 +24,27 @@ public class SysMenuController { + + private final SysMenuService sysMenuService; + +- @ApiOperation("创建菜单") ++ @ApiOperation(value = "创建菜单", notes = "创建新的菜单/目录/按钮。" ++ + "menuType取值:DIRECTORY=目录(含子菜单) MENU=页面菜单 BUTTON=操作按钮。" ++ + "目录和菜单需设置path路由路径,菜单还需设置component组件路径。" ++ + "按钮类型需设置permissionCode权限标识(如system:user:add)。" ++ + "需要SUPER_ADMIN角色。" ++ + "\n\n**关联字典**:\n" ++ + "- menu_type(菜单类型):请求/返回字段menuType(DIRECTORY=目录, MENU=菜单, BUTTON=按钮)\n" ++ + "- common_status(通用状态):返回字段status") + @OperationLog(value = "创建菜单", module = "菜单管理") + @PostMapping + public Result createMenu(@ApiParam("创建菜单请求") @Valid @RequestBody CreateMenuRequest request) { + return Result.success(sysMenuService.createMenu(request)); + } + +- @ApiOperation("更新菜单") ++ @ApiOperation(value = "更新菜单", ++ notes = "更新指定菜单的名称、路径、组件、图标、排序、状态等信息。\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。\n" ++ + "**注意**:修改后需清除 Redis 菜单缓存才能生效。\n\n" ++ + "**关联字典**:\n" ++ + "- menu_type(菜单类型):请求字段menuType(DIRECTORY=目录, MENU=菜单, BUTTON=按钮)\n" ++ + "- common_status(通用状态):请求字段status") + @OperationLog(value = "更新菜单", module = "菜单管理") + @PutMapping("/{menuId}") + public Result updateMenu(@ApiParam("菜单ID") @PathVariable Long menuId, +@@ -39,7 +52,11 @@ public class SysMenuController { + return Result.success(sysMenuService.updateMenu(menuId, request)); + } + +- @ApiOperation("删除菜单") ++ @ApiOperation(value = "删除菜单", ++ notes = "删除指定的菜单/目录/按钮(软删除)。\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。\n" ++ + "**注意**:如果该菜单有子菜单,需先删除子菜单才能删除父菜单。" ++ + "删除后需清除 Redis 菜单缓存才能生效。") + @OperationLog(value = "删除菜单", module = "菜单管理") + @DeleteMapping("/{menuId}") + public Result deleteMenu(@ApiParam("菜单ID") @PathVariable Long menuId) { +@@ -47,25 +64,42 @@ public class SysMenuController { + return Result.success(); + } + +- @ApiOperation("获取菜单详情") ++ @ApiOperation(value = "获取菜单详情", ++ notes = "获取指定菜单的详细信息,包括名称、路径、组件、图标、排序、权限标识等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- menu_type(菜单类型):返回字段menuType(DIRECTORY=目录, MENU=菜单, BUTTON=按钮)\n" ++ + "- common_status(通用状态):返回字段status") + @GetMapping("/{menuId}") + public Result getMenu(@ApiParam("菜单ID") @PathVariable Long menuId) { + return Result.success(sysMenuService.getMenuById(menuId)); + } + +- @ApiOperation("获取完整菜单树") ++ @ApiOperation(value = "获取完整菜单树", notes = "获取系统所有菜单的完整树形结构。" ++ + "用于角色权限配置页面展示完整的菜单树供勾选。" ++ + "仅SUPER_ADMIN可查看完整菜单树。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- menu_type(菜单类型):返回字段menuType\n" ++ + "- common_status(通用状态):返回字段status") + @GetMapping("/tree") + public Result> getMenuTree() { + return Result.success(sysMenuService.getMenuTree()); + } + +- @ApiOperation("获取角色菜单树") ++ @ApiOperation(value = "获取角色菜单树", ++ notes = "获取指定角色已分配的菜单树形结构。\n" ++ + "用于角色权限配置页面,展示该角色已拥有的菜单权限。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/tree/role/{roleId}") + public Result> getMenuTreeByRoleId(@ApiParam("角色ID") @PathVariable Long roleId) { + return Result.success(sysMenuService.getMenuTreeByRoleId(roleId)); + } + +- @ApiOperation("获取当前管理员菜单") ++ @ApiOperation(value = "获取当前管理员菜单", notes = "获取当前登录管理员的菜单树(基于其当前角色的权限)。" ++ + "SUPER_ADMIN角色返回完整菜单树,其他角色返回已授权的菜单子集。" ++ + "前端登录后调用此接口动态生成路由和侧边栏菜单。" ++ + "需要管理员认证。") + @GetMapping("/my") + public Result> getMyMenus(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java +index 1e4979d..52f6507 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java +@@ -25,14 +25,19 @@ public class SysRoleController { + + private final SysRoleService sysRoleService; + +- @ApiOperation("创建角色") ++ @ApiOperation(value = "创建角色", notes = "创建新的系统角色。" ++ + "角色标识(roleKey)全局唯一,创建后不可修改,用于代码中的权限判断。" ++ + "创建后需通过[分配菜单权限]接口为角色授权菜单。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "创建角色", module = "角色管理") + @PostMapping + public Result createRole(@ApiParam("创建角色请求") @Valid @RequestBody CreateRoleRequest request) { + return Result.success(sysRoleService.createRole(request)); + } + +- @ApiOperation("更新角色") ++ @ApiOperation(value = "更新角色", notes = "更新角色名称、状态等信息。角色标识(roleKey)不可修改。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):ACTIVE=启用, DISABLED=禁用\n") + @OperationLog(value = "更新角色", module = "角色管理") + @PutMapping("/{roleId}") + public Result updateRole(@ApiParam("角色ID") @PathVariable Long roleId, +@@ -40,7 +45,10 @@ public class SysRoleController { + return Result.success(sysRoleService.updateRole(roleId, request)); + } + +- @ApiOperation("删除角色") ++ @ApiOperation(value = "删除角色", notes = "删除指定角色(软删除)。" ++ + "如果该角色下还有关联的管理员,将无法删除,需先解除绑定关系。" ++ + "内置角色(SUPER_ADMIN等)不可删除。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "删除角色", module = "角色管理") + @DeleteMapping("/{roleId}") + public Result deleteRole(@ApiParam("角色ID") @PathVariable Long roleId) { +@@ -48,13 +56,17 @@ public class SysRoleController { + return Result.success(); + } + +- @ApiOperation("获取角色详情(含菜单ID)") ++ @ApiOperation(value = "获取角色详情(含菜单ID)", notes = "获取角色基本信息及其已分配的菜单ID列表。" ++ + "返回role对象和menuIds数组,用于角色编辑页面回显已勾选的菜单。" ++ + "需要管理员认证。") + @GetMapping("/{roleId}") + public Result> getRoleDetail(@ApiParam("角色ID") @PathVariable Long roleId) { + return Result.success(sysRoleService.getRoleDetail(roleId)); + } + +- @ApiOperation("分页查询角色") ++ @ApiOperation(value = "分页查询角色", notes = "分页查询系统角色列表,支持按状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):ACTIVE=启用, DISABLED=禁用(筛选条件+列表展示)\n") + @GetMapping + public Result> listRoles( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -63,13 +75,19 @@ public class SysRoleController { + return Result.success(sysRoleService.listRoles(page, pageSize, status)); + } + +- @ApiOperation("获取所有角色(下拉)") ++ @ApiOperation(value = "获取所有角色(下拉)", notes = "获取所有状态正常的角色列表,用于下拉选择框。" ++ + "不分页,返回全部角色。创建管理员、筛选管理员列表时使用。" ++ + "需要管理员认证。") + @GetMapping("/all") + public Result> getAllRoles() { + return Result.success(sysRoleService.getAllRoles()); + } + +- @ApiOperation("分配菜单权限") ++ @ApiOperation(value = "分配菜单权限", notes = "为指定角色分配菜单权限(全量覆盖模式)。" ++ + "传入的menuIds将完全替换该角色原有的菜单权限。" ++ + "分配后该角色的所有在线管理员下次请求 /admin/menu/my 时会获取到新的菜单树。" ++ + "注意:需同步清除Redis中的菜单缓存,否则前端拿到的是旧菜单。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "分配菜单权限", module = "角色管理") + @PutMapping("/{roleId}/menus") + public Result assignMenus(@ApiParam("角色ID") @PathVariable Long roleId, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java +index 5f71654..ac3f257 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java +@@ -22,7 +22,15 @@ public class TravelerController { + + private final TravelerService travelerService; + +- @ApiOperation("新增出行人") ++ @ApiOperation(value = "新增出行人", notes = "为当前用户添加一位出行人信息,用于下单时选择。" ++ + "出行人类型(成人/儿童/婴儿)根据出生日期自动判断,无需手动传入。" ++ + "如果传入身份证号,后端自动校验格式并解析性别。" ++ + "每个用户最多可添加20位出行人。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):请求/返回字段gender(0=女, 1=男)\n" ++ + "- id_card_type(证件类型):请求/返回字段idCardType(ID_CARD=身份证, PASSPORT=护照等)\n" ++ + "- traveler_type(出行人类型):返回字段travelerType(ADULT=成人, CHILD=儿童, INFANT=婴儿,自动计算)") + @PostMapping + public Result addTraveler(HttpServletRequest request, + @ApiParam("出行人信息") @Valid @RequestBody TravelerRequest travelerRequest) { +@@ -31,7 +39,14 @@ public class TravelerController { + return Result.success(traveler); + } + +- @ApiOperation("出行人列表") ++ @ApiOperation(value = "出行人列表", notes = "获取当前用户的所有出行人列表。" ++ + "如果用户已完成实名认证(realName不为空),列表首项会自动注入一个'本人'虚拟出行人(travelerId=0)。" ++ + "默认出行人排在前面,其余按创建时间排序。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType\n" ++ + "- traveler_type(出行人类型):返回字段travelerType") + @GetMapping + public Result> listTravelers(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -39,7 +54,11 @@ public class TravelerController { + return Result.success(travelers); + } + +- @ApiOperation("出行人详情") ++ @ApiOperation(value = "出行人详情", notes = "获取指定出行人的详细信息。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType\n" ++ + "- traveler_type(出行人类型):返回字段travelerType") + @GetMapping("/{travelerId}") + public Result getTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId) { +@@ -48,7 +67,11 @@ public class TravelerController { + return Result.success(traveler); + } + +- @ApiOperation("更新出行人") ++ @ApiOperation(value = "更新出行人", notes = "更新指定出行人的信息。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):请求/返回字段gender\n" ++ + "- id_card_type(证件类型):请求/返回字段idCardType\n" ++ + "- traveler_type(出行人类型):返回字段travelerType(自动计算)") + @PutMapping("/{travelerId}") + public Result updateTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId, +@@ -58,7 +81,10 @@ public class TravelerController { + return Result.success(traveler); + } + +- @ApiOperation("删除出行人") ++ @ApiOperation(value = "删除出行人", ++ notes = "删除指定的出行人记录(软删除)。\n\n" ++ + "**权限**:需要小程序用户认证。\n" ++ + "**注意**:如果该出行人已关联到未完成的订单,删除不影响订单中的出行人快照数据。") + @DeleteMapping("/{travelerId}") + public Result deleteTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId) { +@@ -67,7 +93,10 @@ public class TravelerController { + return Result.success(); + } + +- @ApiOperation("设为默认出行人") ++ @ApiOperation(value = "设为默认出行人", notes = "将指定出行人设为默认。" ++ + "每个用户只能有一个默认出行人,设置新的默认会自动取消原来的默认。" ++ + "默认出行人在下单时会被自动选中。" ++ + "需要小程序用户认证。") + @PutMapping("/{travelerId}/default") + public Result setDefault(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java +index f5d5dc0..24ecd04 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java +@@ -29,28 +29,42 @@ public class UserController { + private final SmsService smsService; + private final FavoriteService favoriteService; + +- @ApiOperation("发送短信验证码") ++ @ApiOperation(value = "发送短信验证码", notes = "向指定手机号发送6位数字短信验证码,用于小程序手机号登录。" ++ + "同一手机号60秒内不可重复发送,每日最多发送10次。" ++ + "验证码有效期5分钟。" ++ + "无需认证即可调用。") + @PostMapping("/sms/send") + public Result sendSmsCode(@ApiParam("发送短信验证码请求") @Valid @RequestBody SendSmsRequest request) { + smsService.sendVerificationCode(request.getPhone()); + return Result.success(); + } + +- @ApiOperation("手机号验证码登录") ++ @ApiOperation(value = "手机号验证码登录", notes = "小程序用户通过手机号+短信验证码登录。" ++ + "首次登录自动注册账号,返回JWT Token。" ++ + "登录成功后若needProfile=true,表示需要补充个人信息(实名认证),前端应跳转到信息补充页。" ++ + "无需认证即可调用。") + @PostMapping("/login/sms") + public Result loginBySms(@ApiParam("短信验证码登录请求") @Valid @RequestBody SmsLoginRequest request) { + LoginResponse response = userService.loginBySms(request); + return Result.success(response); + } + +- @ApiOperation("微信登录") ++ @ApiOperation(value = "微信登录", notes = "小程序用户通过微信授权码(wx.login获取的code)登录。" ++ + "可选传入phoneCode用于获取手机号绑定,avatar和nickname用于设置头像昵称。" ++ + "首次登录自动注册,返回JWT Token。needProfile=true表示需补充实名信息。" ++ + "无需认证即可调用。") + @PostMapping("/login") + public Result login(@ApiParam("微信登录请求") @Valid @RequestBody LoginRequest request) { + LoginResponse response = userService.login(request); + return Result.success(response); + } + +- @ApiOperation("获取用户信息") ++ @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的个人资料,包括昵称、头像、手机号(脱敏)、实名信息等。" ++ + "手机号返回脱敏格式(如138****0000),证件号同样脱敏处理。" ++ + "需要小程序用户认证(Token中的userId)。" ++ + "\n\n**关联字典**:\n" ++ + "- id_card_type(证件类型):ID_CARD=身份证, PASSPORT=护照\n" ++ + "- gender(性别):0=女, 1=男\n") + @GetMapping("/profile") + public Result getProfile(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -58,7 +72,14 @@ public class UserController { + return Result.success(user); + } + +- @ApiOperation("更新用户信息") ++ @ApiOperation(value = "更新用户信息", notes = "更新当前用户的个人资料。" ++ + "首次登录补充信息时realName/idCardType/idCardNo为必填(使用ProfileCompletion验证组)。" ++ + "如果传入身份证号,后端自动解析性别和出生日期。" ++ + "更新手机号后会自动绑定匹配的待绑定订单。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- id_card_type(证件类型):ID_CARD=身份证, PASSPORT=护照(请求参数idCardType)\n" ++ + "- gender(性别):0=女, 1=男\n") + @PutMapping("/profile") + public Result updateProfile(HttpServletRequest request, + @ApiParam("更新用户信息请求") @Valid @RequestBody UpdateProfileRequest updateRequest) { +@@ -67,7 +88,8 @@ public class UserController { + return Result.success(user); + } + +- @ApiOperation("用户登出") ++ @ApiOperation(value = "用户登出", notes = "清除当前用户的登录状态并使Token失效。" ++ + "需要小程序用户认证。") + @PostMapping("/logout") + public Result logout(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -75,7 +97,10 @@ public class UserController { + return Result.success(); + } + +- @ApiOperation("注销账号") ++ @ApiOperation(value = "注销账号", notes = "永久注销当前用户账号(软删除)。" ++ + "注销后该账号的openid和手机号将被释放,可用于重新注册。" ++ + "注销操作不可撤销,请谨慎调用。" ++ + "需要小程序用户认证。") + @DeleteMapping("/account") + public Result deleteAccount(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -83,7 +108,12 @@ public class UserController { + return Result.success(); + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", notes = "检查当前用户是否已收藏指定类型的资源。" ++ + "返回true=已收藏,false=未收藏。" ++ + "targetType取值:SCENIC_SPOT/ACTIVITY/HOTEL/PRODUCT/EXPLORE等。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索(请求参数targetType)\n") + @GetMapping("/favorite/check") + public Result checkFavorite(HttpServletRequest request, + @ApiParam("目标类型") @RequestParam String targetType, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java +index 2b68e9c..03cca6a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java +@@ -23,7 +23,10 @@ public class WechatSyncController { + + private final WechatSyncService wechatSyncService; + +- @ApiOperation("手动同步部门") ++ @ApiOperation(value = "手动同步部门", notes = "从企业微信拉取最新的部门列表并同步到本地数据库。" ++ + "通常在企业微信后台调整组织架构后手动触发。" ++ + "也可通过定时任务自动执行。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "手动同步部门", module = "企业微信同步") + @PostMapping("/sync/departments") + public Result syncDepartments() { +@@ -31,7 +34,10 @@ public class WechatSyncController { + return Result.success(); + } + +- @ApiOperation("手动同步用户") ++ @ApiOperation(value = "手动同步用户", notes = "从企业微信拉取所有部门的成员列表并同步到本地数据库。" ++ + "包括姓名、手机号、职位、部门归属等信息。" ++ + "需先同步部门再同步用户,或直接使用[同步全部]接口。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "手动同步用户", module = "企业微信同步") + @PostMapping("/sync/users") + public Result syncUsers() { +@@ -39,7 +45,10 @@ public class WechatSyncController { + return Result.success(); + } + +- @ApiOperation("手动同步全部(部门+用户)") ++ @ApiOperation(value = "手动同步全部(部门+用户)", notes = "一键同步企业微信的部门和用户数据,先同步部门再同步用户。" ++ + "推荐使用此接口而非单独同步,确保部门和用户数据一致性。" ++ + "同步过程为异步执行,接口立即返回成功。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "手动同步全部", module = "企业微信同步") + @PostMapping("/sync/all") + public Result syncAll() { +@@ -47,7 +56,13 @@ public class WechatSyncController { + return Result.success(); + } + +- @ApiOperation("查询企业微信用户(分页+搜索)") ++ @ApiOperation(value = "查询企业微信用户(分页+搜索)", notes = "分页查询已同步的企业微信用户列表。" ++ + "支持按姓名/手机号/职位关键词搜索,按部门ID和状态筛选。" ++ + "status取值:1=已激活 2=已禁用 4=未关注。" ++ + "用于管理员绑定企微账号时选择企微用户。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- wechat_user_status(企微用户状态):请求参数status和返回字段status(1=已激活, 2=已禁用, 4=未关注)") + @GetMapping("/users") + public Result> listWechatUsers( + @ApiParam("页码") @RequestParam(defaultValue = "1") Integer page, +@@ -58,21 +73,29 @@ public class WechatSyncController { + return Result.success(wechatSyncService.listWechatUsers(page, pageSize, keyword, deptId, status)); + } + +- @ApiOperation("部门列表(部门管理页面)") ++ @ApiOperation(value = "部门列表(部门管理页面)", ++ notes = "获取已同步的所有企业微信部门列表(平铺结构),用于部门管理页面展示。\n" ++ + "包含部门ID、名称、上级部门ID、排序等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/departments") + public Result> listAllDepartments() { + List departments = wechatSyncService.listAllDepartments(); + return Result.success(departments); + } + +- @ApiOperation("部门树(下拉筛选)") ++ @ApiOperation(value = "部门树(下拉筛选)", notes = "以树形结构返回企业微信部门数据。" ++ + "用于部门筛选下拉框,每个节点包含id/label/children。" ++ + "需要管理员认证。") + @GetMapping("/departments/tree") + public Result>> listDepartmentsTree() { + List> tree = wechatSyncService.listDepartmentsTree(); + return Result.success(tree); + } + +- @ApiOperation("同步状态(最后同步时间)") ++ @ApiOperation(value = "同步状态(最后同步时间)", ++ notes = "获取企业微信数据的最后同步时间和状态。\n" ++ + "返回部门和用户各自的最后同步时间,用于管理页面展示同步状态。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/sync/status") + public Result> getSyncStatus() { + Map status = wechatSyncService.getSyncStatus(); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java` (M) + +接口变更 diff: +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java b/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java +index d2b7b8d..aa20c4b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java +@@ -45,7 +45,10 @@ public class AdminNotificationController { + + // ==================== 事件配置 ==================== + +- @ApiOperation("获取通知配置列表(按分类分组)") ++ @ApiOperation(value = "获取通知配置列表(按分类分组)", notes = "获取所有通知事件配置,按消息分类(categoryCode)分组返回。" ++ + "每个事件配置包含各通知渠道的开关状态(smsEnabled/inappEnabled/weworkEnabled等)。" ++ + "\n\n**关联字典**:\n" ++ + "- notification_channel(通知渠道):sms=短信, inapp=站内信, wework=企业微信, miniapp_subscribe=小程序订阅消息, official_account=公众号模板消息\n") + @GetMapping("/config") + public Result>> listConfigs() { + Map> grouped = configService.listGroupedByCategory(); +@@ -66,7 +69,9 @@ public class AdminNotificationController { + return Result.success(result); + } + +- @ApiOperation("切换通道开关") ++ @ApiOperation(value = "切换通道开关", notes = "切换指定通知事件的某个渠道开关。" ++ + "channel取值:sms/inapp/wework/miniapp_subscribe/official_account。" ++ + "注意:只允许开启渠道,不建议关闭已有渠道。") + @PutMapping("/config/{id}/toggle") + public Result toggleChannel(@PathVariable Long id, + @Valid @RequestBody ChannelToggleRequest request) { +@@ -74,7 +79,10 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("编辑事件配置详情") ++ @ApiOperation(value = "编辑事件配置详情", ++ notes = "更新指定通知事件配置的详细信息,包括模板内容、接收人规则等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:修改模板内容后会立即影响后续的通知发送。") + @PutMapping("/config/{id}") + public Result updateConfig(@PathVariable Long id, + @Valid @RequestBody EventConfigUpdateRequest request) { +@@ -84,7 +92,11 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("测试发送") ++ @ApiOperation(value = "测试发送", ++ notes = "使用测试数据触发一次通知发送,验证通知配置是否正确。\n" ++ + "会使用预设的测试参数(订单号、产品名等)填充模板。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:需指定 testUserId 或 testAdminId 作为接收人,发送结果可在发送日志中查看。") + @PostMapping("/config/{id}/test") + public Result testSend(@PathVariable Long id, + @Valid @RequestBody TestSendRequest request) { +@@ -125,7 +137,10 @@ public class AdminNotificationController { + + // ==================== 消息分类 ==================== + +- @ApiOperation("获取消息分类列表") ++ @ApiOperation(value = "获取消息分类列表", ++ notes = "获取所有通知消息分类,包括分类编码、名称、图标、描述等。\n" ++ + "消息分类用于将通知事件归组管理(如订单消息、系统消息等)。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/categories") + public Result> listCategories() { + List categories = categoryService.listAll(); +@@ -135,7 +150,10 @@ public class AdminNotificationController { + return Result.success(voList); + } + +- @ApiOperation("创建消息分类") ++ @ApiOperation(value = "创建消息分类", ++ notes = "创建新的通知消息分类,用于归组管理通知事件。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:分类编码(code)必须唯一,创建后不可修改。") + @PostMapping("/categories") + public Result createCategory(@Valid @RequestBody CategoryRequest request) { + MessageCategory category = new MessageCategory(); +@@ -148,7 +166,10 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("更新消息分类") ++ @ApiOperation(value = "更新消息分类", ++ notes = "更新指定消息分类的名称、图标、描述、排序等信息。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:分类编码(code)不可修改。") + @PutMapping("/categories/{id}") + public Result updateCategory(@PathVariable Long id, + @Valid @RequestBody CategoryRequest request) { +@@ -161,7 +182,10 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("删除消息分类") ++ @ApiOperation(value = "删除消息分类", ++ notes = "删除指定的消息分类。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:如果该分类下有关联的通知事件配置,需先移除关联后才能删除。") + @DeleteMapping("/categories/{id}") + public Result deleteCategory(@PathVariable Long id) { + categoryService.delete(id); +@@ -170,13 +194,18 @@ public class AdminNotificationController { + + // ==================== 发送日志 ==================== + +- @ApiOperation("查询发送日志") ++ @ApiOperation(value = "查询发送日志", notes = "分页查询通知发送日志,支持按事件编码、渠道、状态等筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- notification_channel(通知渠道):返回字段channel\n" ++ + "- notification_send_status(发送状态):返回字段status(SUCCESS=成功, FAILED=失败, SKIPPED=跳过)\n") + @GetMapping("/logs") + public Result> queryLogs(LogQueryRequest request) { + return Result.success(sendLogService.queryLogs(request)); + } + +- @ApiOperation("获取发送统计") ++ @ApiOperation(value = "获取发送统计", ++ notes = "获取通知发送的统计数据,包括总发送数、成功数、失败数、各渠道发送量等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/logs/stats") + public Result getLogStats() { + return Result.success(sendLogService.getStats()); +@@ -184,7 +213,11 @@ public class AdminNotificationController { + + // ==================== 自定义推送 ==================== + +- @ApiOperation("自定义推送") ++ @ApiOperation(value = "自定义推送", ++ notes = "向指定用户发送自定义通知消息,支持选择推送渠道和目标用户。\n" ++ + "用于运营人员手动推送活动通知、系统公告等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:推送记录会记入发送日志。") + @PostMapping("/custom-push") + public Result customPush(@Valid @RequestBody CustomPushRequest request, + HttpServletRequest httpRequest) { +@@ -193,7 +226,10 @@ public class AdminNotificationController { + return Result.success(result); + } + +- @ApiOperation("搜索用户(自定义推送选择目标)") ++ @ApiOperation(value = "搜索用户(自定义推送选择目标)", ++ notes = "按关键词搜索C端用户,用于自定义推送时选择推送目标。\n" ++ + "支持按真实姓名或手机号模糊搜索,最多返回20条结果。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/custom-push/users") + public Result> searchUsersForPush(@RequestParam(required = false) String keyword) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() +``` + +## DTO/VO 字段变更 + +### `hl-user-service/src/main/java/com/hulalv/user/vo/SysJobLogVO.java` (A) + +> **新增** +```java +package com.hulalv.user.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@ApiModel("定时任务执行日志") +public class SysJobLogVO { + @ApiModelProperty("日志ID") + private Long jobLogId; + + @ApiModelProperty("任务ID") + private Long jobId; + + @ApiModelProperty("任务名称") + private String jobName; + + @ApiModelProperty("调用目标") + private String invokeTarget; + + @ApiModelProperty(value = "执行状态", notes = "字典类型:job_log_status。可选值:SUCCESS=成功, FAIL=失败") + private String status; + + @ApiModelProperty("执行结果/异常信息") + private String message; + + @ApiModelProperty("开始时间") + private LocalDateTime startTime; + + @ApiModelProperty("结束时间") + private LocalDateTime endTime; + + @ApiModelProperty("创建时间") + private LocalDateTime createdAt; +} +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/SysJobVO.java` (A) + +> **新增** +```java +package com.hulalv.user.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.time.LocalDateTime; + +@Data +@ApiModel("定时任务信息") +public class SysJobVO { + @ApiModelProperty("任务ID") + private Long jobId; + + @ApiModelProperty("任务名称") + private String jobName; + + @ApiModelProperty(value = "任务分组", notes = "字典类型:job_group。可选值:DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步") + private String jobGroup; + + @ApiModelProperty("调用目标(Bean名称.方法名)") + private String invokeTarget; + + @ApiModelProperty("Cron表达式") + private String cronExpression; + + @ApiModelProperty(value = "计划执行策略", notes = "字典类型:job_misfire_policy。可选值:DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发") + private String misfirePolicy; + + @ApiModelProperty("是否允许并发执行") + private Boolean concurrent; + + @ApiModelProperty(value = "任务状态", notes = "字典类型:job_status。可选值:ACTIVE=启用, PAUSED=已暂停") + private String status; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("创建时间") + private LocalDateTime createdAt; + + @ApiModelProperty("更新时间") + private LocalDateTime updatedAt; +} +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java +index cc334e0..001c095 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java +@@ -1,15 +1,33 @@ + package com.hulalv.callback.msgaudit.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("聊天消息VO") + public class ChatMessageVO { ++ @ApiModelProperty("消息ID") + private String msgId; ++ ++ @ApiModelProperty("发送人ID") + private String fromUser; ++ ++ @ApiModelProperty("发送人姓名") + private String fromUserName; ++ ++ @ApiModelProperty("发送人头像") + private String fromUserAvatar; ++ ++ @ApiModelProperty("群聊ID") + private String roomId; ++ ++ @ApiModelProperty("消息时间戳") + private Long msgTime; ++ ++ @ApiModelProperty("消息类型") + private String msgType; ++ ++ @ApiModelProperty("消息内容") + private String content; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/AdminBasicDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/AdminBasicDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/AdminBasicDTO.java +index 4384bbc..d7ae755 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/AdminBasicDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/AdminBasicDTO.java +@@ -1,14 +1,26 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.io.Serializable; + + @Data ++@ApiModel("管理员基本信息") + public class AdminBasicDTO implements Serializable { ++ @ApiModelProperty("管理员ID") + private Long adminId; ++ ++ @ApiModelProperty("用户名") + private String username; ++ ++ @ApiModelProperty("头像URL") + private String avatarUrl; ++ ++ @ApiModelProperty("企微用户ID") + private String wechatUserid; ++ ++ @ApiModelProperty("企微用户名称") + private String wechatName; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/DepartmentDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/DepartmentDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/DepartmentDTO.java +index 54e49c6..d957404 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/DepartmentDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/DepartmentDTO.java +@@ -1,12 +1,20 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.io.Serializable; + + @Data ++@ApiModel("部门信息") + public class DepartmentDTO implements Serializable { ++ @ApiModelProperty("部门ID") + private Long deptId; ++ ++ @ApiModelProperty("部门名称") + private String deptName; ++ ++ @ApiModelProperty("上级部门ID") + private Long parentId; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/ExternalContactEventDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/ExternalContactEventDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/ExternalContactEventDTO.java +index b460471..b5d3084 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/ExternalContactEventDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/ExternalContactEventDTO.java +@@ -1,13 +1,18 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("外部联系人事件") + public class ExternalContactEventDTO { +- /** add_external_contact / del_follow_user / del_external_contact / edit_external_contact */ ++ @ApiModelProperty("变更类型: add_external_contact/del_follow_user/del_external_contact/edit_external_contact") + private String changeType; +- /** Employee enterprise WeChat userid */ ++ ++ @ApiModelProperty("员工企微用户ID") + private String userId; +- /** External contact ID */ ++ ++ @ApiModelProperty("外部联系人ID") + private String externalUserId; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/FileBindRefsDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/FileBindRefsDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/FileBindRefsDTO.java +index dc20c8c..dda68cc 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/FileBindRefsDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/FileBindRefsDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,8 +11,14 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("文件绑定引用请求") + public class FileBindRefsDTO { ++ @ApiModelProperty("业务类型") + private String bizType; ++ ++ @ApiModelProperty("业务ID") + private Long bizId; ++ ++ @ApiModelProperty("文件ID列表") + private List fileIds; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/FileUnbindRefsDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/FileUnbindRefsDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/FileUnbindRefsDTO.java +index 5cc541a..9a26827 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/FileUnbindRefsDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/FileUnbindRefsDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,7 +9,11 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("文件解绑引用请求") + public class FileUnbindRefsDTO { ++ @ApiModelProperty("业务类型") + private String bizType; ++ ++ @ApiModelProperty("业务ID") + private Long bizId; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/OrderPayInfoDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/OrderPayInfoDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/OrderPayInfoDTO.java +index 2b8b700..1661e45 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/OrderPayInfoDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/OrderPayInfoDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + import java.math.BigDecimal; + +@@ -7,19 +9,41 @@ import java.math.BigDecimal; + * Order payment info DTO (order-service -> payment-service) + */ + @Data ++@ApiModel("订单支付信息") + public class OrderPayInfoDTO { ++ @ApiModelProperty("订单ID") + private Long orderId; ++ ++ @ApiModelProperty("订单编号") + private String orderNo; ++ ++ @ApiModelProperty("用户ID") + private Long userId; ++ ++ @ApiModelProperty("商户号") + private String mchId; ++ ++ @ApiModelProperty("总价") + private BigDecimal totalPrice; ++ ++ @ApiModelProperty("优惠金额") + private BigDecimal discountAmount; ++ ++ @ApiModelProperty("定金金额") + private BigDecimal depositAmount; ++ ++ @ApiModelProperty("已支付金额") + private BigDecimal paidAmount; +- /** 支付模式: FULL=全款 DEPOSIT=定金+尾款 */ ++ ++ @ApiModelProperty("支付模式: FULL=全款, DEPOSIT=定金+尾款") + private String paymentMode; ++ ++ @ApiModelProperty("订单状态") + private String status; ++ ++ @ApiModelProperty("产品名称") + private String productName; +- /** 是否预定产品: true=预定(定金可不填出行人) false=非预定(支付前必须填出行人) */ ++ ++ @ApiModelProperty("是否预定产品: true=预定(定金可不填出行人), false=非预定(支付前必须填出行人)") + private Boolean isBooking; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/PaymentResultDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/PaymentResultDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/PaymentResultDTO.java +index f39ebfa..7becb52 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/PaymentResultDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/PaymentResultDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + import java.math.BigDecimal; + +@@ -7,9 +9,17 @@ import java.math.BigDecimal; + * Payment result notification DTO (payment-service -> order-service) + */ + @Data ++@ApiModel("支付结果通知") + public class PaymentResultDTO { ++ @ApiModelProperty("订单ID") + private Long orderId; +- private String payType; // FULL / DEPOSIT / BALANCE ++ ++ @ApiModelProperty("支付类型: FULL=全款, DEPOSIT=定金, BALANCE=尾款") ++ private String payType; ++ ++ @ApiModelProperty("支付金额") + private BigDecimal paidAmount; ++ ++ @ApiModelProperty("微信支付交易号") + private String transactionIdWx; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/RefundResultDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/RefundResultDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/RefundResultDTO.java +index 27b0f25..7483c4e 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/RefundResultDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/RefundResultDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + import java.math.BigDecimal; + +@@ -7,8 +9,14 @@ import java.math.BigDecimal; + * Refund result notification DTO (payment-service -> order-service) + */ + @Data ++@ApiModel("退款结果通知") + public class RefundResultDTO { ++ @ApiModelProperty("订单ID") + private Long orderId; ++ ++ @ApiModelProperty("退款金额") + private BigDecimal refundAmount; ++ ++ @ApiModelProperty("微信退款单号") + private String refundIdWx; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/ResourceDetailDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/ResourceDetailDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/ResourceDetailDTO.java +index 1311d05..3cc83c0 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/ResourceDetailDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/ResourceDetailDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Builder; + import lombok.Data; +@@ -16,47 +18,48 @@ import java.util.List; + @Builder + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源详情") + public class ResourceDetailDTO { + +- /** 资源ID */ ++ @ApiModelProperty("资源ID") + private String resourceId; + +- /** 资源类型: SCENIC_SPOT/HOTEL/RESTAURANT/ACTIVITY */ ++ @ApiModelProperty("资源类型: SCENIC_SPOT/HOTEL/RESTAURANT/ACTIVITY") + private String resourceType; + +- /** 资源名称 */ ++ @ApiModelProperty("资源名称") + private String name; + +- /** 副标题 */ ++ @ApiModelProperty("副标题") + private String subtitle; + +- /** 简介/描述 */ ++ @ApiModelProperty("简介/描述") + private String description; + +- /** 封面图URL */ ++ @ApiModelProperty("封面图URL") + private String cover; + +- /** 图片URL列表(轮播图) */ ++ @ApiModelProperty("图片URL列表(轮播图)") + private List images; + +- /** 地址 */ ++ @ApiModelProperty("地址") + private String address; + +- /** 经度 */ ++ @ApiModelProperty("经度") + private BigDecimal longitude; + +- /** 纬度 */ ++ @ApiModelProperty("纬度") + private BigDecimal latitude; + +- /** 标签列表 */ ++ @ApiModelProperty("标签列表") + private List tags; + +- /** 图文详情(featureIntro JSON) */ ++ @ApiModelProperty("图文详情(featureIntro JSON)") + private String featureIntro; + +- /** 评分 */ ++ @ApiModelProperty("评分") + private BigDecimal rating; + +- /** 所在城市 */ ++ @ApiModelProperty("所在城市") + private String city; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/TravelerValidationDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/TravelerValidationDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/TravelerValidationDTO.java +index 3defc94..f46a8e4 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/TravelerValidationDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/TravelerValidationDTO.java +@@ -1,5 +1,7 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Builder; + import lombok.Data; +@@ -14,34 +16,23 @@ import java.util.List; + @Builder + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("出行人验证结果") + public class TravelerValidationDTO { +- /** +- * 订单ID +- */ ++ @ApiModelProperty("订单ID") + private Long orderId; + +- /** +- * 需要的出行人数量 +- */ ++ @ApiModelProperty("需要的出行人数量") + private Integer requiredCount; + +- /** +- * 实际填写的出行人数量 +- */ ++ @ApiModelProperty("实际填写的出行人数量") + private Integer actualCount; + +- /** +- * 是否完整(数量足够且信息完整) +- */ ++ @ApiModelProperty("是否完整(数量足够且信息完整)") + private Boolean isComplete; + +- /** +- * 信息不完整的出行人ID列表 +- */ ++ @ApiModelProperty("信息不完整的出行人ID列表") + private List incompleteTravelerIds; + +- /** +- * 验证消息 +- */ ++ @ApiModelProperty("验证消息") + private String message; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/WechatDeptSyncDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/WechatDeptSyncDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/WechatDeptSyncDTO.java +index 6eb1bab..13bb274 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/WechatDeptSyncDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/WechatDeptSyncDTO.java +@@ -1,11 +1,21 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("企微部门同步信息") + public class WechatDeptSyncDTO { ++ @ApiModelProperty("部门ID") + private Long id; ++ ++ @ApiModelProperty("部门名称") + private String name; ++ ++ @ApiModelProperty("上级部门ID") + private Long parentId; ++ ++ @ApiModelProperty("排序值") + private Integer order; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/WechatMessageDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/WechatMessageDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/WechatMessageDTO.java +index 1fae45a..617a3b3 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/WechatMessageDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/WechatMessageDTO.java +@@ -1,12 +1,18 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.io.Serializable; + import java.util.List; + + @Data ++@ApiModel("企微消息推送") + public class WechatMessageDTO implements Serializable { ++ @ApiModelProperty("接收用户ID列表") + private List toUserIds; ++ ++ @ApiModelProperty("消息内容") + private String content; + } +``` + +### `hl-common/src/main/java/com/hulalv/common/dto/WechatUserSyncDTO.java` (M) + +```diff +diff --git a/hl-common/src/main/java/com/hulalv/common/dto/WechatUserSyncDTO.java b/hl-common/src/main/java/com/hulalv/common/dto/WechatUserSyncDTO.java +index f047acc..97a07fc 100644 +--- a/hl-common/src/main/java/com/hulalv/common/dto/WechatUserSyncDTO.java ++++ b/hl-common/src/main/java/com/hulalv/common/dto/WechatUserSyncDTO.java +@@ -1,16 +1,36 @@ + package com.hulalv.common.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("企微用户同步信息") + public class WechatUserSyncDTO { ++ @ApiModelProperty("企微用户ID") + private String userid; ++ ++ @ApiModelProperty("用户名称") + private String name; ++ ++ @ApiModelProperty("所属部门ID(逗号分隔)") + private String department; ++ ++ @ApiModelProperty("职位") + private String position; ++ ++ @ApiModelProperty("手机号") + private String mobile; ++ ++ @ApiModelProperty("性别: 1=男, 2=女, 0=未定义") + private Integer gender; ++ ++ @ApiModelProperty("邮箱") + private String email; ++ ++ @ApiModelProperty("头像URL") + private String avatar; ++ ++ @ApiModelProperty("状态: 1=已激活, 2=已禁用, 4=未激活, 5=退出企业") + private Integer status; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java +index 7adbe0a..93a06f8 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传取消请求") + public class ChunkUploadCancelRequest { + ++ @ApiModelProperty("上传ID") + private String uploadId; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java +index 712c15c..d876fcc 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传完成请求") + public class ChunkUploadCompleteRequest { + ++ @ApiModelProperty("上传ID") + private String uploadId; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java +index 2d94f04..939a630 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java +@@ -1,13 +1,25 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传初始化请求") + public class ChunkUploadInitRequest { + ++ @ApiModelProperty("文件名") + private String filename; ++ ++ @ApiModelProperty("文件大小(字节)") + private Long fileSize; ++ ++ @ApiModelProperty("文件MIME类型") + private String contentType; ++ ++ @ApiModelProperty("分组标识") + private String groupKey; ++ ++ @ApiModelProperty("文件哈希值") + private String fileHash; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java +index 96c2499..449c3b4 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("文件批量ID请求") + public class FileBatchIdsRequest { + ++ @ApiModelProperty("文件ID列表") + private List fileIds; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java +index bb85acc..1b1d316 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("文件上传确认请求") + public class FileUploadConfirmRequest { + ++ @ApiModelProperty("文件ID") + private String fileId; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java +index 4d7a140..ee7cd4e 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java +@@ -1,13 +1,25 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("文件上传令牌请求") + public class FileUploadTokenRequest { + ++ @ApiModelProperty("文件名") + private String fileName; ++ ++ @ApiModelProperty("文件大小(字节)") + private Long fileSize; ++ ++ @ApiModelProperty("文件哈希值") + private String fileHash; ++ ++ @ApiModelProperty("分组标识") + private String groupKey; ++ ++ @ApiModelProperty("是否强制使用预签名URL") + private boolean forcePresigned; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java +index 6cd60b6..9f38bc4 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java +@@ -1,12 +1,22 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传初始化结果") + public class ChunkUploadInitVO { + ++ @ApiModelProperty("上传ID") + private String uploadId; ++ ++ @ApiModelProperty("分片大小(字节)") + private int chunkSize; ++ ++ @ApiModelProperty("文件ID") + private String fileId; ++ ++ @ApiModelProperty("OSS对象Key") + private String ossKey; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java +index 1628687..cc0df47 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传片段结果") + public class ChunkUploadPartVO { + ++ @ApiModelProperty("分片ETag标识") + private String etag; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java +index 779f74d..07b2068 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java +@@ -1,28 +1,58 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.time.LocalDateTime; + + @Data ++@ApiModel("文件上传令牌结果") + public class FileUploadTokenVO { + ++ @ApiModelProperty("文件ID") + private String fileId; ++ ++ @ApiModelProperty("文件MIME类型") + private String contentType; ++ ++ @ApiModelProperty("上传模式") + private String uploadMode; ++ ++ @ApiModelProperty("预签名上传URL") + private String presignedUrl; ++ ++ @ApiModelProperty("OSS对象Key") + private String ossKey; ++ ++ @ApiModelProperty("过期时间") + private LocalDateTime expireAt; ++ ++ @ApiModelProperty("STS临时凭证") + private StsTokenInfo stsToken; ++ ++ @ApiModelProperty("OSS存储桶名称") + private String bucket; ++ ++ @ApiModelProperty("OSS区域") + private String region; ++ ++ @ApiModelProperty("文件信息(秒传时返回)") + private FileVO file; + + @Data ++ @ApiModel("STS临时凭证信息") + public static class StsTokenInfo { ++ @ApiModelProperty("访问密钥ID") + private String accessKeyId; ++ ++ @ApiModelProperty("访问密钥Secret") + private String accessKeySecret; ++ ++ @ApiModelProperty("安全令牌") + private String securityToken; ++ ++ @ApiModelProperty("过期时间") + private String expiration; + } + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java +index a5e43b9..90612e6 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java +@@ -1,23 +1,51 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.time.LocalDateTime; + + @Data ++@ApiModel("文件信息VO") + public class FileVO { + ++ @ApiModelProperty("文件ID") + private String fileId; ++ ++ @ApiModelProperty("文件名") + private String fileName; ++ ++ @ApiModelProperty("文件类型") + private String fileType; ++ ++ @ApiModelProperty("MIME类型") + private String mimeType; ++ ++ @ApiModelProperty("文件大小(字节)") + private Long fileSize; ++ ++ @ApiModelProperty("文件哈希值") + private String fileHash; ++ ++ @ApiModelProperty("OSS访问URL") + private String ossUrl; ++ ++ @ApiModelProperty("缩略图URL") + private String thumbnailUrl; ++ ++ @ApiModelProperty("预览URL") + private String previewUrl; ++ ++ @ApiModelProperty("分组标识") + private String groupKey; ++ ++ @ApiModelProperty("文件状态") + private String status; ++ ++ @ApiModelProperty("引用次数") + private Integer refCount; ++ ++ @ApiModelProperty("创建时间") + private LocalDateTime createdAt; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java +index 8fb0223..48d0a18 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java +@@ -35,7 +35,7 @@ public class AdminCreateOrderRequest { + @Min(value = 0) + private int babyCount = 0; + +- @ApiModelProperty(value = "儿童是否需要床位", example = "false") ++ @ApiModelProperty(value = "儿童是否需要床位(影响房间分配和报价计算)", example = "false") + private Boolean childNeedBed = false; + + @ApiModelProperty(value = "团期ID(GROUP产品必填)") +@@ -59,14 +59,14 @@ public class AdminCreateOrderRequest { + @Size(max = 500, message = "备注不能超过500个字符") + private String remark; + +- @ApiModelProperty(value = "用户手机号(可选,用于关联C端用户)", example = "13800138000") ++ @ApiModelProperty(value = "用户手机号(可选,用于关联C端用户)。如匹配到已注册用户则自动绑定订单", example = "13800138000") + @Size(max = 20) + private String userPhone; + + @ApiModelProperty(value = "定制师ID(可选,默认为创建人)", example = "1760000000000010") + private Long customizerId; + +- @ApiModelProperty(value = "支付时限(分钟),不传则使用全局默认值", example = "30") ++ @ApiModelProperty(value = "支付时限(分钟),不传则使用全局默认值。超时未支付订单自动取消", example = "30") + @Min(value = 1, message = "支付时限最少1分钟") + @Max(value = 1440, message = "支付时限最多1440分钟") + private Integer expiryMinutes; +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java +index dfdbe7d..3eb5db1 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java +@@ -11,11 +11,11 @@ import java.math.BigDecimal; + @Data + @ApiModel("管理员退款审批请求") + public class AdminRefundReviewRequest { +- @ApiModelProperty(value = "审批结果(APPROVE/REJECT)", required = true, example = "APPROVE") ++ @ApiModelProperty(value = "审批结果:APPROVE=通过(自动调起微信退款)、REJECT=拒绝(用户可发起申诉)", required = true, example = "APPROVE") + @NotBlank(message = "审批结果不能为空") + private String action; + +- @ApiModelProperty(value = "实际退款金额(审批通过时可调整)", example = "1500.00") ++ @ApiModelProperty(value = "实际退款金额(审批通过时可调整,不传则使用申请金额)。不能超过订单已付金额", example = "1500.00") + private BigDecimal actualAmount; + + @ApiModelProperty(value = "审批备注", example = "同意全额退款") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java +index 2d1c10e..44a424e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java +@@ -44,7 +44,7 @@ public class AdminUpdateOrderRequest { + @Min(value = 0, message = "幼童数不能为负") + private Integer babyCount; + +- @ApiModelProperty(value = "商户号", example = "1246532201") ++ @ApiModelProperty(value = "商户号(微信支付商户号,多商户场景使用)", example = "1246532201") + @Size(max = 32, message = "商户号不能超过32个字符") + private String mchId; + +@@ -62,6 +62,6 @@ public class AdminUpdateOrderRequest { + + // Note: discount is now managed via separate discount CRUD endpoints (POST/PUT/DELETE /admin/order/{orderId}/discount) + +- @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人)") ++ @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人,不传则不修改出行人)") + private List travelers; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java +index aeb8c8c..b984863 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java +@@ -13,11 +13,12 @@ public class CreateWorkOrderRequest { + @NotNull(message = "订单ID不能为空") + private Long orderId; + +- @ApiModelProperty(value = "工单类型: ROOM_CHANGE/ROOM_ADD/CHECKOUT_CHANGE/HOTEL_ISSUE/VEHICLE_CHANGE/SCENIC_ADD/SCENIC_REMOVE/OTHER", required = true) ++ @ApiModelProperty(value = "工单类型: ROOM_CHANGE(换房)/ROOM_ADD(加房)/CHECKOUT_CHANGE(改退房日期)/" + ++ "HOTEL_ISSUE(酒店问题)/VEHICLE_CHANGE(换车)/SCENIC_ADD(加景点)/SCENIC_REMOVE(减景点)/OTHER(其他)", required = true) + @NotBlank(message = "工单类型不能为空") + private String type; + +- @ApiModelProperty(value = "优先级: URGENT/NORMAL", required = true) ++ @ApiModelProperty(value = "优先级: URGENT(紧急,如当天出发需处理)/NORMAL(普通)", required = true) + @NotBlank(message = "优先级不能为空") + private String priority; + +@@ -31,7 +32,7 @@ public class CreateWorkOrderRequest { + @ApiModelProperty("资源详情JSON(酒店/车辆/景点信息)") + private String resourceDetail; + +- @ApiModelProperty("差价(正数=加价, 负数=退费)") ++ @ApiModelProperty("差价(正数=客户需补差价, 负数=需退费给客户)") + private BigDecimal costDifference; + + @ApiModelProperty("指定处理人ID") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java +index f2f451c..a678aff 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java +@@ -24,12 +24,12 @@ public class EarlyBirdPlanRequest { + @NotNull(message = "生效结束日期不能为空") + private LocalDate endDate; + +- @ApiModelProperty(value = "最低人数", required = true, example = "2") ++ @ApiModelProperty(value = "最低出行人数(含成人+儿童),订单人数>=此值才能享受优惠", required = true, example = "2") + @NotNull(message = "最低人数不能为空") + @Min(value = 1, message = "最低人数至少为1") + private Integer minPeople; + +- @ApiModelProperty(value = "优惠金额", required = true, example = "200.00") ++ @ApiModelProperty(value = "优惠金额(从订单总价中扣减的固定金额)", required = true, example = "200.00") + @NotNull(message = "优惠金额不能为空") + @DecimalMin(value = "0.01", message = "优惠金额必须大于0") + private BigDecimal discountAmount; +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java +index 125cd6a..9a93336 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java +@@ -13,7 +13,7 @@ public class InvoiceApplyRequest { + @NotNull(message = "orderId is required") + private Long orderId; + +- @ApiModelProperty(value = "抬头类型(personal=个人/company=企业)", example = "personal") ++ @ApiModelProperty(value = "抬头类型:personal=个人(默认)、company=企业(需填写税号)", example = "personal") + private String titleType = "personal"; + + @ApiModelProperty(value = "发票抬头", required = true, example = "张三") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java +index 98b28d5..c28453b 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java +@@ -10,7 +10,7 @@ import javax.validation.constraints.Min; + @Data + @ApiModel("C端订单查询请求") + public class MpOrderQueryRequest { +- @ApiModelProperty(value = "订单状态", example = "PAID") ++ @ApiModelProperty(value = "订单状态(不传则查全部)。可选值:PENDING_PAY/DEPOSIT_PAID/PAID/CONFIRMED/PENDING_BALANCE/PENDING_DEPARTURE/TRAVELLING/COMPLETED/AFTER_SALE/REFUNDING/REFUNDED/CANCELLED", example = "PAID") + private String status; + + @ApiModelProperty(value = "页码", example = "1") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java +index 9782f64..0b13f71 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java +@@ -9,12 +9,12 @@ import java.time.LocalDate; + import java.util.List; + + @Data +-@ApiModel("小程序修改订单请求") ++@ApiModel(value = "小程序修改订单请求", description = "用户可修改出发日期和出行人。修改后系统自动重算价格,内部流程已启动的订单会通知定制师") + public class MpUpdateOrderRequest { + +- @ApiModelProperty(value = "出发日期", example = "2026-05-01") ++ @ApiModelProperty(value = "出发日期(修改出发日期会触发价格重算)", example = "2026-05-01") + private LocalDate departureDate; + +- @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人)") ++ @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人,不传则不修改出行人)") + private List travelers; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java +index 4d8aa75..7c32a24 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java +@@ -11,11 +11,11 @@ import javax.validation.constraints.Size; + @Data + @ApiModel("退款申请请求") + public class RefundApplyRequest { +- @ApiModelProperty(value = "退款类型(字典:refund_type)", required = true, example = "FULL") ++ @ApiModelProperty(value = "退款类型:FULL=全额退款、PARTIAL=部分退款", required = true, example = "FULL") + @NotBlank(message = "退款类型不能为空") + private String refundType; + +- @ApiModelProperty(value = "退款原因ID", example = "1760000000000001") ++ @ApiModelProperty(value = "退款原因ID(从退款原因列表接口获取)", example = "1760000000000001") + private Long reasonId; + + @ApiModelProperty(value = "退款原因", required = true, example = "行程有变,无法出行") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java +index cb0873c..a6a18a7 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java +@@ -42,12 +42,12 @@ public class RefundPolicyRequest { + @Data + @ApiModel("退款规则项") + public static class RuleItem { +- @ApiModelProperty(value = "距出发最少天数", required = true, example = "7") ++ @ApiModelProperty(value = "距出发最少天数(含当天)。例如:minDays=7表示出发前7天及以上适用此规则", required = true, example = "7") + @NotNull(message = "最少天数不能为空") + @Min(value = 0, message = "最少天数不能小于0") + private Integer minDays; + +- @ApiModelProperty(value = "退款比例(百分比)", required = true, example = "80") ++ @ApiModelProperty(value = "退款比例(百分比,0-100)。例如:80表示退已付金额的80%", required = true, example = "80") + @NotNull(message = "退款比例不能为空") + @Min(value = 0, message = "退款比例不能小于0") + @Max(value = 100, message = "退款比例不能超过100") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java +index f290109..c40fb91 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java +@@ -9,7 +9,10 @@ import javax.validation.constraints.NotBlank; + @Data + @ApiModel("更新订单状态请求") + public class UpdateOrderStatusRequest { +- @ApiModelProperty(value = "目标状态(字典:order_status)", required = true, example = "CONFIRMED") ++ @ApiModelProperty(value = "目标状态。可选值:PENDING_PAY(待支付)/DEPOSIT_PAID(已付定金)/PAID(已全额支付)/" + ++ "CONFIRMED(已确认)/PENDING_BALANCE(待付尾款)/PENDING_DEPARTURE(待出行)/" + ++ "TRAVELLING(旅行中)/COMPLETED(已完成)/AFTER_SALE(售后中)/REFUNDING(退款中)/" + ++ "REFUNDED(已退款)/CANCELLED(已取消)", required = true, example = "CONFIRMED") + @NotBlank(message = "状态不能为空") + private String status; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java b/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java +index 58106e0..f6bcd64 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java +@@ -82,12 +82,24 @@ public class WorkOrderVO { + private List logs; + + @Data ++ @io.swagger.annotations.ApiModel("工单操作日志VO") + public static class WorkOrderLogVO { ++ @ApiModelProperty("日志ID") + private String logId; ++ ++ @ApiModelProperty("操作动作") + private String action; ++ ++ @ApiModelProperty("操作动作标签") + private String actionLabel; ++ ++ @ApiModelProperty("操作内容") + private String content; ++ ++ @ApiModelProperty("操作人姓名") + private String operatorName; ++ ++ @ApiModelProperty("操作时间") + private LocalDateTime createdAt; + } + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java +index 223810b..84591cf 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java +@@ -9,7 +9,7 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.Size; + + @Data +-@ApiModel("家庭分组保存请求") ++@ApiModel(value = "家庭分组保存请求", description = "仅适用于CUSTOM定制产品,用于将行程按家庭单位分配") + public class FamilySaveRequest { + + @ApiModelProperty(value = "家庭名称", required = true, example = "家庭1") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java +index 4acb045..89b3240 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java +@@ -29,7 +29,8 @@ public class FormulaStepRequest { + @ApiModelProperty(value = "执行顺序", example = "1") + private Integer executionOrder; + +- @ApiModelProperty(value = "表达式", required = true, example = "baseCost = adultCount * adultUnitCost + childCount * childUnitCost") ++ @ApiModelProperty(value = "Aviator表达式(支持数学运算、条件判断、内置函数;可引用前置步骤的输出变量和公式变量表中的变量)", ++ required = true, example = "baseCost = adultCount * adultUnitCost + childCount * childUnitCost") + @NotBlank(message = "表达式不能为空") + @Size(max = 2000, message = "表达式不能超过2000个字符") + private String expression; +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java +index 70e06ec..2cf6432 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java +@@ -8,34 +8,34 @@ import javax.validation.constraints.*; + import java.time.LocalDate; + + @Data +-@ApiModel("create group batch request") ++@ApiModel("创建拼团批次请求") + public class GroupBatchCreateRequest { + +- @ApiModelProperty(value = "batch name", required = true, example = "Jul 20 Batch 1") +- @NotBlank(message = "batch name required") ++ @ApiModelProperty(value = "批次名称", required = true, example = "7月20日第1批") ++ @NotBlank(message = "批次名称不能为空") + @Size(max = 128) + private String batchName; + +- @ApiModelProperty(value = "departure date", required = true, example = "2026-07-20") +- @NotNull(message = "departure date required") ++ @ApiModelProperty(value = "出发日期", required = true, example = "2026-07-20") ++ @NotNull(message = "出发日期不能为空") + private LocalDate departureDate; + +- @ApiModelProperty(value = "enrollment deadline", required = true, example = "2026-07-15") +- @NotNull(message = "enrollment deadline required") ++ @ApiModelProperty(value = "报名截止日期,必须早于出发日期", required = true, example = "2026-07-15") ++ @NotNull(message = "报名截止日期不能为空") + private LocalDate enrollmentDeadline; + +- @ApiModelProperty(value = "min participants for group confirmation (0=no limit)", example = "10") ++ @ApiModelProperty(value = "最低成团人数(0=不限制,达到此人数自动变为CONFIRMED状态)", example = "10") + @Min(0) + private int minParticipants = 0; + +- @ApiModelProperty(value = "max participants", required = true, example = "30") +- @Min(value = 1, message = "max participants must be >= 1") ++ @ApiModelProperty(value = "最大参团人数(报名人数达到上限后自动关闭报名)", required = true, example = "30") ++ @Min(value = 1, message = "最大参团人数至少为1") + private int maxParticipants; + +- @ApiModelProperty(value = "remark", example = "summer special batch") ++ @ApiModelProperty(value = "备注说明", example = "暑期特别批次") + @Size(max = 512) + private String remark; + +- @ApiModelProperty(value = "sort order", example = "0") ++ @ApiModelProperty(value = "排序序号(越小越靠前)", example = "0") + private int sortOrder = 0; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java +index 369a7ca..ca769e4 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java +@@ -8,11 +8,11 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.Size; + + @Data +-@ApiModel("disband batch request") ++@ApiModel("解散批次请求") + public class GroupBatchDisbandRequest { + +- @ApiModelProperty(value = "disband reason", required = true, example = "insufficient enrollment") +- @NotBlank(message = "disband reason required") ++ @ApiModelProperty(value = "解散原因(如:报名人数不足、行程调整等)", required = true, example = "报名人数不足") ++ @NotBlank(message = "解散原因不能为空") + @Size(max = 512) + private String reason; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java +index 8c2f4bb..712181e 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java +@@ -9,22 +9,22 @@ import javax.validation.constraints.NotNull; + import javax.validation.constraints.Size; + + @Data +-@ApiModel("batch staff assignment request") ++@ApiModel("批次服务人员分配请求") + public class GroupBatchStaffRequest { + +- @ApiModelProperty(value = "staff ID (from resource-service)", required = true, example = "1760000000000001") +- @NotNull(message = "staff ID required") ++ @ApiModelProperty(value = "人员ID(来自资源服务的人员库)", required = true, example = "1760000000000001") ++ @NotNull(message = "人员ID不能为空") + private Long staffId; + +- @ApiModelProperty(value = "role in this batch: LEADER/PHOTOGRAPHER/DRIVER/OTHER", required = true, example = "LEADER") +- @NotBlank(message = "staff role required") ++ @ApiModelProperty(value = "在该批次中的角色:LEADER(领队)/PHOTOGRAPHER(摄影师)/DRIVER(司机)/OTHER(其他)", required = true, example = "LEADER") ++ @NotBlank(message = "人员角色不能为空") + @Size(max = 32) + private String staffRole; + +- @ApiModelProperty(value = "remark", example = "main guide") ++ @ApiModelProperty(value = "备注(如:主导游、备用摄影师等)", example = "主导游") + @Size(max = 256) + private String remark; + +- @ApiModelProperty(value = "sort order", example = "0") ++ @ApiModelProperty(value = "排序序号(越小越靠前)", example = "0") + private int sortOrder = 0; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java +index a8e2de6..4532f60 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java +@@ -9,31 +9,31 @@ import javax.validation.constraints.Size; + import java.time.LocalDate; + + @Data +-@ApiModel("update group batch request") ++@ApiModel("更新拼团批次请求") + public class GroupBatchUpdateRequest { + +- @ApiModelProperty(value = "batch name", example = "Jul 20 Batch 1") ++ @ApiModelProperty(value = "批次名称", example = "7月20日第1批") + @Size(max = 128) + private String batchName; + +- @ApiModelProperty(value = "departure date", example = "2026-07-20") ++ @ApiModelProperty(value = "出发日期", example = "2026-07-20") + private LocalDate departureDate; + +- @ApiModelProperty(value = "enrollment deadline", example = "2026-07-15") ++ @ApiModelProperty(value = "报名截止日期", example = "2026-07-15") + private LocalDate enrollmentDeadline; + +- @ApiModelProperty(value = "min participants", example = "10") ++ @ApiModelProperty(value = "最低成团人数(0=不限制)", example = "10") + @Min(0) + private Integer minParticipants; + +- @ApiModelProperty(value = "max participants", example = "30") ++ @ApiModelProperty(value = "最大参团人数(不能低于已报名人数)", example = "30") + @Min(1) + private Integer maxParticipants; + +- @ApiModelProperty(value = "remark") ++ @ApiModelProperty(value = "备注说明") + @Size(max = 512) + private String remark; + +- @ApiModelProperty(value = "sort order") ++ @ApiModelProperty(value = "排序序号") + private Integer sortOrder; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java +index a19ae8a..eae3469 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java +@@ -37,10 +37,10 @@ public class NodeCreateRequest { + @ApiModelProperty(value = "纬度", example = "26.872108") + private BigDecimal latitude; + +- @ApiModelProperty(value = "关联资源类型:SCENIC_SPOT/HOTEL/RESTAURANT/ACTIVITY/VEHICLE/SERVICE", example = "SCENIC_SPOT") ++ @ApiModelProperty(value = "关联资源类型(关联后可从资源服务获取价格参与成本计算):SCENIC/HOTEL/RESTAURANT/ACTIVITY/VEHICLE/SERVICE", example = "SCENIC") + private String resourceType; + +- @ApiModelProperty(value = "关联资源ID", example = "1893012345678901234") ++ @ApiModelProperty(value = "关联资源ID(来自资源服务,关联后节点名称和图片可自动同步)", example = "1893012345678901234") + private String resourceId; + + @ApiModelProperty(value = "节点描述", example = "漫步古城,感受纳西文化") +@@ -58,6 +58,6 @@ public class NodeCreateRequest { + @ApiModelProperty(value = "数量", example = "1") + private Integer quantity; + +- @ApiModelProperty(value = "所属家庭ID列表(定制产品按家庭分配)") ++ @ApiModelProperty(value = "所属家庭ID列表(仅CUSTOM定制产品使用,实现按家庭分配行程节点)") + private List familyIds; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java +index a5188da..dacb69c 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java +@@ -28,13 +28,13 @@ public class PriceCalendarRequest { + @ApiModelProperty(value = "儿童成本价", example = "1800.00") + private BigDecimal childCostPrice; + +- @ApiModelProperty(value = "是否自动计算成本", example = "true") ++ @ApiModelProperty(value = "是否自动计算成本(true时重新测算会自动更新此日期的价格)", example = "true") + private Boolean costAutoCalc; + +- @ApiModelProperty(value = "库存数量", example = "30") ++ @ApiModelProperty(value = "库存数量(CORE/GROUP按人头扣减,CUSTOM/ROUTE按单扣减)", example = "30") + private Integer stock; + +- @ApiModelProperty(value = "状态:OPEN=开放 CLOSED=关闭", example = "OPEN") ++ @ApiModelProperty(value = "状态:OPEN=开放预订 CLOSED=关闭(不可预订)", example = "OPEN") + private String status; + + @ApiModelProperty(value = "备注", example = "五一黄金周特价") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java +index 28b7e49..a937367 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java +@@ -11,10 +11,10 @@ import java.util.List; + @ApiModel("定价配置请求") + public class PricingRequest { + +- @ApiModelProperty(value = "定价模式:AUTO=自动计算 MANUAL=手动定价 CUSTOM=定制定价", example = "AUTO") ++ @ApiModelProperty(value = "定价模式:AUTO=根据行程资源价格自动计算 MANUAL=手动在价格日历设置每日价格 CUSTOM=定制产品整单定价", example = "AUTO") + private String pricingMode; + +- @ApiModelProperty(value = "利润模式:FIXED=固定金额 PERCENT=百分比", example = "FIXED") ++ @ApiModelProperty(value = "利润模式(AUTO模式下生效):FIXED=在成本基础上加固定金额 PERCENT=在成本基础上按百分比加价", example = "FIXED") + private String profitMode; + + @ApiModelProperty(value = "利润金额(FIXED模式下使用)", example = "500.00") +@@ -32,16 +32,16 @@ public class PricingRequest { + @ApiModelProperty(value = "餐费预算", example = "100.00") + private BigDecimal mealBudget; + +- @ApiModelProperty(value = "儿童占床价", example = "1800.00") ++ @ApiModelProperty(value = "儿童加床费(childNeedBed=true时额外加收的费用)", example = "1800.00") + private BigDecimal childWithBed; + +- @ApiModelProperty(value = "儿童不占床价", example = "1200.00") ++ @ApiModelProperty(value = "儿童不占床价(暂未使用,预留字段)", example = "1200.00") + private BigDecimal childNoBed; + +- @ApiModelProperty(value = "婴儿价", example = "300.00") ++ @ApiModelProperty(value = "婴儿固定价格(不随日期变化)", example = "300.00") + private BigDecimal babyPrice; + +- @ApiModelProperty(value = "儿童折扣百分比", example = "70.00") ++ @ApiModelProperty(value = "小童折扣百分比(小童价=儿童价×此百分比/100,如70表示打7折)", example = "70.00") + private BigDecimal childDiscountPercent; + + @ApiModelProperty(value = "车型ID列表") +@@ -56,24 +56,24 @@ public class PricingRequest { + @ApiModelProperty(value = "陪同人员价格", example = "0.00") + private BigDecimal companionPrice; + +- @ApiModelProperty(value = "定制产品总价(CUSTOM模式下使用)", example = "28800.00") ++ @ApiModelProperty(value = "定制产品总价(CUSTOM定价模式下使用,代表整单总价)", example = "28800.00") + private BigDecimal customTotalPrice; + +- @ApiModelProperty(value = "最小成团人数", example = "2") ++ @ApiModelProperty(value = "最小成团人数(CORE/GROUP产品用,影响均摊成本计算)", example = "2") + private Integer minGroupSize; + +- @ApiModelProperty(value = "最大成团人数", example = "16") ++ @ApiModelProperty(value = "最大成团人数(CORE/GROUP产品用)", example = "16") + private Integer maxGroupSize; + +- @ApiModelProperty(value = "支付方式:FULL=全款 DEPOSIT=定金+尾款", example = "FULL") ++ @ApiModelProperty(value = "支付方式:FULL=全款支付 DEPOSIT=定金+尾款分期支付", example = "FULL") + private String paymentType; + +- @ApiModelProperty(value = "定金比例(百分比)", example = "30") ++ @ApiModelProperty(value = "定金比例(百分比,如30代表30%。与depositAmount二选一,优先使用比例)", example = "30") + private Integer depositRatio; + +- @ApiModelProperty(value = "定金金额", example = "1000.00") ++ @ApiModelProperty(value = "定金金额(固定金额,与depositRatio二选一)", example = "1000.00") + private BigDecimal depositAmount; + +- @ApiModelProperty(value = "尾款支付截止天数(出发前N天)", example = "7") ++ @ApiModelProperty(value = "尾款支付截止天数(出发前N天必须支付尾款,超时可能取消订单)", example = "7") + private Integer balanceDueDays; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java +index 23e1203..99033be 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java +@@ -10,10 +10,11 @@ import javax.validation.constraints.NotBlank; + @ApiModel("产品状态变更请求") + public class ProductStatusRequest { + +- @ApiModelProperty(value = "目标状态:DRAFT/PENDING_REVIEW/REVIEWED/REJECTED/PUBLISHED/UNPUBLISHED/COMPLETED", required = true, example = "PUBLISHED") ++ @ApiModelProperty(value = "目标状态。核心/小蒙马:DRAFT/PENDING_REVIEW/REVIEWED/REJECTED/PUBLISHED/UNPUBLISHED;定制产品:COMPLETED", ++ required = true, example = "PUBLISHED") + @NotBlank(message = "目标状态不能为空") + private String status; + +- @ApiModelProperty(value = "状态变更原因(驳回时必填)", example = "行程信息不完整,请补充") ++ @ApiModelProperty(value = "状态变更原因(驳回时必填;上架/下架审批时可填)", example = "行程信息不完整,请补充") + private String reason; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java +index fd39d97..92c28aa 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java +@@ -21,18 +21,18 @@ public class QuoteRequest { + @Min(value = 1, message = "成人人数最少1人") + private Integer adultCount; + +- @ApiModelProperty(value = "儿童人数(占床)", example = "1") ++ @ApiModelProperty(value = "儿童人数(占床,按儿童价计算)", example = "1") + @Min(value = 0, message = "儿童人数不能为负数") + private Integer childCount = 0; + +- @ApiModelProperty(value = "小童人数(不占床)", example = "0") ++ @ApiModelProperty(value = "小童人数(不占床,按儿童价 × childDiscountPercent 折扣比例计算)", example = "0") + @Min(value = 0, message = "小童人数不能为负数") + private Integer youngChildCount = 0; + +- @ApiModelProperty(value = "婴儿人数", example = "0") ++ @ApiModelProperty(value = "婴儿人数(按固定 babyPrice 计算)", example = "0") + @Min(value = 0, message = "幼童人数不能为负数") + private Integer babyCount = 0; + +- @ApiModelProperty(value = "儿童是否加床", example = "false") ++ @ApiModelProperty(value = "儿童是否加床(true 时额外加收 childWithBed 费用)", example = "false") + private Boolean childNeedBed = false; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java +index 46060ff..63b4dc9 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("批量素材ID请求") + public class BatchMaterialIdsRequest { + ++ @ApiModelProperty("素材ID列表") + private List materialIds; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java +index e859cea..53c0c3d 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("批量引用绑定请求") + public class RefBatchBindRequest { + ++ @ApiModelProperty("引用绑定列表") + private List refs; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java +index 965c0e9..b532ee1 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("批量引用解绑请求") + public class RefBatchUnbindRequest { + ++ @ApiModelProperty("引用解绑列表") + private List refs; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java +index 8d95b02..16fdb65 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,11 +9,21 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("引用绑定请求") + public class RefBindRequest { + ++ @ApiModelProperty("素材ID") + private Long materialId; ++ ++ @ApiModelProperty("业务类型") + private String bizType; ++ ++ @ApiModelProperty("业务ID") + private Long bizId; ++ ++ @ApiModelProperty("业务名称") + private String bizName; ++ ++ @ApiModelProperty("用途类型") + private String usageType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java +index 04252db..cdd7901 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,10 +9,18 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("引用解绑请求") + public class RefUnbindRequest { + ++ @ApiModelProperty("素材ID") + private Long materialId; ++ ++ @ApiModelProperty("业务类型") + private String bizType; ++ ++ @ApiModelProperty("业务ID") + private Long bizId; ++ ++ @ApiModelProperty("用途类型") + private String usageType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java +index da0d81d..9188dfb 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,7 +9,12 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源封面查询") + public class ResourceCoverQuery { ++ ++ @ApiModelProperty("资源类型") + private String resourceType; ++ ++ @ApiModelProperty("资源ID") + private String resourceId; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java +index 90b98cf..685d2e0 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Builder; + import lombok.Data; +@@ -12,16 +14,21 @@ import java.util.List; + @Builder + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源价格查询") + public class ResourcePriceQuery { + ++ @ApiModelProperty("资源ID列表") + private List resourceIds; + ++ @ApiModelProperty("人员类型列表") + private List staffTypes; + ++ @ApiModelProperty("开始日期") + private LocalDate startDate; + ++ @ApiModelProperty("结束日期") + private LocalDate endDate; + +- /** resource sub-type (e.g. room_type_id for hotel, vehicle category for vehicle) */ ++ @ApiModelProperty("资源子类型(如酒店房型ID、车辆类别)") + private String subType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java +index d072f29..ec5b204 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java +@@ -1,13 +1,25 @@ + package com.hulalv.product.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("素材信息VO") + public class MaterialVO { + ++ @ApiModelProperty("素材ID") + private String materialId; ++ ++ @ApiModelProperty("OSS访问URL") + private String ossUrl; ++ ++ @ApiModelProperty("缩略图URL") + private String thumbnailUrl; ++ ++ @ApiModelProperty("素材名称") + private String materialName; ++ ++ @ApiModelProperty("文件类型") + private String fileType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java +index 4cf6dae..232915a 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Builder; + import lombok.Data; +@@ -12,15 +14,21 @@ import java.time.LocalDate; + @Builder + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源价格VO") + public class ResourcePriceVO { + ++ @ApiModelProperty("资源ID") + private Long resourceId; + ++ @ApiModelProperty("人员类型") + private String staffType; + ++ @ApiModelProperty("日期") + private LocalDate date; + ++ @ApiModelProperty("价格") + private BigDecimal price; + ++ @ApiModelProperty("资源名称") + private String resourceName; + } +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java +index 629213d..23de858 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java +@@ -61,8 +61,8 @@ public class RestaurantCreateRequest { + @Size(max = 30) + private String district; + +- @ApiModelProperty(value = "城市标签", required = true, example = "拉萨") +- @NotBlank(message = "城市标签不能为空") ++ @ApiModelProperty(value = "城市名称(纯文本输入)", required = true, example = "拉萨") ++ @NotBlank(message = "城市名称不能为空") + @Size(max = 30) + private String cityName; + +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java +index 34e331b..ba2f6e9 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java +@@ -25,7 +25,7 @@ public class RestaurantQueryRequest { + @ApiModelProperty(value = "省份", example = "西藏自治区") + private String province; + +- @ApiModelProperty(value = "城市标签", example = "拉萨") ++ @ApiModelProperty(value = "城市名称筛选(纯文本)", example = "拉萨") + private String cityName; + + @ApiModelProperty(value = "城市", example = "拉萨市") +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java +index 8b62d81..51eb13c 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java +@@ -57,7 +57,7 @@ public class RestaurantUpdateRequest { + @Size(max = 30) + private String district; + +- @ApiModelProperty(value = "城市标签", example = "拉萨") ++ @ApiModelProperty(value = "城市名称(纯文本输入)", example = "拉萨") + @Size(max = 30) + private String cityName; + +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java +index df37c80..f0d4d24 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java +@@ -36,7 +36,7 @@ public class RestaurantListVO { + @ApiModelProperty("人均消费(元)") + private BigDecimal pricePerPerson; + +- @ApiModelProperty("城市标签") ++ @ApiModelProperty("城市名称(纯文本)") + private String cityName; + + @ApiModelProperty("亮点摘要") +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java +index acfd3d8..4396d6e 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java +@@ -54,7 +54,7 @@ public class RestaurantVO { + @ApiModelProperty("区县") + private String district; + +- @ApiModelProperty("城市标签") ++ @ApiModelProperty("城市名称(纯文本)") + private String cityName; + + @ApiModelProperty("详细地址") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java +index 3dcbbb3..3bde0cd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java +@@ -6,13 +6,15 @@ import lombok.Data; + import javax.validation.constraints.NotBlank; + + @Data +-@ApiModel("管理员登录请求") ++@ApiModel(value = "管理员登录请求", description = "后台管理员通过用户名+密码登录,新设备首次登录需2FA验证") + public class AdminLoginRequest { +- @ApiModelProperty(value = "用户名", required = true, example = "admin") ++ @ApiModelProperty(value = "用户名", required = true, example = "admin", ++ notes = "管理员账号的用户名,由SUPER_ADMIN创建时指定") + @NotBlank(message = "用户名不能为空") + private String username; + +- @ApiModelProperty(value = "密码", required = true, example = "Admin@2026") ++ @ApiModelProperty(value = "密码", required = true, example = "Admin@2026", ++ notes = "须包含大小写字母和数字,长度8-128位。默认密码为Admin@123456") + @NotBlank(message = "密码不能为空") + private String password; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java +index 9c59721..160c8c7 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java +@@ -9,7 +9,7 @@ import javax.validation.constraints.NotBlank; + @Data + @ApiModel("联系我们请求") + public class ContactRequest { +- @ApiModelProperty(value = "渠道类型:ABOUT=关于我们 ONLINE_CS=在线客服 PHONE=电话咨询", required = true, example = "PHONE") ++ @ApiModelProperty(value = "渠道类型,关联字典contact_channel_type:ABOUT=关于我们, ONLINE_CS=在线客服, PHONE=电话咨询", required = true, example = "PHONE") + @NotBlank(message = "渠道类型不能为空") + private String channelType; + +@@ -32,6 +32,6 @@ public class ContactRequest { + @ApiModelProperty(value = "排序号(越小越靠前)", example = "1") + private Integer sortOrder; + +- @ApiModelProperty(value = "状态:0=下线 1=上线", example = "1") ++ @ApiModelProperty(value = "状态,关联字典common_status:0=下线, 1=上线", example = "1") + private Integer status; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java +index 5d0ffe3..72f20fd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java +@@ -7,17 +7,20 @@ import javax.validation.constraints.NotBlank; + import java.util.List; + + @Data +-@ApiModel("创建管理员请求") ++@ApiModel(value = "创建管理员请求", description = "创建后台管理员账号,默认密码Admin@123456") + public class CreateAdminRequest { +- @ApiModelProperty(value = "用户名", required = true, example = "zhangsan") ++ @ApiModelProperty(value = "用户名", required = true, example = "zhangsan", ++ notes = "全局唯一的登录用户名,创建后不可修改") + @NotBlank(message = "用户名不能为空") + private String username; + + /** 角色ID列表(多角色),兼容旧的单角色 roleId */ +- @ApiModelProperty(value = "角色ID列表(多角色)", example = "[1,2]") ++ @ApiModelProperty(value = "角色ID列表(多角色)", example = "[1,2]", ++ notes = "支持分配多个角色,管理员登录后可通过切换角色接口切换当前活跃角色") + private List roleIds; + + /** @deprecated 兼容旧接口,优先使用 roleIds */ +- @ApiModelProperty(value = "角色ID(已废弃,请使用roleIds)", example = "1") ++ @ApiModelProperty(value = "角色ID(已废弃,请使用roleIds)", example = "1", ++ notes = "兼容旧接口的单角色参数,优先使用roleIds") + private Long roleId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java +index dff93b6..5d8d05b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java +@@ -12,18 +12,18 @@ public class CreateJobRequest { + @NotBlank(message = "任务名称不能为空") + private String jobName; + +- @ApiModelProperty(value = "任务分组", example = "SYSTEM") ++ @ApiModelProperty(value = "任务分组,字典类型:job_group(DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步)", example = "SYSTEM") + private String jobGroup; + +- @ApiModelProperty(value = "调用目标(Bean名称.方法名)", required = true, example = "wechatSyncService.syncDepartments") ++ @ApiModelProperty(value = "调用目标(Bean名称.方法名),方法必须是无参公开方法", required = true, example = "wechatSyncService.syncDepartments") + @NotBlank(message = "调用目标不能为空") + private String invokeTarget; + +- @ApiModelProperty(value = "Cron表达式", required = true, example = "0 0 2 * * ?") ++ @ApiModelProperty(value = "Cron表达式,标准6位(秒 分 时 日 月 周)", required = true, example = "0 0 2 * * ?") + @NotBlank(message = "Cron表达式不能为空") + private String cronExpression; + +- @ApiModelProperty(value = "计划执行策略:0=默认 1=立即触发 2=触发一次 3=不触发", example = "0") ++ @ApiModelProperty(value = "计划执行策略,字典类型:job_misfire_policy(DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发)", example = "DEFAULT") + private String misfirePolicy; + + @ApiModelProperty(value = "是否允许并发执行", example = "false") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java +index cbb0455..b7b4fbb 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java +@@ -7,13 +7,15 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.NotNull; + + @Data +-@ApiModel("收藏请求") ++@ApiModel(value = "收藏请求", description = "添加收藏时的请求体,指定收藏的资源类型和ID") + public class FavoriteRequest { +- @ApiModelProperty(value = "收藏类型", required = true, example = "SCENIC_SPOT") ++ @ApiModelProperty(value = "收藏类型,关联字典favorite_resource_type", required = true, example = "SCENIC_SPOT", ++ notes = "可选值:SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索分类") + @NotBlank(message = "目标类型不能为空") + private String targetType; + +- @ApiModelProperty(value = "收藏目标ID", required = true, example = "1") ++ @ApiModelProperty(value = "收藏目标ID", required = true, example = "1", ++ notes = "对应资源的ID,如景区ID、活动ID等") + @NotNull(message = "目标ID不能为空") + private Long targetId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java +index 6a9905c..a700a4d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java +@@ -7,13 +7,15 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.NotNull; + + @Data +-@ApiModel("足迹请求") ++@ApiModel(value = "足迹请求", description = "记录用户浏览足迹时的请求体") + public class FootprintRequest { +- @ApiModelProperty(value = "资源类型", required = true, example = "SCENIC_SPOT") ++ @ApiModelProperty(value = "资源类型,关联字典footprint_resource_type", required = true, example = "SCENIC_SPOT", ++ notes = "可选值:SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品") + @NotBlank(message = "资源类型不能为空") + private String resourceType; + +- @ApiModelProperty(value = "资源ID", required = true, example = "1") ++ @ApiModelProperty(value = "资源ID", required = true, example = "1", ++ notes = "对应资源的ID,同一用户同一资源只保留最新一条足迹") + @NotNull(message = "资源ID不能为空") + private Long resourceId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java +index e8ff874..bdc2f40 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java +@@ -6,18 +6,22 @@ import lombok.Data; + import javax.validation.constraints.NotBlank; + + @Data +-@ApiModel("微信小程序登录请求") ++@ApiModel(value = "微信小程序登录请求", description = "通过wx.login获取code进行登录,首次登录自动注册") + public class LoginRequest { +- @ApiModelProperty(value = "微信登录授权码", required = true, example = "0c3NKj000...") ++ @ApiModelProperty(value = "微信登录授权码", required = true, example = "0c3NKj000...", ++ notes = "通过wx.login()获取的临时授权码,后端用此code换取openid/unionid") + @NotBlank(message = "微信code不能为空") + private String code; + +- @ApiModelProperty(value = "手机号授权码(用于获取手机号)", example = "0c3NKj000...") ++ @ApiModelProperty(value = "手机号授权码(用于获取手机号)", example = "0c3NKj000...", ++ notes = "通过getPhoneNumber按钮获取的code,后端用此code换取用户手机号并绑定") + private String phoneCode; + +- @ApiModelProperty(value = "用户头像URL", example = "https://thirdwx.qlogo.cn/xxx") ++ @ApiModelProperty(value = "用户头像URL", example = "https://thirdwx.qlogo.cn/xxx", ++ notes = "微信头像地址,首次登录时传入用于设置用户头像") + private String avatar; + +- @ApiModelProperty(value = "用户昵称", example = "微信用户") ++ @ApiModelProperty(value = "用户昵称", example = "微信用户", ++ notes = "微信昵称,首次登录时传入用于设置用户昵称") + private String nickname; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java +index 48d700d..945424d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java +@@ -7,10 +7,11 @@ import lombok.Data; + import javax.validation.constraints.NotNull; + + @Data +-@ApiModel("角色切换请求") ++@ApiModel(value = "角色切换请求", description = "多角色管理员切换当前活跃角色") + public class SwitchRoleRequest { + + @NotNull(message = "角色ID不能为空") +- @ApiModelProperty(value = "目标角色ID", required = true) ++ @ApiModelProperty(value = "目标角色ID", required = true, ++ notes = "只能切换到当前管理员已分配的角色,切换后返回新Token和对应菜单权限") + private Long roleId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java +index f8d33c8..1c67bb6 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java +@@ -15,10 +15,10 @@ public class TravelerRequest { + @Size(max = 50, message = "姓名长度不能超过50个字符") + private String name; + +- @ApiModelProperty(value = "出行人类型(无需传入,后端根据出生日期自动判断)", hidden = true) ++ @ApiModelProperty(value = "出行人类型,关联字典traveler_type:ADULT=成人, CHILD=儿童, INFANT=婴儿(无需传入,后端根据birthday自动判断)", hidden = true) + private String travelerType; // auto-resolved from birthday + +- @ApiModelProperty(value = "证件类型:ID_CARD=身份证 PASSPORT=护照", example = "ID_CARD") ++ @ApiModelProperty(value = "证件类型,关联字典id_card_type:ID_CARD=身份证, PASSPORT=护照", example = "ID_CARD") + private String idCardType; // Default: ID_CARD + + @ApiModelProperty(value = "证件号码", example = "110101199001011234") +@@ -29,7 +29,7 @@ public class TravelerRequest { + @Size(max = 20, message = "手机号长度不能超过20个字符") + private String phone; + +- @ApiModelProperty(value = "性别:0=女 1=男", example = "1") ++ @ApiModelProperty(value = "性别,关联字典gender:0=女, 1=男", example = "1") + private Integer gender; // 0=female, 1=male + + @ApiModelProperty(value = "出生日期(必填,后端根据此字段自动判断人员类型)", required = true, example = "1990-01-01") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java +index 273a9bc..1e4c1f4 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java +@@ -7,13 +7,15 @@ import lombok.Data; + import javax.validation.constraints.NotBlank; + + @Data +-@ApiModel("头像更新请求") ++@ApiModel(value = "头像更新请求", description = "更新管理员头像,需先通过文件服务上传图片") + public class UpdateAvatarRequest { + + @NotBlank(message = "头像URL不能为空") +- @ApiModelProperty(value = "头像URL", required = true) ++ @ApiModelProperty(value = "头像URL", required = true, ++ notes = "文件服务返回的OSS URL地址") + private String avatar; + +- @ApiModelProperty("文件ID") ++ @ApiModelProperty(value = "文件ID", ++ notes = "文件服务返回的fileId,用于建立文件引用关系,传入后旧头像引用自动解绑") + private Long fileId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java +index a42399c..4e85a2a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java +@@ -10,16 +10,16 @@ public class UpdateJobRequest { + @ApiModelProperty(value = "任务名称", example = "同步企微通讯录") + private String jobName; + +- @ApiModelProperty(value = "任务分组", example = "SYSTEM") ++ @ApiModelProperty(value = "任务分组,字典类型:job_group(DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步)", example = "SYSTEM") + private String jobGroup; + +- @ApiModelProperty(value = "调用目标(Bean名称.方法名)", example = "wechatSyncService.syncDepartments") ++ @ApiModelProperty(value = "调用目标(Bean名称.方法名),方法必须是无参公开方法", example = "wechatSyncService.syncDepartments") + private String invokeTarget; + +- @ApiModelProperty(value = "Cron表达式", example = "0 0 2 * * ?") ++ @ApiModelProperty(value = "Cron表达式,标准6位(秒 分 时 日 月 周)", example = "0 0 2 * * ?") + private String cronExpression; + +- @ApiModelProperty(value = "计划执行策略:0=默认 1=立即触发 2=触发一次 3=不触发", example = "0") ++ @ApiModelProperty(value = "计划执行策略,字典类型:job_misfire_policy(DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发)", example = "DEFAULT") + private String misfirePolicy; + + @ApiModelProperty(value = "是否允许并发执行", example = "false") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java b/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java +index 228bb27..2a3ee4f 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.user.notification.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import javax.validation.constraints.NotBlank; +@@ -10,28 +12,31 @@ import java.util.List; + * 自定义推送请求 + */ + @Data ++@ApiModel("自定义推送请求") + public class CustomPushRequest { + ++ @ApiModelProperty("推送标题") + @NotBlank(message = "推送标题不能为空") + private String title; + ++ @ApiModelProperty("推送内容") + @NotBlank(message = "推送内容不能为空") + private String content; + +- /** 推送通道: INAPP, SMS, WECHAT_WORK */ ++ @ApiModelProperty("推送通道: INAPP/SMS/WECHAT_WORK") + @NotNull(message = "请选择推送通道") + private String channel; + +- /** 目标类型: ALL_USERS, SPECIFIC_USERS */ ++ @ApiModelProperty("目标类型: ALL_USERS/SPECIFIC_USERS") + @NotNull(message = "请选择目标类型") + private String targetType; + +- /** targetType=SPECIFIC_USERS时必填 */ ++ @ApiModelProperty("目标用户ID列表(目标类型为SPECIFIC_USERS时必填)") + private List userIds; + +- /** 消息分类编码,默认SYSTEM */ ++ @ApiModelProperty("消息分类编码,默认SYSTEM") + private String categoryCode; + +- /** 跳转链接(站内信时使用) */ ++ @ApiModelProperty("跳转链接(站内信时使用)") + private String link; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java +index e3cdaf2..495cb3d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java +@@ -1,19 +1,22 @@ + package com.hulalv.user.notification.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + /** + * 自定义推送结果 + */ + @Data ++@ApiModel("自定义推送结果VO") + public class CustomPushResultVO { + +- /** 推送总数 */ ++ @ApiModelProperty("推送总数") + private int totalCount; + +- /** 成功数 */ ++ @ApiModelProperty("成功数") + private int successCount; + +- /** 失败数 */ ++ @ApiModelProperty("失败数") + private int failCount; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java +index 8b7e7d1..7434992 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java +@@ -21,7 +21,7 @@ public class EventConfigVO { + @ApiModelProperty("所属分类名称") + private String categoryName; + +- @ApiModelProperty("站内信开关") ++ @ApiModelProperty("站内信开关(0=关闭, 1=开启)") + private Integer inappEnabled; + + @ApiModelProperty("站内信标题模板") +@@ -33,7 +33,7 @@ public class EventConfigVO { + @ApiModelProperty("站内信跳转路径模板") + private String inappLinkTemplate; + +- @ApiModelProperty("短信开关") ++ @ApiModelProperty("短信开关(0=关闭, 1=开启)") + private Integer smsEnabled; + + @ApiModelProperty("阿里云短信模板编号") +@@ -42,7 +42,7 @@ public class EventConfigVO { + @ApiModelProperty("短信签名") + private String smsSignName; + +- @ApiModelProperty("小程序订阅消息开关") ++ @ApiModelProperty("小程序订阅消息开关(0=关闭, 1=开启)") + private Integer miniappEnabled; + + @ApiModelProperty("微信订阅消息模板ID") +@@ -54,7 +54,7 @@ public class EventConfigVO { + @ApiModelProperty("小程序字段映射JSON") + private String miniappFieldMapping; + +- @ApiModelProperty("公众号模板消息开关") ++ @ApiModelProperty("公众号模板消息开关(0=关闭, 1=开启)") + private Integer oaEnabled; + + @ApiModelProperty("公众号模板ID") +@@ -66,10 +66,10 @@ public class EventConfigVO { + @ApiModelProperty("公众号字段映射JSON") + private String oaFieldMapping; + +- @ApiModelProperty("企微通知开关") ++ @ApiModelProperty("企微通知开关(0=关闭, 1=开启)") + private Integer weworkEnabled; + +- @ApiModelProperty("企微接收人类型") ++ @ApiModelProperty("企微接收人类型(ROLE=按角色, DEPT=按部门, SPECIFIC=指定人员)") + private String weworkReceiverType; + + @ApiModelProperty("企微消息内容模板") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java +index 8e44260..52c307c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java +@@ -14,7 +14,7 @@ public class SendLogVO { + @ApiModelProperty("事件编码") + private String eventCode; + +- @ApiModelProperty("通道: INAPP/SMS/MINIAPP/OA/WEWORK") ++ @ApiModelProperty("通道,关联字典notification_channel:INAPP=站内信, SMS=短信, MINIAPP=小程序订阅, OA=公众号模板, WEWORK=企业微信") + private String channel; + + @ApiModelProperty("用户ID") +@@ -38,7 +38,7 @@ public class SendLogVO { + @ApiModelProperty("关联业务类型") + private String bizType; + +- @ApiModelProperty("发送状态: 0成功 1失败 2跳过") ++ @ApiModelProperty("发送状态,关联字典notification_send_status:0=成功, 1=失败, 2=跳过") + private Integer status; + + @ApiModelProperty("失败原因") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java +index 448b5df..9ad4b62 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java +@@ -1,18 +1,25 @@ + package com.hulalv.user.notification.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + /** + * 用户简要信息(自定义推送选择目标用户时使用) + */ + @Data ++@ApiModel("用户简要信息VO") + public class UserSimpleVO { + ++ @ApiModelProperty("用户ID") + private Long id; + ++ @ApiModelProperty("真实姓名") + private String realName; + ++ @ApiModelProperty("手机号") + private String phone; + ++ @ApiModelProperty("头像URL") + private String avatarUrl; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java +index 8bd3d9d..53a203c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java +@@ -14,7 +14,7 @@ public class ContactVO { + @ApiModelProperty(value = "联系方式ID") + private String id; + +- @ApiModelProperty(value = "渠道类型:ABOUT=关于我们 ONLINE_CS=在线客服 PHONE=电话咨询") ++ @ApiModelProperty(value = "渠道类型,关联字典contact_channel_type:ABOUT=关于我们, ONLINE_CS=在线客服, PHONE=电话咨询") + private String channelType; + + @ApiModelProperty(value = "标题") +@@ -35,7 +35,7 @@ public class ContactVO { + @ApiModelProperty(value = "排序号") + private Integer sortOrder; + +- @ApiModelProperty(value = "状态:0=下线 1=上线") ++ @ApiModelProperty(value = "状态,关联字典common_status:0=下线, 1=上线") + private Integer status; + + @ApiModelProperty(value = "创建时间") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java +index d72a7b3..be9f83a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java +@@ -26,7 +26,7 @@ public class CustomerVO { + @ApiModelProperty(value = "手机号(不脱敏)") + private String phone; + +- @ApiModelProperty(value = "状态:ACTIVE=正常 DISABLED=禁用") ++ @ApiModelProperty(value = "状态,关联字典user_status:ACTIVE=正常, BANNED=已封禁") + private String status; + + @ApiModelProperty(value = "创建时间") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java +index 89620fe..3582c3d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java +@@ -18,7 +18,7 @@ public class LoginLogVO { + @ApiModelProperty(value = "管理员名称") + private String adminName; + +- @ApiModelProperty(value = "登录方式:PASSWORD=密码 WECHAT=企微扫码 TWO_FA=二次验证") ++ @ApiModelProperty(value = "登录方式,关联字典login_method:PASSWORD=密码登录, WECHAT_QR=企微扫码登录, TWO_FA=二次验证登录") + private String loginMethod; + + @ApiModelProperty(value = "登录IP地址") +@@ -36,7 +36,7 @@ public class LoginLogVO { + @ApiModelProperty(value = "登录地区") + private String location; + +- @ApiModelProperty(value = "登录状态:SUCCESS=成功 FAILED=失败") ++ @ApiModelProperty(value = "登录状态,关联字典login_status:SUCCESS=成功, FAILED=失败") + private String status; + + @ApiModelProperty(value = "失败原因") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java +index cb64d33..bbc0ede 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java +@@ -29,20 +29,20 @@ public class UserVO { + @ApiModelProperty(value = "真实手机号(仅内部接口返回,用于订单预填)", hidden = true) + private String rawPhone; // 真实手机号(仅内部接口返回,用于订单预填) + +- @ApiModelProperty(value = "状态:ACTIVE=正常 DISABLED=禁用") ++ @ApiModelProperty(value = "状态,关联字典user_status:ACTIVE=正常, BANNED=已封禁") + private String status; + + // 个人信息字段(用于编辑"本人"出行人信息) + @ApiModelProperty(value = "真实姓名") + private String realName; + +- @ApiModelProperty(value = "证件类型:ID_CARD=身份证 PASSPORT=护照") ++ @ApiModelProperty(value = "证件类型,关联字典id_card_type:ID_CARD=身份证, PASSPORT=护照") + private String idCardType; + + @ApiModelProperty(value = "证件号码") + private String idCardNo; + +- @ApiModelProperty(value = "性别:0=女 1=男") ++ @ApiModelProperty(value = "性别,关联字典gender:0=女, 1=男") + private Integer gender; + + @ApiModelProperty(value = "出生日期") +``` + +## 数据库变更 (SQL) + +### `sql/add_customer_service_role.sql` (A) + +```sql +-- 新增客服角色 +-- 权限:查看全部订单、全部产品(含定制产品)、配置保险、配置合同、查看素材 + +-- 1. 创建角色 +INSERT INTO sys_role (role_id, role_name, role_key, sort_order, status) +VALUES (8, '客服', 'CUSTOMER_SERVICE', 8, 'ACTIVE'); + +-- 2. 分配菜单权限 +INSERT INTO sys_role_menu (role_id, menu_id) VALUES +-- 订单管理(查看,不含创建) +(8, 700), -- 订单管理(目录) +(8, 710), -- 订单列表 +(8, 730), -- 订单详情 +(8, 740), -- 早鸟优惠 +(8, 750), -- 工单管理 +-- 退款管理(查看) +(8, 6001), -- 退款管理(目录) +(8, 6010), -- 退款申请 +(8, 6020), -- 退款政策 +(8, 6030), -- 退款原因 +-- 产品管理(查看全部,含定制产品,不含增删改按钮) +(8, 500), -- 产品管理(目录) +(8, 510), -- 产品列表 +(8, 520), -- 产品线管理 +(8, 530), -- 团期管理 +-- 保险管理(配置) +(8, 800), -- 保险管理(目录) +(8, 810), -- 保险产品 +(8, 820), -- 保险订单 +(8, 830), -- 保险方案 +-- 合同管理(配置) +(8, 850), -- 合同管理(目录) +(8, 851), -- 合同列表 +(8, 852), -- 补充约定模板 +-- 素材库(查看) +(8, 1890000000000000100); -- 素材库 +``` + +### `sql/dict_data_seed.sql` (M) + +```diff +diff --git a/sql/dict_data_seed.sql b/sql/dict_data_seed.sql +index b4646bd..933fd27 100644 +--- a/sql/dict_data_seed.sql ++++ b/sql/dict_data_seed.sql +@@ -5,7 +5,7 @@ + USE hl_user_service; + + -- ============================================================ +--- Dict Types (7 types) ++-- Dict Types (9 types) + -- ============================================================ + INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status, remark, created_at, updated_at) + VALUES +@@ -15,7 +15,9 @@ VALUES + (4, '字典分类', 'dict_category', 'BASE', 'ACTIVE', NULL, NOW(), NOW()), + (5, '任务补偿策略', 'job_misfire_policy', 'BASE', 'ACTIVE', NULL, NOW(), NOW()), + (6, '部门状态', 'dept_status', 'BASE', 'ACTIVE', NULL, NOW(), NOW()), +- (7, '任务日志状态', 'job_log_status', 'BASE', 'ACTIVE', NULL, NOW(), NOW()); ++ (7, '任务日志状态', 'job_log_status', 'BASE', 'ACTIVE', NULL, NOW(), NOW()), ++ (8, '任务状态', 'job_status', 'BASE', 'ACTIVE', NULL, NOW(), NOW()), ++ (9, '任务分组', 'job_group', 'BASE', 'ACTIVE', NULL, NOW(), NOW()); + + -- ============================================================ + -- Dict Data (remark stores el-tag type for styling) +@@ -67,4 +69,18 @@ VALUES + (701, 'job_log_status', '成功', 'SUCCESS', 1, 'ACTIVE', 'success', NOW(), NOW()), + (702, 'job_log_status', '失败', 'FAIL', 2, 'ACTIVE', 'danger', NOW(), NOW()); + ++-- job_status ++INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status, remark, created_at, updated_at) ++VALUES ++ (801, 'job_status', '启用', 'ACTIVE', 1, 'ACTIVE', 'success', NOW(), NOW()), ++ (802, 'job_status', '已暂停', 'PAUSED', 2, 'ACTIVE', 'info', NOW(), NOW()); ++ ++-- job_group ++INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status, remark, created_at, updated_at) ++VALUES ++ (901, 'job_group', '默认分组', 'DEFAULT', 1, 'ACTIVE', '', NOW(), NOW()), ++ (902, 'job_group', '系统任务', 'SYSTEM', 2, 'ACTIVE', 'primary', NOW(), NOW()), ++ (903, 'job_group', '企微同步', 'WECHAT', 3, 'ACTIVE', 'success', NOW(), NOW()), ++ (904, 'job_group', '保险同步', 'INSURANCE', 4, 'ACTIVE', 'warning', NOW(), NOW()); ++ + SELECT 'Seed complete' AS result; +``` + +### `sql/dict_fix_frontend.sql` (A) + +```sql +-- ============================================================ +-- 前端缺失的字典类型和字典数据补齐 +-- 对比前端 hl-ui 代码 vs 后端 sys_dict_type 表 +-- ============================================================ + +-- 1. cities - 城市(树形字典,MobilePreview/useLocation用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000001, '城市', 'cities', 'BASE', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900100001, 'cities', '海拉尔', 'hailar', 1, 'ACTIVE'), +(1900100002, 'cities', '满洲里', 'manzhouli', 2, 'ACTIVE'), +(1900100003, 'cities', '额尔古纳', 'eergu', 3, 'ACTIVE'), +(1900100004, 'cities', '根河', 'genhe', 4, 'ACTIVE'), +(1900100005, 'cities', '牙克石', 'yakeshi', 5, 'ACTIVE'), +(1900100006, 'cities', '扎兰屯', 'zhalantun', 6, 'ACTIVE'), +(1900100007, 'cities', '阿尔山', 'aershan', 7, 'ACTIVE'), +(1900100008, 'cities', '室韦', 'shiwei', 8, 'ACTIVE'), +(1900100009, 'cities', '恩和', 'enhe', 9, 'ACTIVE'), +(1900100010, 'cities', '黑山头', 'heishantou', 10, 'ACTIVE'), +(1900100011, 'cities', '陈巴尔虎旗', 'chenbaerhu', 11, 'ACTIVE'), +(1900100012, 'cities', '新巴尔虎左旗', 'xinbaerhuzuo', 12, 'ACTIVE'), +(1900100013, 'cities', '新巴尔虎右旗', 'xinbaerhuyou', 13, 'ACTIVE'), +(1900100014, 'cities', '鄂温克旗', 'ewenke', 14, 'ACTIVE'), +(1900100015, 'cities', '莫尔道嘎', 'moerdaoga', 15, 'ACTIVE'); + +-- 2. city - 城市筛选(产品行程资源面板用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000002, '城市筛选', 'city', 'BASE', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900200001, 'city', '海拉尔', 'hailar', 1, 'ACTIVE'), +(1900200002, 'city', '满洲里', 'manzhouli', 2, 'ACTIVE'), +(1900200003, 'city', '额尔古纳', 'eergu', 3, 'ACTIVE'), +(1900200004, 'city', '根河', 'genhe', 4, 'ACTIVE'), +(1900200005, 'city', '阿尔山', 'aershan', 5, 'ACTIVE'), +(1900200006, 'city', '室韦', 'shiwei', 6, 'ACTIVE'), +(1900200007, 'city', '恩和', 'enhe', 7, 'ACTIVE'), +(1900200008, 'city', '黑山头', 'heishantou', 8, 'ACTIVE'); + +-- 3. city_label - 城市标签(餐厅列表筛选用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000003, '城市标签', 'city_label', 'BASE', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900300001, 'city_label', '海拉尔', 'hailar', 1, 'ACTIVE'), +(1900300002, 'city_label', '满洲里', 'manzhouli', 2, 'ACTIVE'), +(1900300003, 'city_label', '额尔古纳', 'eergu', 3, 'ACTIVE'), +(1900300004, 'city_label', '根河', 'genhe', 4, 'ACTIVE'), +(1900300005, 'city_label', '阿尔山', 'aershan', 5, 'ACTIVE'), +(1900300006, 'city_label', '室韦', 'shiwei', 6, 'ACTIVE'), +(1900300007, 'city_label', '恩和', 'enhe', 7, 'ACTIVE'), +(1900300008, 'city_label', '黑山头', 'heishantou', 8, 'ACTIVE'); + +-- 4. environment_type - 环境类型(餐厅编辑用,前端key是environment_type) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000004, '环境类型', 'environment_type', 'BASE', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900400001, 'environment_type', '室内', 'INDOOR', 1, 'ACTIVE'), +(1900400002, 'environment_type', '户外', 'OUTDOOR', 2, 'ACTIVE'), +(1900400003, 'environment_type', '混合', 'MIXED', 3, 'ACTIVE'); + +-- 5. cost_unit - 费用计价单位(费用项编辑用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000005, '费用计价单位', 'cost_unit', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900500001, 'cost_unit', '元/人', 'PER_PERSON', 1, 'ACTIVE'), +(1900500002, 'cost_unit', '元/台', 'PER_VEHICLE', 2, 'ACTIVE'), +(1900500003, 'cost_unit', '元/天', 'PER_DAY', 3, 'ACTIVE'), +(1900500004, 'cost_unit', '元/次', 'PER_TIME', 4, 'ACTIVE'), +(1900500005, 'cost_unit', '元/间', 'PER_ROOM', 5, 'ACTIVE'), +(1900500006, 'cost_unit', '元/桌', 'PER_TABLE', 6, 'ACTIVE'), +(1900500007, 'cost_unit', '固定金额', 'FIXED', 7, 'ACTIVE'); + +-- 6. service_unit - 服务计价单位(服务项编辑用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000006, '服务计价单位', 'service_unit', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900600001, 'service_unit', '元/人', 'PER_PERSON', 1, 'ACTIVE'), +(1900600002, 'service_unit', '元/次', 'PER_TIME', 2, 'ACTIVE'), +(1900600003, 'service_unit', '元/天', 'PER_DAY', 3, 'ACTIVE'), +(1900600004, 'service_unit', '元/台', 'PER_VEHICLE', 4, 'ACTIVE'), +(1900600005, 'service_unit', '固定金额', 'FIXED', 5, 'ACTIVE'); + +-- 7. material_tag - 素材标签(素材上传/编辑用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000007, '素材标签', 'material_tag', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900700001, 'material_tag', '风景', 'landscape', 1, 'ACTIVE'), +(1900700002, 'material_tag', '人物', 'portrait', 2, 'ACTIVE'), +(1900700003, 'material_tag', '美食', 'food', 3, 'ACTIVE'), +(1900700004, 'material_tag', '住宿', 'hotel', 4, 'ACTIVE'), +(1900700005, 'material_tag', '交通', 'transport', 5, 'ACTIVE'), +(1900700006, 'material_tag', '活动', 'activity', 6, 'ACTIVE'), +(1900700007, 'material_tag', '冬季', 'winter', 7, 'ACTIVE'), +(1900700008, 'material_tag', '夏季', 'summer', 8, 'ACTIVE'), +(1900700009, 'material_tag', '草原', 'grassland', 9, 'ACTIVE'), +(1900700010, 'material_tag', '森林', 'forest', 10, 'ACTIVE'); + +-- 8. product_category - 产品分类(产品基本信息编辑用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000008, '产品分类', 'product_category', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900800001, 'product_category', '亲子游', 'family', 1, 'ACTIVE'), +(1900800002, 'product_category', '蜜月旅行', 'honeymoon', 2, 'ACTIVE'), +(1900800003, 'product_category', '摄影之旅', 'photography', 3, 'ACTIVE'), +(1900800004, 'product_category', '深度体验', 'experience', 4, 'ACTIVE'), +(1900800005, 'product_category', '自驾越野', 'driving', 5, 'ACTIVE'); + +-- 9. settle_status - 结算状态(结算记录用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000009, '结算状态', 'settle_status', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1900900001, 'settle_status', '待结算', 'pending', 1, 'ACTIVE'), +(1900900002, 'settle_status', '已结算', 'settled', 2, 'ACTIVE'), +(1900900003, 'settle_status', '结算中', 'processing', 3, 'ACTIVE'), +(1900900004, 'settle_status', '已取消', 'cancelled', 4, 'ACTIVE'); + +-- 10. trip_status - 行程状态(定制行程列表用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000010, '行程状态', 'trip_status', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1901000001, 'trip_status', '草稿', 'draft', 1, 'ACTIVE'), +(1901000002, 'trip_status', '已上线', 'online', 2, 'ACTIVE'), +(1901000003, 'trip_status', '已下线', 'offline', 3, 'ACTIVE'); + +-- 11. trip_type - 行程类型(定制行程表单用) +INSERT IGNORE INTO sys_dict_type (dict_type_id, dict_name, dict_type, category, status) +VALUES (1900000011, '行程类型', 'trip_type', 'BUSINESS', 'ACTIVE'); + +INSERT IGNORE INTO sys_dict_data (dict_data_id, dict_type, dict_label, dict_value, sort_order, status) +VALUES +(1901100001, 'trip_type', '跟团游', 'group', 1, 'ACTIVE'), +(1901100002, 'trip_type', '自由行', 'free', 2, 'ACTIVE'), +(1901100003, 'trip_type', '定制游', 'custom', 3, 'ACTIVE'), +(1901100004, 'trip_type', '半自由行', 'semi_free', 4, 'ACTIVE'); +``` + +## 配置变更 + +### `hl-callback-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-callback-service/src/main/resources/bootstrap.yml b/hl-callback-service/src/main/resources/bootstrap.yml +index 7b5d1dc..5d1c2d6 100644 +--- a/hl-callback-service/src/main/resources/bootstrap.yml ++++ b/hl-callback-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -13,6 +13,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u4F01\u5FAE\u56DE\u8C03\u670D\u52A1" +``` + +### `hl-contract-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-contract-service/src/main/resources/bootstrap.yml b/hl-contract-service/src/main/resources/bootstrap.yml +index 2ad048d..9a8fadc 100644 +--- a/hl-contract-service/src/main/resources/bootstrap.yml ++++ b/hl-contract-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u5408\u540C\u670D\u52A1" +``` + +### `hl-file-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-file-service/src/main/resources/bootstrap.yml b/hl-file-service/src/main/resources/bootstrap.yml +index 80be6f4..f060b2f 100644 +--- a/hl-file-service/src/main/resources/bootstrap.yml ++++ b/hl-file-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -13,6 +13,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u6587\u4EF6\u670D\u52A1" +``` + +### `hl-gateway/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-gateway/src/main/resources/bootstrap.yml b/hl-gateway/src/main/resources/bootstrap.yml +index b081310..e4431ac 100644 +--- a/hl-gateway/src/main/resources/bootstrap.yml ++++ b/hl-gateway/src/main/resources/bootstrap.yml +@@ -5,10 +5,10 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u7F51\u5173\u670D\u52A1" +``` + +### `hl-guide-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-guide-service/src/main/resources/bootstrap.yml b/hl-guide-service/src/main/resources/bootstrap.yml +index fe9e45a..e9e3e60 100644 +--- a/hl-guide-service/src/main/resources/bootstrap.yml ++++ b/hl-guide-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u653B\u7565\u670D\u52A1" +``` + +### `hl-insurance-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-insurance-service/src/main/resources/bootstrap.yml b/hl-insurance-service/src/main/resources/bootstrap.yml +index 3fa8071..6a668aa 100644 +--- a/hl-insurance-service/src/main/resources/bootstrap.yml ++++ b/hl-insurance-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u4FDD\u9669\u670D\u52A1" +``` + +### `hl-material-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-material-service/src/main/resources/bootstrap.yml b/hl-material-service/src/main/resources/bootstrap.yml +index a2129ab..affb9da 100644 +--- a/hl-material-service/src/main/resources/bootstrap.yml ++++ b/hl-material-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -13,6 +13,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u7D20\u6750\u5E93\u670D\u52A1" +``` + +### `hl-monitor-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-monitor-service/src/main/resources/bootstrap.yml b/hl-monitor-service/src/main/resources/bootstrap.yml +index d578a0b..32ebbb5 100644 +--- a/hl-monitor-service/src/main/resources/bootstrap.yml ++++ b/hl-monitor-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u76D1\u63A7\u670D\u52A1" +``` + +### `hl-mp-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-mp-service/src/main/resources/bootstrap.yml b/hl-mp-service/src/main/resources/bootstrap.yml +index 826eadd..d3103ee 100644 +--- a/hl-mp-service/src/main/resources/bootstrap.yml ++++ b/hl-mp-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u5C0F\u7A0B\u5E8FBFF\u670D\u52A1" +``` + +### `hl-order-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-order-service/src/main/resources/bootstrap.yml b/hl-order-service/src/main/resources/bootstrap.yml +index 7a5aac5..a5f007a 100644 +--- a/hl-order-service/src/main/resources/bootstrap.yml ++++ b/hl-order-service/src/main/resources/bootstrap.yml +@@ -7,7 +7,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -19,6 +19,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u8BA2\u5355\u670D\u52A1" +``` + +### `hl-payment-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-payment-service/src/main/resources/bootstrap.yml b/hl-payment-service/src/main/resources/bootstrap.yml +index a70de62..00e9efd 100644 +--- a/hl-payment-service/src/main/resources/bootstrap.yml ++++ b/hl-payment-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + discovery: + metadata: + description: "\u652F\u4ED8\u670D\u52A1" +``` + +### `hl-product-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-product-service/src/main/resources/bootstrap.yml b/hl-product-service/src/main/resources/bootstrap.yml +index a9fab53..7f26008 100644 +--- a/hl-product-service/src/main/resources/bootstrap.yml ++++ b/hl-product-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u4EA7\u54C1\u670D\u52A1" +``` + +### `hl-resource-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-resource-service/src/main/resources/bootstrap.yml b/hl-resource-service/src/main/resources/bootstrap.yml +index 2f8d63d..05aece0 100644 +--- a/hl-resource-service/src/main/resources/bootstrap.yml ++++ b/hl-resource-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -17,6 +17,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u8D44\u6E90\u670D\u52A1" +``` + +### `hl-review-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-review-service/src/main/resources/bootstrap.yml b/hl-review-service/src/main/resources/bootstrap.yml +index 5a0bc48..4c5260b 100644 +--- a/hl-review-service/src/main/resources/bootstrap.yml ++++ b/hl-review-service/src/main/resources/bootstrap.yml +@@ -10,7 +10,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -22,6 +22,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u8BC4\u4EF7\u670D\u52A1" +``` + +### `hl-task-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-task-service/src/main/resources/bootstrap.yml b/hl-task-service/src/main/resources/bootstrap.yml +index 810de1f..7bc1d67 100644 +--- a/hl-task-service/src/main/resources/bootstrap.yml ++++ b/hl-task-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -13,6 +13,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u4EFB\u52A1\u670D\u52A1" +``` + +### `hl-user-service/src/main/resources/bootstrap.yml` (M) + +```diff +diff --git a/hl-user-service/src/main/resources/bootstrap.yml b/hl-user-service/src/main/resources/bootstrap.yml +index 520eb90..caedb1f 100644 +--- a/hl-user-service/src/main/resources/bootstrap.yml ++++ b/hl-user-service/src/main/resources/bootstrap.yml +@@ -5,7 +5,7 @@ spring: + active: dev + cloud: + nacos: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + config: + file-extension: yml + shared-configs: +@@ -13,6 +13,6 @@ spring: + group: DEFAULT_GROUP + refresh: true + discovery: +- server-addr: ${NACOS_SERVER_ADDR:192.168.100.236:8848} ++ server-addr: ${NACOS_SERVER_ADDR:127.0.0.1:8848} + metadata: + description: "\u7528\u6237\u670D\u52A1" +``` + +## Service 业务逻辑变更 + +### `hl-callback-service/src/main/java/com/hulalv/callback/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/config/Knife4jConfig.java b/hl-callback-service/src/main/java/com/hulalv/callback/config/Knife4jConfig.java +index c64ad00..3fd0b5e 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/config/Knife4jConfig.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.callback.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.service.ApiInfo; + import springfox.documentation.spi.DocumentationType; +@@ -12,6 +12,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket callbackApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -19,7 +24,7 @@ public class Knife4jConfig { + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.callback.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java b/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java +index a9d6ea9..adf49be 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/controller/MsgAuditCallbackController.java +@@ -21,7 +21,7 @@ import java.util.concurrent.Executors; + * 路径: /callback/msg-audit + */ + @Slf4j +-@Api(tags = "【回调接口】会话内容存档") ++@Api(tags = "【回调接口】会话内容存档", hidden = true) + @RestController + @RequestMapping("/callback") + public class MsgAuditCallbackController { +@@ -59,7 +59,8 @@ public class MsgAuditCallbackController { + * URL 验证端点。 + * 企业微信配置回调 URL 时发送 GET 请求验证,需解密 echostr 并返回明文。 + */ +- @ApiOperation("会话内容存档回调URL验证") ++ @ApiOperation(value = "会话内容存档回调URL验证", ++ notes = "企业微信会话内容存档的回调URL验证端点。使用独立的Token/AESKey,在企微后台配置会话存档回调URL时进行验证。") + @GetMapping(value = "/msg-audit", produces = MediaType.TEXT_PLAIN_VALUE) + public String verifyUrl( + @RequestParam("msg_signature") String msgSignature, +@@ -89,7 +90,8 @@ public class MsgAuditCallbackController { + * 企业微信在有新的存档消息时 POST 加密 XML 事件通知。 + * 通知仅表示"有新消息可拉取",具体消息内容需通过 API 主动拉取。 + */ +- @ApiOperation("接收会话内容存档事件通知") ++ @ApiOperation(value = "接收会话内容存档事件通知", ++ notes = "企业微信在有新的存档消息时推送事件通知到此端点。通知仅表示'有新消息可拉取',收到后异步触发消息拉取任务(通过Finance SDK API主动拉取具体内容并存储)。必须5秒内返回'success'。") + @PostMapping(value = "/msg-audit", + consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE}, + produces = MediaType.TEXT_PLAIN_VALUE) +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java b/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java +index cad043a..0b1d68b 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/controller/WxCallbackController.java +@@ -27,7 +27,7 @@ import java.io.StringReader; + * No JWT auth required - uses WeChat's own signature verification. + */ + @Slf4j +-@Api(tags = "【回调接口】企业微信回调") ++@Api(tags = "【回调接口】企业微信回调", hidden = true) + @RestController + @RequestMapping("/wx/callback") + public class WxCallbackController { +@@ -88,7 +88,8 @@ public class WxCallbackController { + * WeChat sends GET request to verify the callback URL. + * Must decrypt echostr and return it as plain text. + */ +- @ApiOperation("Callback URL verification") ++ @ApiOperation(value = "回调URL验证", ++ notes = "企业微信自建应用的回调URL验证端点。企微在配置回调URL时发送GET请求,需解密echostr并返回明文以完成验证。无需JWT认证,使用企微自有的签名校验机制。") + @GetMapping(value = "/app", produces = MediaType.TEXT_PLAIN_VALUE) + public String verifyUrl( + @RequestParam("msg_signature") String msgSignature, +@@ -118,7 +119,8 @@ public class WxCallbackController { + * WeChat POSTs encrypted XML for all event types. + * We decrypt, parse, dispatch to handler, and return "success". + */ +- @ApiOperation("Receive callback events") ++ @ApiOperation(value = "接收回调事件", ++ notes = "企业微信自建应用的事件接收端点。接收加密XML格式的事件通知(审批变更、消息等),解密后按事件类型分发:change_contact→通讯录变更,change_external_contact→外部联系人变更,open_approval_change→审批状态变更。必须5秒内返回'success'。") + @PostMapping(value = "/app", + consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE}, + produces = MediaType.TEXT_PLAIN_VALUE) +@@ -162,7 +164,8 @@ public class WxCallbackController { + // Contact Sync Callback Endpoints + // ========================================== + +- @ApiOperation("Contact sync URL verification") ++ @ApiOperation(value = "联系人同步URL验证", ++ notes = "企业微信通讯录同步的回调URL验证端点。使用独立的Token/AESKey(与应用回调不同),用于接收通讯录变更事件的回调URL配置验证。") + @GetMapping(value = "/contacts", produces = MediaType.TEXT_PLAIN_VALUE) + public String verifyContactsUrl( + @RequestParam("msg_signature") String msgSignature, +@@ -187,7 +190,8 @@ public class WxCallbackController { + return result; + } + +- @ApiOperation("Receive contact sync events") ++ @ApiOperation(value = "接收联系人同步事件", ++ notes = "企业微信通讯录变更事件接收端点。接收员工创建/更新/删除、部门变更等事件,解密后转发给ContactChangeHandler处理,同步更新本地管理员数据。必须5秒内返回'success'。") + @PostMapping(value = "/contacts", + consumes = {MediaType.TEXT_XML_VALUE, MediaType.APPLICATION_XML_VALUE}, + produces = MediaType.TEXT_PLAIN_VALUE) +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClient.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClient.java b/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClient.java +index 127e6f5..e8b0be4 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClient.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClient.java +@@ -11,17 +11,17 @@ import org.springframework.web.bind.annotation.*; + public interface UserServiceClient { + + @PostMapping("/internal/wechat/user/sync") +- Result syncUser(@RequestBody WechatUserSyncDTO dto); ++ Result syncUser(@RequestBody WechatUserSyncDTO dto); + + @DeleteMapping("/internal/wechat/user/{userid}") +- Result deleteUser(@PathVariable("userid") String userid); ++ Result deleteUser(@PathVariable("userid") String userid); + + @PostMapping("/internal/wechat/department/sync") +- Result syncDepartment(@RequestBody WechatDeptSyncDTO dto); ++ Result syncDepartment(@RequestBody WechatDeptSyncDTO dto); + + @DeleteMapping("/internal/wechat/department/{deptId}") +- Result deleteDepartment(@PathVariable("deptId") Long deptId); ++ Result deleteDepartment(@PathVariable("deptId") Long deptId); + + @PostMapping("/internal/wechat/external-contact/event") +- Result notifyExternalContactEvent(@RequestBody ExternalContactEventDTO dto); ++ Result notifyExternalContactEvent(@RequestBody ExternalContactEventDTO dto); + } +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClientFallback.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClientFallback.java b/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClientFallback.java +index fe9a971..9a8d5e2 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClientFallback.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/feign/UserServiceClientFallback.java +@@ -17,31 +17,31 @@ public class UserServiceClientFallback implements FallbackFactory syncUser(WechatUserSyncDTO dto) { ++ public Result syncUser(WechatUserSyncDTO dto) { + log.error("Failed to sync user: {}", dto.getUserid()); + return Result.error(500, "user-service unavailable"); + } + + @Override +- public Result deleteUser(String userid) { ++ public Result deleteUser(String userid) { + log.error("Failed to delete user: {}", userid); + return Result.error(500, "user-service unavailable"); + } + + @Override +- public Result syncDepartment(WechatDeptSyncDTO dto) { ++ public Result syncDepartment(WechatDeptSyncDTO dto) { + log.error("Failed to sync department: {}", dto.getId()); + return Result.error(500, "user-service unavailable"); + } + + @Override +- public Result deleteDepartment(Long deptId) { ++ public Result deleteDepartment(Long deptId) { + log.error("Failed to delete department: {}", deptId); + return Result.error(500, "user-service unavailable"); + } + + @Override +- public Result notifyExternalContactEvent(ExternalContactEventDTO dto) { ++ public Result notifyExternalContactEvent(ExternalContactEventDTO dto) { + log.error("Failed to notify external contact event: userId={}, changeType={}", + dto.getUserId(), dto.getChangeType()); + return Result.error(500, "user-service unavailable"); +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/handler/ApprovalEventHandler.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/handler/ApprovalEventHandler.java b/hl-callback-service/src/main/java/com/hulalv/callback/handler/ApprovalEventHandler.java +index 2f75d43..cd97724 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/handler/ApprovalEventHandler.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/handler/ApprovalEventHandler.java +@@ -117,7 +117,7 @@ public class ApprovalEventHandler { + // MQ-first for approval log, Feign fallback + if (!mqLogProducer.sendApprovalLog(dto)) { + try { +- Result result = monitorFeignClient.pushApprovalLog(dto); ++ Result result = monitorFeignClient.pushApprovalLog(dto); + if (result.getCode() != 200) { + log.error("Feign pushApprovalLog failed: code={}, msg={}", + result.getCode(), result.getMessage()); +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/handler/ContactChangeHandler.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/handler/ContactChangeHandler.java b/hl-callback-service/src/main/java/com/hulalv/callback/handler/ContactChangeHandler.java +index a288d73..85f2ff0 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/handler/ContactChangeHandler.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/handler/ContactChangeHandler.java +@@ -70,7 +70,7 @@ public class ContactChangeHandler { + } + + log.info("Syncing user via Feign: changeType={}, userid={}", changeType, userid); +- Result result = userServiceClient.syncUser(dto); ++ Result result = userServiceClient.syncUser(dto); + if (result.getCode() != 200) { + log.error("Feign syncUser failed: code={}, msg={}", result.getCode(), result.getMessage()); + } +@@ -84,7 +84,7 @@ public class ContactChangeHandler { + } + + log.info("Deleting user via Feign: userid={}", userid); +- Result result = userServiceClient.deleteUser(userid); ++ Result result = userServiceClient.deleteUser(userid); + if (result.getCode() != 200) { + log.error("Feign deleteUser failed: code={}, msg={}", result.getCode(), result.getMessage()); + } +@@ -119,7 +119,7 @@ public class ContactChangeHandler { + } + + log.info("Syncing department via Feign: changeType={}, deptId={}", changeType, dto.getId()); +- Result result = userServiceClient.syncDepartment(dto); ++ Result result = userServiceClient.syncDepartment(dto); + if (result.getCode() != 200) { + log.error("Feign syncDepartment failed: code={}, msg={}", result.getCode(), result.getMessage()); + } +@@ -140,7 +140,7 @@ public class ContactChangeHandler { + return; + } + log.info("Deleting department via Feign: deptId={}", deptId); +- Result result = userServiceClient.deleteDepartment(deptId); ++ Result result = userServiceClient.deleteDepartment(deptId); + if (result.getCode() != 200) { + log.error("Feign deleteDepartment failed: code={}, msg={}", result.getCode(), result.getMessage()); + } +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/handler/ExternalContactHandler.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/handler/ExternalContactHandler.java b/hl-callback-service/src/main/java/com/hulalv/callback/handler/ExternalContactHandler.java +index 9715b66..87f6e0b 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/handler/ExternalContactHandler.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/handler/ExternalContactHandler.java +@@ -55,7 +55,7 @@ public class ExternalContactHandler { + dto.setExternalUserId(externalUserId); + + try { +- Result result = userServiceClient.notifyExternalContactEvent(dto); ++ Result result = userServiceClient.notifyExternalContactEvent(dto); + if (result.getCode() != 200) { + log.error("Feign notifyExternalContactEvent failed: code={}, msg={}", + result.getCode(), result.getMessage()); +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/InternalChatMessageController.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/InternalChatMessageController.java b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/InternalChatMessageController.java +index 36b5a17..88ee4df 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/InternalChatMessageController.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/InternalChatMessageController.java +@@ -27,7 +27,8 @@ public class InternalChatMessageController { + * @param roomId 群聊ID + * @param limit 最大条数(默认20,最大50) + */ +- @ApiOperation("查询指定群的最近消息") ++ @ApiOperation(value = "查询指定群的最近消息", ++ notes = "内部服务间调用。供其他服务通过Feign查询指定群聊的最近消息记录。返回消息基本信息(发送人、时间、类型、内容),不含发送人姓名/头像解析。limit默认20,最大50。") + @GetMapping("/messages") + public Result> getRecentMessages( + @RequestParam String roomId, +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/MsgAuditController.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/MsgAuditController.java b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/MsgAuditController.java +index 57b84e3..9689460 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/MsgAuditController.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/MsgAuditController.java +@@ -29,7 +29,8 @@ public class MsgAuditController { + private final WechatGroupService wechatGroupService; + private final ChatMessageService chatMessageService; + +- @ApiOperation("获取开启存档的成员列表") ++ @ApiOperation(value = "获取开启存档的成员列表", ++ notes = "调用企微API获取已开启会话内容存档的企业成员列表,返回原始JSON。用于管理员查看哪些成员的聊天记录正在被存档。") + @GetMapping("/permit-users") + public Result getPermitUsers() { + try { +@@ -41,7 +42,8 @@ public class MsgAuditController { + } + } + +- @ApiOperation("获取群聊信息") ++ @ApiOperation(value = "获取群聊信息", ++ notes = "通过roomId调用企微API获取企业内部群的群聊信息(群名、群主、成员等),返回原始JSON。外部群无法通过此接口查询。") + @GetMapping("/group-chat") + public Result getGroupChatInfo( + @ApiParam("群聊ID (roomid)") @RequestParam String roomId) { +@@ -54,7 +56,8 @@ public class MsgAuditController { + } + } + +- @ApiOperation("检查群聊同意情况") ++ @ApiOperation(value = "检查群聊同意情况", ++ notes = "调用企微API检查指定群聊中各成员是否已同意会话内容存档。未同意的成员其聊天记录不会被存档。返回原始JSON。") + @GetMapping("/group-chat/agree") + public Result checkRoomAgree( + @ApiParam("群聊ID (roomid)") @RequestParam String roomId) { +@@ -67,7 +70,8 @@ public class MsgAuditController { + } + } + +- @ApiOperation("拉取聊天记录(需要 Finance SDK)") ++ @ApiOperation(value = "拉取聊天记录(需要 Finance SDK)", ++ notes = "通过Finance SDK拉取会话存档的聊天记录原始数据。需要本地部署Finance SDK动态库。seq为起始序号(0表示从头开始),limit为最大返回条数(上限1000)。返回原始JSON。") + @GetMapping("/chat-data") + public Result getChatData( + @ApiParam("起始序号(0=从头开始)") @RequestParam(defaultValue = "0") long seq, +@@ -81,7 +85,8 @@ public class MsgAuditController { + } + } + +- @ApiOperation("获取 SDK 状态") ++ @ApiOperation(value = "获取 SDK 状态", ++ notes = "检查Finance SDK动态库是否可用。可用时支持拉取聊天记录和下载媒体文件;不可用时仅支持HTTP管理API(成员列表、群聊信息等)。") + @GetMapping("/status") + public Result getStatus() { + boolean sdkAvailable = msgAuditService.isSdkAvailable(); +@@ -91,14 +96,16 @@ public class MsgAuditController { + return Result.success(status); + } + +- @ApiOperation("手动触发拉取消息") ++ @ApiOperation(value = "手动触发拉取消息", ++ notes = "手动触发一次消息拉取任务,从上次拉取位置开始拉取新消息并存入数据库。正常情况下由回调事件自动触发,此接口用于手动补拉或调试。返回本次新增的消息数量。") + @PostMapping("/pull") + public Result pullMessages() { + int count = chatMessageService.pullAndStoreMessages(); + return Result.success("拉取完成,新增 " + count + " 条消息"); + } + +- @ApiOperation("下载媒体文件(图片、视频等)") ++ @ApiOperation(value = "下载媒体文件(图片、视频等)", ++ notes = "通过Finance SDK下载会话存档中的媒体文件(图片、视频、语音、文件等)。需提供sdkfileid(从聊天记录中获取),可选md5sum用于校验。返回二进制文件流(默认Content-Type为image/jpeg)。需要Finance SDK可用。") + @GetMapping("/media") + public ResponseEntity downloadMedia( + @ApiParam("SDK文件ID") @RequestParam String sdkfileid, +@@ -119,19 +126,22 @@ public class MsgAuditController { + // 群组管理 + // ========================================== + +- @ApiOperation("群组列表") ++ @ApiOperation(value = "群组列表", ++ notes = "获取已添加的企微群组列表。返回所有已录入的群组信息(群名、roomId、群主、成员数、备注等)。群组需先通过'添加群组'接口录入。") + @GetMapping("/groups") + public Result> listGroups() { + return Result.success(wechatGroupService.listGroups()); + } + +- @ApiOperation("发现群组(从消息记录中自动发现未添加的群)") ++ @ApiOperation(value = "发现群组(从消息记录中自动发现未添加的群)", ++ notes = "扫描已拉取的聊天消息记录,自动发现尚未录入群组管理的群聊roomId。返回未添加的群列表及基本信息,管理员可据此选择性添加需要监控的群组。") + @GetMapping("/groups/discover") + public Result>> discoverGroups() { + return Result.success(wechatGroupService.discoverGroups()); + } + +- @ApiOperation("查看群最近消息") ++ @ApiOperation(value = "查看群最近消息", ++ notes = "查询指定群聊的最近消息记录。返回消息列表(含发送人姓名、头像、消息类型、内容、时间等)。limit最大50条。发送人信息通过批量解析userId获取(企微成员显示姓名+头像,外部人员显示userId)。") + @GetMapping("/groups/messages") + public Result> getGroupMessages( + @ApiParam("群聊ID") @RequestParam String roomId, +@@ -162,7 +172,8 @@ public class MsgAuditController { + return Result.success(voList); + } + +- @ApiOperation("添加群组(输入roomId,自动尝试同步群信息)") ++ @ApiOperation(value = "添加群组(输入roomId,自动尝试同步群信息)", ++ notes = "将指定群聊添加到群组管理列表。自动尝试通过企微API同步群信息(群名、群主、成员等)。内部群可自动获取群信息,外部群需手动填写groupName。可选填写remark备注。") + @PostMapping("/groups") + public Result addGroup( + @ApiParam("群聊ID") @RequestParam String roomId, +@@ -175,7 +186,8 @@ public class MsgAuditController { + } + } + +- @ApiOperation("同步群组信息(从企微API刷新)") ++ @ApiOperation(value = "同步群组信息(从企微API刷新)", ++ notes = "从企微API重新拉取指定群组的最新信息(群名、群主、成员列表等)并更新本地记录。仅对内部群有效,外部群无法通过API同步。") + @PostMapping("/groups/{id}/sync") + public Result syncGroup(@PathVariable Long id) { + try { +@@ -185,7 +197,8 @@ public class MsgAuditController { + } + } + +- @ApiOperation("更新群组信息(群名、备注)") ++ @ApiOperation(value = "更新群组信息(群名、备注)", ++ notes = "手动修改群组的显示名称和备注信息。适用于外部群(无法自动同步群名)或需要自定义备注的场景。groupName和remark均为可选,传入哪个更新哪个。") + @PutMapping("/groups/{id}") + public Result updateGroup( + @PathVariable Long id, +@@ -195,7 +208,8 @@ public class MsgAuditController { + return Result.success(null); + } + +- @ApiOperation("删除群组") ++ @ApiOperation(value = "删除群组", ++ notes = "从群组管理列表中删除指定群组。仅删除本地管理记录,不影响企微实际群聊和已拉取的历史消息数据。") + @DeleteMapping("/groups/{id}") + public Result deleteGroup(@PathVariable Long id) { + wechatGroupService.deleteGroup(id); +``` + +### `hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java` (M) + +```diff +diff --git a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java +index cc334e0..001c095 100644 +--- a/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java ++++ b/hl-callback-service/src/main/java/com/hulalv/callback/msgaudit/vo/ChatMessageVO.java +@@ -1,15 +1,33 @@ + package com.hulalv.callback.msgaudit.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("聊天消息VO") + public class ChatMessageVO { ++ @ApiModelProperty("消息ID") + private String msgId; ++ ++ @ApiModelProperty("发送人ID") + private String fromUser; ++ ++ @ApiModelProperty("发送人姓名") + private String fromUserName; ++ ++ @ApiModelProperty("发送人头像") + private String fromUserAvatar; ++ ++ @ApiModelProperty("群聊ID") + private String roomId; ++ ++ @ApiModelProperty("消息时间戳") + private Long msgTime; ++ ++ @ApiModelProperty("消息类型") + private String msgType; ++ ++ @ApiModelProperty("消息内容") + private String content; + } +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/config/Knife4jConfig.java b/hl-contract-service/src/main/java/com/hulalv/contract/config/Knife4jConfig.java +index 9813464..ca855b5 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/config/Knife4jConfig.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.contract.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.spi.DocumentationType; + import springfox.documentation.spring.web.plugins.Docket; +@@ -11,6 +11,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket contractApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -22,7 +27,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.contract.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java` (M) + +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java +index f955c57..91ac6ed 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminClauseTemplateController.java +@@ -21,31 +21,33 @@ public class AdminClauseTemplateController { + + private final ClauseTemplateService clauseTemplateService; + +- @ApiOperation("获取启用的补充约定模板列表(创建合同用)") ++ @ApiOperation(value = "获取启用的补充约定模板列表(创建合同用)", ++ notes = "返回所有启用状态的补充约定模板,创建合同时选择需要附加的补充约定条款。\n\n**权限**:需管理员登录。") + @GetMapping("/list") + public Result> listActive() { + return Result.success(clauseTemplateService.listActive()); + } + +- @ApiOperation("获取全部补充约定模板(管理页用)") ++ @ApiOperation(value = "获取全部补充约定模板(管理页用)", notes = "**关联字典**:\n- common_status:通用状态(列表显示,ACTIVE=启用/INACTIVE=停用)") + @GetMapping("/list-all") + public Result> listAll() { + return Result.success(clauseTemplateService.listAll()); + } + +- @ApiOperation("切换模板启用/停用状态") ++ @ApiOperation(value = "切换模板启用/停用状态", notes = "**关联字典**:\n- common_status:通用状态(状态切换,ACTIVE=启用/INACTIVE=停用)") + @PutMapping("/{id}/toggle-status") + public Result toggleStatus(@ApiParam("模板ID") @PathVariable("id") Long templateId) { + return Result.success(clauseTemplateService.toggleStatus(templateId)); + } + +- @ApiOperation("创建补充约定模板") ++ @ApiOperation(value = "创建补充约定模板", notes = "创建合同补充约定的模板,支持变量占位符。创建后默认启用") + @PostMapping + public Result create(@Valid @RequestBody ClauseTemplateRequest request) { + return Result.success(clauseTemplateService.create(request)); + } + +- @ApiOperation("更新补充约定模板") ++ @ApiOperation(value = "更新补充约定模板", ++ notes = "更新模板的标题和内容。已被合同引用的模板更新不影响已创建的合同(合同记录的是快照内容)。\n\n**权限**:需管理员登录。") + @PutMapping("/{id}") + public Result update( + @ApiParam("模板ID") @PathVariable("id") Long templateId, +@@ -53,7 +55,7 @@ public class AdminClauseTemplateController { + return Result.success(clauseTemplateService.update(templateId, request)); + } + +- @ApiOperation("删除补充约定模板") ++ @ApiOperation(value = "删除补充约定模板", notes = "软删除模板。已被合同引用的模板仍可删除,不影响已创建的合同") + @DeleteMapping("/{id}") + public Result delete(@ApiParam("模板ID") @PathVariable("id") Long templateId) { + clauseTemplateService.delete(templateId); +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java` (M) + +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java +index a6a6dbe..437717e 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/AdminContractController.java +@@ -30,19 +30,20 @@ public class AdminContractController { + + private final ContractService contractService; + +- @ApiOperation("可用旅行社列表") ++ @ApiOperation(value = "可用旅行社列表", notes = "返回系统配置的旅行社列表,创建合同时选择签约旅行社") + @GetMapping("/agencies") + public Result> listAgencies() { + return Result.success(contractService.listAgencies()); + } + +- @ApiOperation("合同模板列表") ++ @ApiOperation(value = "合同模板列表", notes = "返回合同平台可用的合同模板列表,创建合同时选择模板") + @GetMapping("/templates") + public Result> listTemplates() { + return Result.success(contractService.listTemplates()); + } + +- @ApiOperation("创建合同(标准模式)") ++ @ApiOperation(value = "创建合同(标准模式)", notes = "标准电子签约流程:创建合同 → 平台生成合同PDF → 发送签署短信给出行人 → 出行人在线签署 → 回调更新状态。" ++ + "状态流转:CREATED → SIGNING → SIGNED") + @PostMapping("/create") + public Result createContract( + @ApiParam("创建合同请求") @Valid @RequestBody CreateContractRequest request, +@@ -51,7 +52,8 @@ public class AdminContractController { + return Result.success(contractService.createContract(request, adminId)); + } + +- @ApiOperation("报备合同(同步模式)") ++ @ApiOperation(value = "报备合同(同步模式)", notes = "线下签约模式:创建合同记录 → 管理员上传已签署的PDF → 同步到12301报备平台。" ++ + "状态流转:CREATED → UPLOADED → REPORTED") + @PostMapping("/report") + public Result reportContract( + @ApiParam("报备合同请求") @Valid @RequestBody ReportContractRequest request, +@@ -60,49 +62,51 @@ public class AdminContractController { + return Result.success(contractService.reportContract(request, adminId)); + } + +- @ApiOperation("合同列表") ++ @ApiOperation(value = "合同列表", notes = "分页查询合同记录,支持按订单号、合同状态、旅行社筛选\n\n**关联字典**:\n- contract_status:合同状态(列表筛选+显示)") + @GetMapping("/list") + public Result> listContracts(@ApiParam("合同查询条件") ContractQueryRequest request) { + return Result.success(contractService.listContracts(request)); + } + +- @ApiOperation("合同详情") ++ @ApiOperation(value = "合同详情", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/{id}") + public Result getContractDetail(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.getContractDetail(contractId)); + } + +- @ApiOperation("按订单查询合同") ++ @ApiOperation(value = "按订单查询合同", ++ notes = "查询指定订单下的所有合同记录(含已作废),按创建时间倒序排列。用于订单详情页展示合同历史。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- contract_status:合同状态(列表显示)") + @GetMapping("/by-order/{orderId}") + public Result> getByOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(contractService.getByOrderId(orderId)); + } + +- @ApiOperation("获取订单有效合同") ++ @ApiOperation(value = "获取订单有效合同", ++ notes = "返回订单当前有效的合同(非作废状态的最新合同),用于检查订单是否已有签署中或已签署的合同。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/active-by-order/{orderId}") + public Result getActiveByOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(contractService.getActiveContractByOrderId(orderId)); + } + +- @ApiOperation("刷新合同状态(从平台同步)") ++ @ApiOperation(value = "刷新合同状态(从平台同步)", notes = "主动查询合同平台的最新签署状态并同步到本地,适用于回调未到达的场景") + @GetMapping("/{id}/status") + public Result refreshStatus(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.refreshStatus(contractId)); + } + +- @ApiOperation("作废合同") ++ @ApiOperation(value = "作废合同", notes = "将合同标记为作废状态(不可恢复)。作废后该合同不再有效,可重新为订单创建新合同") + @PostMapping("/{id}/invalidate") + public Result invalidateContract(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.invalidateContract(contractId)); + } + +- @ApiOperation("重发签署短信") ++ @ApiOperation(value = "重发签署短信", notes = "重新发送签署短信给出行人,用于签署短信过期或未收到的场景。仅SIGNING状态的合同可操作") + @PostMapping("/{id}/resend-sms") + public Result resendSms(@ApiParam("合同ID") @PathVariable("id") Long contractId) { + return Result.success(contractService.resendSms(contractId)); + } + +- @ApiOperation("上传已签署PDF(同步模式)") ++ @ApiOperation(value = "上传已签署PDF(同步模式)", notes = "同步模式专用:上传线下签署完成的合同PDF文件,上传后合同状态变为UPLOADED,可进一步报备") + @PostMapping("/{id}/upload-pdf") + public Result uploadPdf( + @ApiParam("合同ID") @PathVariable("id") Long contractId, +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java` (M) + +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java +index 8415d27..bad13a5 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/ContractCallbackController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + + import javax.validation.Valid; + +-@Api(tags = "【回调接口】合同回调") ++@Api(tags = "【回调接口】合同回调", hidden = true) + @Slf4j + @RestController + @RequestMapping("/contract/callback") +@@ -20,7 +20,7 @@ public class ContractCallbackController { + + private final ContractCallbackService callbackService; + +- @ApiOperation("12301合同状态回调") ++ @ApiOperation(value = "12301合同状态回调", notes = "接收12301全国旅游监管平台的合同签署状态回调。出行人签署完成后平台推送状态变更到此接口,自动更新本地合同状态") + @PostMapping("/12301") + public ResponseEntity handle12301Callback(@Valid @RequestBody ContractCallbackPayload payload) { + log.info("Received 12301 callback: contractNumber={}, state={}", +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java` (M) + +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java +index 8929f18..3c25a33 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalContractController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】合同(Feign调用)") ++@Api(tags = "【内部接口】合同(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/contract") + @RequiredArgsConstructor +@@ -19,19 +19,19 @@ public class InternalContractController { + + private final ContractService contractService; + +- @ApiOperation("按订单查询合同(内部调用)") ++ @ApiOperation(value = "按订单查询合同(内部调用)", notes = "**关联字典**:\n- contract_status:合同状态(返回字段)") + @GetMapping("/by-order/{orderId}") + public Result> getByOrder(@PathVariable Long orderId) { + return Result.success(contractService.getByOrderId(orderId)); + } + +- @ApiOperation("按订单批量查询合同(内部调用)") ++ @ApiOperation(value = "按订单批量查询合同(内部调用)", notes = "**关联字典**:\n- contract_status:合同状态(返回字段)") + @PostMapping("/by-orders") + public Result>> getByOrders(@RequestBody List orderIds) { + return Result.success(contractService.getByOrderIds(orderIds)); + } + +- @ApiOperation("检查订单是否有已签署合同(内部调用)") ++ @ApiOperation(value = "检查订单是否有已签署合同(内部调用)", notes = "检查订单是否存在有效签署的合同(SIGNED/REPORTED/UPLOADED状态),用于订单流程中的合同校验") + @GetMapping("/has-signed/{orderId}") + public Result hasSigned(@PathVariable Long orderId) { + List contracts = contractService.getByOrderId(orderId); +@@ -41,7 +41,7 @@ public class InternalContractController { + return Result.success(signed); + } + +- @ApiOperation("按订单作废所有有效合同(级联调用)") ++ @ApiOperation(value = "按订单作废所有有效合同(级联调用)", notes = "订单取消或退款时级联作废该订单下所有有效合同,reason参数记录作废原因") + @PostMapping("/invalidate/{orderId}") + public Result invalidateByOrder(@PathVariable Long orderId, + @RequestParam(value = "reason", required = false) String reason) { +``` + +### `hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java` (M) + +```diff +diff --git a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java +index 90d323c..bbb5883 100644 +--- a/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java ++++ b/hl-contract-service/src/main/java/com/hulalv/contract/controller/InternalMpContractController.java +@@ -16,7 +16,7 @@ import java.util.Map; + * C端合同内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序合同(Feign调用)") ++@Api(tags = "【内部接口】小程序合同(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/contract") + @RequiredArgsConstructor +@@ -24,7 +24,7 @@ public class InternalMpContractController { + + private final ContractService contractService; + +- @ApiOperation("用户合同列表") ++ @ApiOperation(value = "用户合同列表", notes = "**关联字典**:\n- contract_status:合同状态(列表筛选+显示)") + @GetMapping("/list") + public Result> listContracts( + @RequestParam Long userId, +@@ -34,7 +34,7 @@ public class InternalMpContractController { + return Result.success(contractService.listUserContracts(userId, status, page, pageSize)); + } + +- @ApiOperation("用户合同详情") ++ @ApiOperation(value = "用户合同详情", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/{id}") + public Result getContractDetail( + @PathVariable("id") Long contractId, +@@ -42,7 +42,7 @@ public class InternalMpContractController { + return Result.success(contractService.getUserContractDetail(contractId, userId)); + } + +- @ApiOperation("按订单查合同(返回最新有效合同)") ++ @ApiOperation(value = "按订单查合同(返回最新有效合同)", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}") + public Result getContractByOrder( + @PathVariable Long orderId, +@@ -50,7 +50,7 @@ public class InternalMpContractController { + return Result.success(contractService.getUserContractByOrderId(orderId, userId)); + } + +- @ApiOperation("按订单查所有有效合同(TOUR+INSURANCE各一条)") ++ @ApiOperation(value = "按订单查所有有效合同(TOUR+INSURANCE各一条)", notes = "**关联字典**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}/all") + public Result> getContractsByOrder( + @PathVariable Long orderId, +@@ -58,7 +58,8 @@ public class InternalMpContractController { + return Result.success(contractService.getUserContractsByOrderId(orderId, userId)); + } + +- @ApiOperation("重新发送合同签署短信") ++ @ApiOperation(value = "重新发送合同签署短信", ++ notes = "内部服务间调用。小程序端用户请求重发签署短信,用于签署链接过期或短信未收到的场景。仅SIGNING状态的合同可操作。\n\n**关联字典**:\n- contract_status:合同状态(仅SIGNING可操作)") + @PostMapping("/{contractId}/resend-sms") + public Result resendContractSms( + @PathVariable("contractId") Long contractId, +``` + +### `hl-file-service/src/main/java/com/hulalv/file/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/config/Knife4jConfig.java b/hl-file-service/src/main/java/com/hulalv/file/config/Knife4jConfig.java +index 59a5ded..39f6e7a 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/config/Knife4jConfig.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.file.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.spi.DocumentationType; + import springfox.documentation.spring.web.plugins.Docket; +@@ -11,6 +11,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket fileApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -22,7 +27,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.file.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java` (M) + +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java b/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java +index 5b04b02..c78b2d2 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/controller/FileController.java +@@ -33,7 +33,7 @@ public class FileController { + private final FileService fileService; + private final FileRefService fileRefService; + +- @ApiOperation("请求上传凭证") ++ @ApiOperation(value = "请求上传凭证", notes = "上传流程第一步:前端请求上传凭证 → 获取OSS预签名URL和临时凭证 → 前端直传OSS → 调用确认上传接口。凭证有效期有限,过期需重新请求") + @OperationLog(value = "请求上传凭证", module = "文件管理") + @PostMapping("/upload/token") + public Result requestUploadToken( +@@ -44,7 +44,7 @@ public class FileController { + return Result.success(vo); + } + +- @ApiOperation("确认上传完成") ++ @ApiOperation(value = "确认上传完成", notes = "上传流程第二步:前端直传OSS完成后调用此接口,系统验证文件存在性并创建文件记录。支持MD5去重,相同文件不会重复存储") + @OperationLog(value = "确认上传", module = "文件管理") + @PostMapping("/upload/confirm") + public Result confirmUpload( +@@ -55,21 +55,21 @@ public class FileController { + return Result.success(vo); + } + +- @ApiOperation("文件列表(分页)") ++ @ApiOperation(value = "文件列表(分页)", notes = "支持按文件类型、分组、上传者等条件筛选,按上传时间倒序分页返回\n\n**关联字典**:\n- file_type:文件类型(列表筛选+显示)\n- file_status:文件状态(显示)") + @GetMapping("/list") + public Result> listFiles(@ApiParam("文件查询条件") @Valid FileQueryRequest request) { + IPage page = fileService.listFiles(request); + return Result.success(page); + } + +- @ApiOperation("文件详情") ++ @ApiOperation(value = "文件详情", notes = "**关联字典**:\n- file_type:文件类型(显示)\n- file_status:文件状态(显示)") + @GetMapping("/{fileId}") + public Result getFileDetail(@ApiParam("文件ID") @PathVariable Long fileId) { + FileVO vo = fileService.getFileDetail(fileId); + return Result.success(vo); + } + +- @ApiOperation("删除文件") ++ @ApiOperation(value = "删除文件", notes = "软删除文件记录,如果文件存在引用关系则不允许删除。OSS上的物理文件由定时任务清理") + @OperationLog(value = "删除文件", module = "文件管理") + @DeleteMapping("/{fileId}") + public Result deleteFile(@ApiParam("文件ID") @PathVariable Long fileId) { +@@ -77,21 +77,21 @@ public class FileController { + return Result.success(null); + } + +- @ApiOperation("文件引用列表") ++ @ApiOperation(value = "文件引用列表", notes = "查看文件被哪些业务实体引用(如景区封面、酒店图片等),用于判断文件是否可安全删除") + @GetMapping("/{fileId}/refs") + public Result> getFileRefs(@ApiParam("文件ID") @PathVariable Long fileId) { + List refs = fileRefService.getRefsByFileId(fileId); + return Result.success(refs); + } + +- @ApiOperation("存储统计") ++ @ApiOperation(value = "存储统计", notes = "返回文件总数、总存储空间、各类型文件占比等统计信息") + @GetMapping("/stats") + public Result getStats() { + FileStatsVO stats = fileService.getStats(); + return Result.success(stats); + } + +- @ApiOperation("文件内容流式预览") ++ @ApiOperation(value = "文件内容流式预览", notes = "流式输出文件内容,设置正确的Content-Type头,支持浏览器直接预览图片和PDF等文件") + @GetMapping("/{fileId}/preview") + public void previewContent(@ApiParam("文件ID") @PathVariable Long fileId, HttpServletResponse response) throws IOException { + fileService.streamContent(fileId, response); +``` + +### `hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java` (M) + +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java b/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java +index cf46b6b..3690ff3 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/controller/InternalFileController.java +@@ -30,7 +30,7 @@ import org.springframework.web.multipart.MultipartFile; + import javax.validation.Valid; + import java.util.List; + +-@Api(tags = "【内部接口】文件(Feign调用)") ++@Api(tags = "【内部接口】文件(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/file") + @RequiredArgsConstructor +@@ -40,28 +40,30 @@ public class InternalFileController { + private final FileRefService fileRefService; + private final ChunkUploadService chunkUploadService; + +- @ApiOperation("绑定文件到业务实体") ++ @ApiOperation(value = "绑定文件到业务实体", notes = "将文件与业务实体建立引用关系(如景区ID+封面图),同一文件可被多个业务实体引用") + @PostMapping("/bindRefs") + public Result bindRefs(@Valid @RequestBody BindRefsRequest request) { + fileRefService.bindRefs(request.getBizType(), request.getBizId(), request.getFileIds()); + return Result.success(null); + } + +- @ApiOperation("解绑业务实体的所有文件") ++ @ApiOperation(value = "解绑业务实体的所有文件", notes = "删除指定业务类型+业务ID下的所有文件引用关系,常用于业务实体删除时的级联清理") + @PostMapping("/unbindRefs") + public Result unbindRefs(@Valid @RequestBody UnbindRefsRequest request) { + fileRefService.unbindRefs(request.getBizType(), request.getBizId()); + return Result.success(null); + } + +- @ApiOperation("批量获取文件信息") ++ @ApiOperation(value = "批量获取文件信息", ++ notes = "内部服务间调用。根据文件ID列表批量查询文件信息(含OSS URL、文件名、类型等),用于其他服务获取关联文件的详细数据。") + @PostMapping("/byIds") + public Result> getFilesByIds(@Valid @RequestBody BatchFileRequest request) { + List files = fileService.getFilesByIds(request.getFileIds()); + return Result.success(files); + } + +- @ApiOperation("内部上传凭证(素材服务调用)") ++ @ApiOperation(value = "内部上传凭证(素材服务调用)", ++ notes = "内部服务间调用。素材服务代理调用,为指定管理员生成OSS上传预签名URL和临时凭证,用于素材库的文件上传流程。") + @PostMapping("/upload/token") + public Result requestUploadTokenInternal( + @Valid @RequestBody UploadTokenRequest request, +@@ -69,7 +71,7 @@ public class InternalFileController { + return Result.success(fileService.requestUploadToken(request, adminId)); + } + +- @ApiOperation("内部直接上传文件(服务间调用)") ++ @ApiOperation(value = "内部直接上传文件(服务间调用)", notes = "服务间直接上传文件到OSS,跳过预签名流程。返回OSS公开访问URL,适用于后端生成的文件(如路线地图截图)") + @PostMapping("/upload/direct") + public Result uploadDirect( + @RequestParam("file") MultipartFile file, +@@ -78,7 +80,8 @@ public class InternalFileController { + return Result.success(vo.getOssUrl()); + } + +- @ApiOperation("内部确认上传(素材服务调用)") ++ @ApiOperation(value = "内部确认上传(素材服务调用)", ++ notes = "内部服务间调用。素材服务代理调用,确认文件已上传至OSS并创建文件记录。支持MD5去重。") + @PostMapping("/upload/confirm") + public Result confirmUploadInternal( + @Valid @RequestBody UploadConfirmRequest request, +@@ -88,7 +91,7 @@ public class InternalFileController { + + // ==================== 分片上传 ==================== + +- @ApiOperation("分片上传-初始化") ++ @ApiOperation(value = "分片上传-初始化", notes = "大文件上传第一步:初始化分片上传任务,返回uploadId和每个分片的预签名URL。前端按分片并发上传后调用complete接口合并") + @PostMapping("/upload/chunk/init") + public Result chunkUploadInit( + @Valid @RequestBody ChunkUploadInitRequest request, +@@ -96,7 +99,7 @@ public class InternalFileController { + return Result.success(chunkUploadService.initChunkUpload(request, adminId)); + } + +- @ApiOperation("分片上传-上传分片") ++ @ApiOperation(value = "分片上传-上传分片", notes = "大文件上传第二步:逐个上传分片,返回分片的ETag用于后续合并校验。支持断点续传,已上传的分片无需重传") + @PostMapping("/upload/chunk") + public Result chunkUploadPart( + @RequestParam("uploadId") String uploadId, +@@ -105,14 +108,14 @@ public class InternalFileController { + return Result.success(chunkUploadService.uploadChunk(uploadId, chunkIndex, chunk)); + } + +- @ApiOperation("分片上传-完成合并") ++ @ApiOperation(value = "分片上传-完成合并", notes = "大文件上传第三步:所有分片上传完成后调用,OSS端合并分片为完整文件并创建文件记录") + @PostMapping("/upload/chunk/complete") + public Result chunkUploadComplete( + @Valid @RequestBody ChunkUploadCompleteRequest request) { + return Result.success(chunkUploadService.completeChunkUpload(request.getUploadId())); + } + +- @ApiOperation("分片上传-取消") ++ @ApiOperation(value = "分片上传-取消", notes = "取消分片上传任务,清理已上传的分片数据和OSS临时文件") + @PostMapping("/upload/chunk/cancel") + public Result chunkUploadCancel( + @Valid @RequestBody ChunkUploadCancelRequest request) { +``` + +### `hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java` (M) + +```diff +diff --git a/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java b/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java +index b78e094..73b8a70 100644 +--- a/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java ++++ b/hl-file-service/src/main/java/com/hulalv/file/controller/MpFileController.java +@@ -23,7 +23,7 @@ public class MpFileController { + + private final FileService fileService; + +- @ApiOperation("上传文件(C端用户)") ++ @ApiOperation(value = "上传文件(C端用户)", notes = "小程序端直接上传文件,支持头像、评价图片等场景。groupKey决定存储路径和文件策略,默认为avatar") + @PostMapping("/upload") + public Result upload( + @ApiParam("上传文件") @RequestParam("file") MultipartFile file, +@@ -34,7 +34,8 @@ public class MpFileController { + return Result.success(vo); + } + +- @ApiOperation("文件内容流式预览") ++ @ApiOperation(value = "文件内容流式预览", ++ notes = "流式输出文件内容,设置正确的Content-Type头。用于小程序端通过web-view直接预览图片和PDF等文件。") + @GetMapping("/{fileId}/preview") + public void previewContent(@ApiParam("文件ID") @PathVariable Long fileId, HttpServletResponse response) throws IOException { + fileService.streamContent(fileId, response); +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java` (M) + +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java +index a96b208..10fe073 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideArticleController.java +@@ -22,19 +22,20 @@ public class AdminGuideArticleController { + + private final GuideArticleService articleService; + +- @ApiOperation("文章列表") ++ @ApiOperation(value = "文章列表", notes = "分页查询攻略文章,支持按分类、状态、关键词筛选\n\n**关联字典**:\n- wiki_status:文章状态(列表筛选+显示)") + @GetMapping("/list") + public Result> listArticles(@Valid ArticleQueryRequest query) { + return Result.success(articleService.listArticles(query)); + } + +- @ApiOperation("文章详情") ++ @ApiOperation(value = "文章详情", notes = "**关联字典**:\n- wiki_status:文章状态(显示)") + @GetMapping("/{articleId}") + public Result getArticle(@PathVariable Long articleId) { + return Result.success(articleService.getArticle(articleId)); + } + +- @ApiOperation("创建文章") ++ @ApiOperation(value = "创建文章", ++ notes = "创建攻略文章,需指定分类。创建后默认为草稿状态,需手动发布后小程序端才可见。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- wiki_status:文章状态(创建后默认DRAFT)") + @PostMapping + public Result createArticle( + @Valid @RequestBody ArticleCreateRequest request, +@@ -43,7 +44,8 @@ public class AdminGuideArticleController { + return Result.success(articleService.createArticle(request, adminId)); + } + +- @ApiOperation("更新文章") ++ @ApiOperation(value = "更新文章", ++ notes = "更新攻略文章的标题、内容、封面图、分类等信息。已发布的文章更新后立即生效。\n\n**权限**:需管理员登录。") + @PutMapping("/{articleId}") + public Result updateArticle( + @PathVariable Long articleId, +@@ -51,14 +53,15 @@ public class AdminGuideArticleController { + return Result.success(articleService.updateArticle(articleId, request)); + } + +- @ApiOperation("删除文章") ++ @ApiOperation(value = "删除文章", ++ notes = "软删除攻略文章,同时清除文章的标签关联。\n\n**权限**:需管理员登录。") + @DeleteMapping("/{articleId}") + public Result deleteArticle(@PathVariable Long articleId) { + articleService.deleteArticle(articleId); + return Result.success(); + } + +- @ApiOperation("发布/下架") ++ @ApiOperation(value = "发布/下架", notes = "切换文章发布状态。发布后小程序端可见,下架后小程序端不再展示但管理端仍可查看\n\n**关联字典**:\n- wiki_status:文章状态(状态切换)") + @PutMapping("/{articleId}/status") + public Result updateStatus( + @PathVariable Long articleId, +@@ -67,7 +70,7 @@ public class AdminGuideArticleController { + return Result.success(); + } + +- @ApiOperation("设置推荐") ++ @ApiOperation(value = "设置推荐", notes = "设置/取消文章推荐。推荐文章会在小程序首页和推荐列表中优先展示") + @PutMapping("/{articleId}/recommend") + public Result updateRecommend( + @PathVariable Long articleId, +@@ -76,7 +79,7 @@ public class AdminGuideArticleController { + return Result.success(); + } + +- @ApiOperation("设置置顶") ++ @ApiOperation(value = "设置置顶", notes = "设置/取消文章置顶。置顶文章在分类列表中始终排在最前面") + @PutMapping("/{articleId}/top") + public Result updateTop( + @PathVariable Long articleId, +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java` (M) + +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java +index 8b849da..0eddd64 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideCategoryController.java +@@ -24,19 +24,20 @@ public class AdminGuideCategoryController { + + private final GuideCategoryService categoryService; + +- @ApiOperation("分类列表") ++ @ApiOperation(value = "分类列表", notes = "返回全部攻略分类(含启用和停用),按排序值升序排列\n\n**关联字典**:\n- common_status:通用状态(列表显示,ACTIVE=启用/INACTIVE=停用)") + @GetMapping("/list") + public Result> listCategories() { + return Result.success(categoryService.listCategories()); + } + +- @ApiOperation("启用的分类列表") ++ @ApiOperation(value = "启用的分类列表", notes = "仅返回状态为启用的分类,创建文章时用于选择分类") + @GetMapping("/enabled") + public Result> listEnabledCategories() { + return Result.success(categoryService.listEnabledCategories()); + } + +- @ApiOperation("创建分类") ++ @ApiOperation(value = "创建分类", ++ notes = "创建攻略分类,分类名称不可重复。创建后默认启用,排序值越小越靠前。\n\n**权限**:需管理员登录。") + @PostMapping + public Result createCategory( + @Valid @RequestBody CategoryCreateRequest request, +@@ -45,7 +46,8 @@ public class AdminGuideCategoryController { + return Result.success(categoryService.createCategory(request, adminId)); + } + +- @ApiOperation("更新分类") ++ @ApiOperation(value = "更新分类", ++ notes = "更新攻略分类的名称、图标、描述等信息。\n\n**权限**:需管理员登录。") + @PutMapping("/{categoryId}") + public Result updateCategory( + @PathVariable Long categoryId, +@@ -53,14 +55,14 @@ public class AdminGuideCategoryController { + return Result.success(categoryService.updateCategory(categoryId, request)); + } + +- @ApiOperation("删除分类") ++ @ApiOperation(value = "删除分类", notes = "删除分类前需确保分类下无文章,否则删除失败") + @DeleteMapping("/{categoryId}") + public Result deleteCategory(@PathVariable Long categoryId) { + categoryService.deleteCategory(categoryId); + return Result.success(); + } + +- @ApiOperation("更新分类状态") ++ @ApiOperation(value = "更新分类状态", notes = "启用或停用分类。停用后该分类下的文章不会在小程序端展示,但不影响已有文章\n\n**关联字典**:\n- common_status:通用状态(状态切换,ACTIVE=启用/INACTIVE=停用)") + @PutMapping("/{categoryId}/status") + public Result updateStatus( + @PathVariable Long categoryId, +@@ -69,7 +71,8 @@ public class AdminGuideCategoryController { + return Result.success(); + } + +- @ApiOperation("更新分类排序") ++ @ApiOperation(value = "更新分类排序", ++ notes = "更新分类的排序值,排序值越小越靠前。影响小程序端分类导航的展示顺序。\n\n**权限**:需管理员登录。") + @PutMapping("/{categoryId}/sort") + public Result updateSort( + @PathVariable Long categoryId, +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java` (M) + +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java +index acd32b1..d747ae4 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/AdminGuideTagController.java +@@ -23,19 +23,20 @@ public class AdminGuideTagController { + + private final GuideTagService tagService; + +- @ApiOperation("系统标签列表") ++ @ApiOperation(value = "系统标签列表", notes = "返回管理员创建的系统标签(不含用户自定义标签),用于标签管理页") + @GetMapping("/managed") + public Result> listManagedTags() { + return Result.success(tagService.listManagedTags()); + } + +- @ApiOperation("所有标签列表") ++ @ApiOperation(value = "所有标签列表", notes = "返回全部标签(含系统标签和用户自定义标签),用于文章编辑时的标签选择器") + @GetMapping("/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", ++ notes = "创建攻略系统标签,标签名称不可重复。创建后可用于文章分类和筛选。\n\n**权限**:需管理员登录。") + @PostMapping + public Result createTag( + @Valid @RequestBody TagCreateRequest request, +@@ -44,7 +45,8 @@ public class AdminGuideTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", ++ notes = "更新标签名称。标签名称不可与其他已有标签重复。\n\n**权限**:需管理员登录。") + @PutMapping("/{tagId}") + public Result updateTag( + @PathVariable Long tagId, +@@ -52,14 +54,15 @@ public class AdminGuideTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", ++ notes = "删除标签并自动解除与所有文章的关联关系。\n\n**权限**:需管理员登录。") + @DeleteMapping("/{tagId}") + public Result deleteTag(@PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新文章标签") ++ @ApiOperation(value = "更新文章标签", notes = "全量替换文章的标签关联,传入新的标签ID列表(空数组表示清除所有标签)") + @PutMapping("/article/{articleId}") + public Result updateArticleTags( + @PathVariable Long articleId, +``` + +### `hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java` (M) + +```diff +diff --git a/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java b/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java +index 42c16dd..62838a6 100644 +--- a/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java ++++ b/hl-guide-service/src/main/java/com/hulalv/guide/controller/InternalWikiController.java +@@ -16,7 +16,7 @@ import java.util.Map; + /** + * 内部接口 - 供 mp-service Feign 调用 + */ +-@Api(tags = "【内部接口】攻略百科(Feign调用)") ++@Api(tags = "【内部接口】攻略百科(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/wiki") + @RequiredArgsConstructor +@@ -25,13 +25,14 @@ public class InternalWikiController { + private final GuideCategoryService categoryService; + private final GuideArticleService articleService; + +- @ApiOperation("查询已启用的攻略分类列表") ++ @ApiOperation(value = "查询已启用的攻略分类列表", ++ notes = "内部服务间调用。返回所有状态为启用的攻略分类,供小程序端展示分类导航。\n\n**关联字典**:\n- common_status:通用状态(仅返回ACTIVE状态的分类)") + @GetMapping("/categories") + public Result> listEnabledCategories() { + return Result.success(categoryService.listEnabledCategories()); + } + +- @ApiOperation("分页查询指定分类下的已发布文章") ++ @ApiOperation(value = "分页查询指定分类下的已发布文章", notes = "**关联字典**:\n- wiki_status:文章状态(返回字段)") + @GetMapping("/category/{categoryId}/articles") + public Result>> listCategoryArticles( + @PathVariable Long categoryId, +@@ -40,13 +41,14 @@ public class InternalWikiController { + return Result.success(articleService.listPublishedArticlesByCategory(categoryId, page, pageSize)); + } + +- @ApiOperation("查询已发布文章详情") ++ @ApiOperation(value = "查询已发布文章详情", notes = "**关联字典**:\n- wiki_status:文章状态(返回字段)") + @GetMapping("/article/{articleId}") + public Result> getArticle(@PathVariable Long articleId) { + return Result.success(articleService.getPublishedArticle(articleId)); + } + +- @ApiOperation("查询推荐文章列表") ++ @ApiOperation(value = "查询推荐文章列表", ++ notes = "内部服务间调用。返回已发布且标记为推荐的文章列表,用于小程序首页推荐位展示。默认返回5条。") + @GetMapping("/recommend-articles") + public Result>> listRecommendArticles( + @RequestParam(defaultValue = "5") Integer limit) { +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/config/Knife4jConfig.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/config/Knife4jConfig.java +index 3528af0..9b09f25 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/config/Knife4jConfig.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.insurance.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.spi.DocumentationType; + import springfox.documentation.spring.web.plugins.Docket; +@@ -11,6 +11,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket insuranceApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -22,7 +27,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.insurance.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java` (M) + +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java +index 852da1c..1505c2c 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceController.java +@@ -48,7 +48,8 @@ public class AdminInsuranceController { + private final InsuranceEntityProperties entityProperties; + private final PolicyShareService policyShareService; + +- @ApiOperation("保险产品列表") ++ @ApiOperation(value = "保险产品列表", ++ notes = "分页查询已同步的保险产品,支持按是否境外筛选。产品数据来源于保游网同步。\n\n**权限**:需管理员登录。") + @GetMapping("/products") + public Result> listProducts( + @ApiParam("页码") @RequestParam(defaultValue = "1") Integer page, +@@ -57,26 +58,30 @@ public class AdminInsuranceController { + return Result.success(orderService.listProducts(page, pageSize, isOverseas)); + } + +- @ApiOperation("保险产品详情") ++ @ApiOperation(value = "保险产品详情", ++ notes = "返回保险产品完整信息,包含产品名称、保险公司、保障范围、适用地区等。\n\n**权限**:需管理员登录。") + @GetMapping("/products/{id}") + public Result getProduct(@ApiParam("保险产品ID") @PathVariable("id") Long productId) { + return Result.success(orderService.getProductDetail(productId)); + } + +- @ApiOperation("保险产品计划及费率") ++ @ApiOperation(value = "保险产品计划及费率", ++ notes = "返回指定保险产品的所有投保计划及对应费率表,包含不同天数区间的保费价格。投保下单前需选择具体计划。\n\n**权限**:需管理员登录。") + @GetMapping("/products/{id}/plans") + public Result> getProductPlans(@ApiParam("保险产品ID") @PathVariable("id") Long productId) { + return Result.success(orderService.getProductPlans(productId)); + } + +- @ApiOperation("从保游网同步产品数据") ++ @ApiOperation(value = "从保游网同步产品数据", ++ notes = "手动触发从保游网API拉取最新保险产品数据(含计划和费率),同步到本地数据库。返回同步的产品数量。\n\n**权限**:需管理员登录。") + @PostMapping("/sync-products") + public Result syncProducts() { + int count = syncService.syncAll(); + return Result.success(count); + } + +- @ApiOperation("投保公司主体列表") ++ @ApiOperation(value = "投保公司主体列表", ++ notes = "返回系统配置的投保公司主体列表(来自Nacos配置),投保下单时选择以哪个公司主体投保。每个主体包含编码、公司名称和商户ID。\n\n**权限**:需管理员登录。") + @GetMapping("/entities") + public Result>> listEntities() { + List> list = entityProperties.getList().stream().map(e -> { +@@ -91,7 +96,7 @@ public class AdminInsuranceController { + return Result.success(list); + } + +- @ApiOperation("投保下单(每人独立保单)") ++ @ApiOperation(value = "投保下单(每人独立保单)", notes = "**关联字典**:\n- gender:性别(被保人信息)\n- id_card_type:证件类型(被保人信息)") + @PostMapping("/purchase") + public Result> purchase( + @ApiParam("投保请求") @Valid @RequestBody PurchaseInsuranceRequest request, +@@ -100,43 +105,48 @@ public class AdminInsuranceController { + return Result.success(orderService.purchase(request, adminId)); + } + +- @ApiOperation("退保") ++ @ApiOperation(value = "退保", ++ notes = "对单个保险订单发起退保,调用保游网退保API。退保成功后保险状态变为CANCELLED。\n\n**权限**:需管理员登录。\n**注意**:已生效的保单退保可能产生手续费。\n\n**关联字典**:\n- insurance_status:保险状态(状态流转)") + @PostMapping("/cancel/{id}") + public Result cancel(@ApiParam("保险订单ID") @PathVariable("id") Long insuranceOrderId) { + return Result.success(orderService.cancel(insuranceOrderId)); + } + +- @ApiOperation("保险订单列表") ++ @ApiOperation(value = "保险订单列表", notes = "**关联字典**:\n- insurance_status:保险状态(列表筛选+显示)") + @GetMapping("/orders") + public Result> listOrders(@ApiParam("查询条件") InsuranceQueryRequest request) { + return Result.success(orderService.listOrders(request)); + } + +- @ApiOperation("保险订单详情(含被保人)") ++ @ApiOperation(value = "保险订单详情(含被保人)", notes = "**关联字典**:\n- insurance_status:保险状态(显示)\n- gender:性别(被保人信息显示)\n- id_card_type:证件类型(被保人信息显示)") + @GetMapping("/orders/{id}") + public Result getOrderDetail(@ApiParam("保险订单ID") @PathVariable("id") Long insuranceOrderId) { + return Result.success(orderService.getOrderDetail(insuranceOrderId)); + } + +- @ApiOperation("按旅行订单查询保险单") ++ @ApiOperation(value = "按旅行订单查询保险单", ++ notes = "根据旅行订单ID查询关联的所有保险订单列表。在订单详情页展示保险购买情况。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- insurance_status:保险状态(列表显示)") + @GetMapping("/orders/by-order/{orderId}") + public Result> getByOrder(@ApiParam("旅行订单ID") @PathVariable Long orderId) { + return Result.success(orderService.getByOrderId(orderId)); + } + +- @ApiOperation("查询订单保险保障(含被保人详情)") ++ @ApiOperation(value = "查询订单保险保障(含被保人详情)", ++ notes = "返回订单维度的保险保障汇总信息,包含覆盖人数、保障期间、每位被保人的保单明细。用于订单详情页的保险保障展示。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- insurance_status:保险状态(显示)\n- gender:性别(被保人信息显示)\n- id_card_type:证件类型(被保人信息显示)") + @GetMapping("/coverage/{orderId}") + public Result getCoverage(@ApiParam("旅行订单ID") @PathVariable Long orderId) { + return Result.success(orderService.getCoverageByOrderId(orderId)); + } + +- @ApiOperation("保费试算(本地费率)") ++ @ApiOperation(value = "保费试算(本地费率)", ++ notes = "根据保险计划、投保天数和人数,使用本地同步的费率表试算保费。不调用保游网API,用于投保前的费用预估。\n\n**权限**:需管理员登录。") + @PostMapping("/trial-price") + public Result> trialPrice(@ApiParam("试算请求") @Valid @RequestBody TrialPriceRequest request) { + return Result.success(orderService.trialPrice(request)); + } + +- @ApiOperation("查询保游网账户余额") ++ @ApiOperation(value = "查询保游网账户余额", ++ notes = "查询保游网平台的账户余额,用于管理端展示当前可用投保额度。查询失败时返回null(非关键信息,不影响业务)。\n\n**权限**:需管理员登录。") + @GetMapping("/balance") + public Result getBalance() { + try { +@@ -152,13 +162,15 @@ public class AdminInsuranceController { + return Result.success(null); + } + +- @ApiOperation("下载保单PDF(Base64)") ++ @ApiOperation(value = "下载保单PDF(Base64)", ++ notes = "从保游网下载指定保险订单的电子保单PDF,以Base64编码返回。前端可解码后展示或提供下载。\n\n**权限**:需管理员登录。") + @GetMapping("/policy/{id}/download") + public Result downloadPolicy(@ApiParam("保险订单ID") @PathVariable("id") Long insuranceOrderId) { + return Result.success(orderService.downloadPolicy(insuranceOrderId)); + } + +- @ApiOperation("获取保游网充值链接(旧接口,保留兼容)") ++ @ApiOperation(value = "获取保游网充值链接(旧接口,保留兼容)", ++ notes = "返回保游网平台的充值页面URL。此为旧版接口,保留用于向后兼容,推荐使用在线充值接口。\n\n**权限**:需管理员登录。") + @GetMapping("/recharge-url") + public Result getRechargeUrl() { + String url = baoyouProperties.getRechargeUrl(); +@@ -168,13 +180,15 @@ public class AdminInsuranceController { + return Result.success(url); + } + +- @ApiOperation("在线充值(调用保游网支付API)") ++ @ApiOperation(value = "在线充值(调用保游网支付API)", ++ notes = "调用保游网在线充值API,生成充值支付链接。支持选择支付方式(支付宝/微信),充值完成后账户余额自动更新。\n\n**权限**:需管理员登录。") + @PostMapping("/recharge") + public Result> recharge(@ApiParam("充值请求") @Valid @RequestBody RechargeRequest request) { + return Result.success(orderService.recharge(request.getMoney(), request.getPayType(), request.getBackUrl())); + } + +- @ApiOperation("分享保单(合并某出行人所有有效保单PDF,上传OSS返回链接)") ++ @ApiOperation(value = "分享保单(合并某出行人所有有效保单PDF,上传OSS返回链接)", ++ notes = "合并指定出行人的所有有效保单PDF为一个文件,上传至OSS后返回公开访问链接。用于管理端分享保单给出行人。\n\n**权限**:需管理员登录。") + @PostMapping("/share-policy") + public Result sharePolicy( + @ApiParam("分享保单请求") @Valid @RequestBody SharePolicyRequest request) { +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java` (M) + +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java +index 9497720..04db6d6 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/AdminInsuranceSchemeController.java +@@ -24,26 +24,30 @@ public class AdminInsuranceSchemeController { + + private final InsuranceSchemeService schemeService; + +- @ApiOperation("活跃方案列表(下拉选择用)") ++ @ApiOperation(value = "活跃方案列表(下拉选择用)", ++ notes = "返回所有状态为启用的保险方案模板,用于投保下单时的方案下拉选择。\n\n**权限**:需管理员登录。") + @GetMapping("/list") + public Result> listActiveSchemes() { + return Result.success(schemeService.listActiveSchemes()); + } + +- @ApiOperation("全部方案列表(管理用)") ++ @ApiOperation(value = "全部方案列表(管理用)", ++ notes = "返回所有保险方案模板(含启用和停用),用于方案管理页面展示和编辑。\n\n**权限**:需管理员登录。") + @GetMapping("/list-all") + public Result> listAllSchemes() { + return Result.success(schemeService.listAllSchemes()); + } + +- @ApiOperation("方案详情") ++ @ApiOperation(value = "方案详情", ++ notes = "返回单个保险方案模板的完整信息,包含方案名称、保险产品关联、天数规则、费率配置等。\n\n**权限**:需管理员登录。") + @GetMapping("/{id}") + public Result getSchemeDetail( + @ApiParam("方案ID") @PathVariable("id") Long schemeId) { + return Result.success(schemeService.getSchemeDetail(schemeId)); + } + +- @ApiOperation("创建方案") ++ @ApiOperation(value = "创建方案", ++ notes = "创建保险方案模板,配置关联保险产品、投保天数规则和费率。创建后默认启用。\n\n**权限**:需管理员登录。") + @PostMapping + public Result createScheme( + @ApiParam("方案请求") @Valid @RequestBody InsuranceSchemeRequest request, +@@ -52,7 +56,8 @@ public class AdminInsuranceSchemeController { + return Result.success(schemeService.createScheme(request, adminId)); + } + +- @ApiOperation("更新方案") ++ @ApiOperation(value = "更新方案", ++ notes = "更新保险方案模板的配置信息,包括方案名称、关联产品、天数规则、费率等。\n\n**权限**:需管理员登录。") + @PutMapping("/{id}") + public Result updateScheme( + @ApiParam("方案ID") @PathVariable("id") Long schemeId, +@@ -62,14 +67,16 @@ public class AdminInsuranceSchemeController { + return Result.success(schemeService.updateScheme(schemeId, request, adminId)); + } + +- @ApiOperation("切换方案状态(启用/停用)") ++ @ApiOperation(value = "切换方案状态(启用/停用)", ++ notes = "切换保险方案模板的启用/停用状态。停用后不会出现在投保下单的方案选择列表中。\n\n**权限**:需管理员登录。\n\n**关联字典**:\n- common_status:通用状态(ACTIVE=启用/INACTIVE=停用)") + @PutMapping("/{id}/toggle-status") + public Result toggleStatus( + @ApiParam("方案ID") @PathVariable("id") Long schemeId) { + return Result.success(schemeService.toggleStatus(schemeId)); + } + +- @ApiOperation("删除方案(软删除)") ++ @ApiOperation(value = "删除方案(软删除)", ++ notes = "软删除保险方案模板。已使用该方案创建的保险订单不受影响。\n\n**权限**:需管理员登录。") + @DeleteMapping("/{id}") + public Result deleteScheme( + @ApiParam("方案ID") @PathVariable("id") Long schemeId) { +@@ -77,7 +84,8 @@ public class AdminInsuranceSchemeController { + return Result.success(null); + } + +- @ApiOperation("预览应用方案(解析日期+估算保费)") ++ @ApiOperation(value = "预览应用方案(解析日期+估算保费)", ++ notes = "根据方案模板和行程日期预览投保效果:解析实际投保起止日期、计算每人保费和总保费。用于投保前确认费用。\n\n**权限**:需管理员登录。") + @PostMapping("/preview-apply") + public Result previewApply( + @ApiParam("预览请求") @Valid @RequestBody ApplySchemeRequest request) { +``` + +### `hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java` (M) + +```diff +diff --git a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java +index 828cc04..d77d99e 100644 +--- a/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java ++++ b/hl-insurance-service/src/main/java/com/hulalv/insurance/controller/InternalInsuranceController.java +@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】保险(Feign调用)") ++@Api(tags = "【内部接口】保险(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/insurance") + @RequiredArgsConstructor +@@ -26,19 +26,22 @@ public class InternalInsuranceController { + private final InsuranceProductSyncService syncService; + private final PolicyShareService policyShareService; + +- @ApiOperation("按旅行订单查询保险单(内部调用)") ++ @ApiOperation(value = "按旅行订单查询保险单(内部调用)", ++ notes = "内部服务间调用。根据旅行订单ID查询关联的所有保险订单,返回保险状态、保费、保障期间等信息。\n\n**关联字典**:\n- insurance_status:保险状态(返回字段)") + @GetMapping("/by-order/{orderId}") + public Result> getByOrder(@ApiParam("旅行订单ID") @PathVariable Long orderId) { + return Result.success(orderService.getByOrderId(orderId)); + } + +- @ApiOperation("按订单批量查询保险单(内部调用)") ++ @ApiOperation(value = "按订单批量查询保险单(内部调用)", ++ notes = "内部服务间调用。批量查询多个旅行订单的保险订单,返回Map结构(key=订单ID,value=保险单列表),用于订单列表页展示保险状态。") + @PostMapping("/by-orders") + public Result>> getByOrders(@RequestBody List orderIds) { + return Result.success(orderService.getByOrderIds(orderIds)); + } + +- @ApiOperation("检查保险是否全覆盖(内部调用)") ++ @ApiOperation(value = "检查保险是否全覆盖(内部调用)", ++ notes = "内部服务间调用。根据出行人数和行程天数计算所需的人日数,与已投保的有效保单覆盖人日数对比,判断保险是否已全覆盖。") + @GetMapping("/coverage-complete/{orderId}") + public Result isCoverageComplete( + @ApiParam("旅行订单ID") @PathVariable Long orderId, +@@ -57,7 +60,8 @@ public class InternalInsuranceController { + return Result.success(coveredPersonDays >= requiredPersonDays); + } + +- @ApiOperation("按订单批量退保(级联失效调用)") ++ @ApiOperation(value = "按订单批量退保(级联失效调用)", ++ notes = "内部服务间调用。旅行订单取消或退款时级联调用,将该订单下所有有效保险单批量退保(调用保游网退保API),记录退保原因。") + @PostMapping("/invalidate/{orderId}") + public Result invalidateInsurance( + @ApiParam("旅行订单ID") @PathVariable Long orderId, +@@ -66,19 +70,22 @@ public class InternalInsuranceController { + return Result.success(null); + } + +- @ApiOperation("分享保单PDF(内部调用,返回base64)") ++ @ApiOperation(value = "分享保单PDF(内部调用,返回base64)", ++ notes = "内部服务间调用。合并指定出行人的所有有效保单PDF为一个文件,上传至OSS后返回下载链接和Base64内容,用于小程序端分享保单。") + @PostMapping("/share-policy") + public Result sharePolicy(@RequestBody SharePolicyRequest request) { + return Result.success(policyShareService.sharePolicy(request)); + } + +- @ApiOperation("按订单获取所有保单PDF(内部调用,合并所有出行人)") ++ @ApiOperation(value = "按订单获取所有保单PDF(内部调用,合并所有出行人)", ++ notes = "内部服务间调用。将指定订单下所有出行人的有效保单PDF合并为一个文件,上传至OSS后返回下载链接,用于订单维度的保单查看。") + @GetMapping("/share-policy-by-order/{orderId}") + public Result sharePolicyByOrder(@PathVariable Long orderId) { + return Result.success(policyShareService.sharePolicyByOrder(orderId)); + } + +- @ApiOperation("触发保险产品同步(内部调用/定时任务)") ++ @ApiOperation(value = "触发保险产品同步(内部调用/定时任务)", ++ notes = "内部服务间调用。从保游网API拉取最新保险产品数据(含计划和费率),同步到本地数据库。返回同步的产品数量。") + @PostMapping("/sync-products") + public Result syncProducts() { + int count = syncService.syncAll(); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/config/Knife4jConfig.java b/hl-material-service/src/main/java/com/hulalv/material/config/Knife4jConfig.java +index 93e40f0..c55eaa0 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/config/Knife4jConfig.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.material.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.spi.DocumentationType; + import springfox.documentation.spring.web.plugins.Docket; +@@ -11,6 +11,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket materialApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -22,7 +27,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.material.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java +index 08122a4..686a577 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/InternalMaterialController.java +@@ -22,7 +22,7 @@ import java.util.List; + * Internal endpoints for Feign calls from other services (scenic, hotel, etc.). + * Not exposed through gateway. + */ +-@Api(tags = "素材内部接口(Feign调用)") ++@Api(tags = "素材内部接口(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/material") + @RequiredArgsConstructor +@@ -31,7 +31,7 @@ public class InternalMaterialController { + private final MaterialRefService refService; + private final MaterialService materialService; + +- @ApiOperation("绑定引用") ++ @ApiOperation(value = "绑定引用", notes = "将素材与业务实体建立引用关系(如景区ID+封面图),记录引用类型(COVER/GALLERY/DETAIL等)") + @PostMapping("/ref/bind") + public Result bindRef( + @Valid @RequestBody RefBindRequest request, +@@ -40,7 +40,7 @@ public class InternalMaterialController { + return Result.success(); + } + +- @ApiOperation("批量绑定引用") ++ @ApiOperation(value = "批量绑定引用", notes = "批量建立素材与业务实体的引用关系,常用于保存包含多张图片的业务数据") + @PostMapping("/ref/batch-bind") + public Result batchBindRefs( + @Valid @RequestBody RefBatchBindRequest request, +@@ -49,7 +49,7 @@ public class InternalMaterialController { + return Result.success(); + } + +- @ApiOperation("解绑引用") ++ @ApiOperation(value = "解绑引用", notes = "删除单个素材与业务实体的引用关系") + @DeleteMapping("/ref/unbind") + public Result unbindRef(@Valid @RequestBody RefUnbindRequest request) { + refService.unbindRef(request.getMaterialId(), request.getBizType(), +@@ -57,14 +57,15 @@ public class InternalMaterialController { + return Result.success(); + } + +- @ApiOperation("批量解绑引用") ++ @ApiOperation(value = "批量解绑引用", notes = "批量删除素材引用关系,常用于业务实体更新时先清除旧引用再绑定新引用") + @DeleteMapping("/ref/batch-unbind") + public Result batchUnbindRefs(@Valid @RequestBody RefBatchUnbindRequest request) { + refService.batchUnbindRefs(request.getRefs()); + return Result.success(); + } + +- @ApiOperation("批量查询素材信息") ++ @ApiOperation(value = "批量查询素材信息", ++ notes = "内部服务间调用。根据素材ID列表批量查询素材信息,用于其他服务获取素材详情(如产品、景区等关联的素材数据)。") + @PostMapping("/by-ids") + public Result> getMaterialsByIds(@Valid @RequestBody BatchMaterialIdsRequest request) { + return Result.success(materialService.getMaterialsByIds(request.getMaterialIds())); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java +index 03566eb..77fa5a6 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialCategoryPermissionController.java +@@ -23,7 +23,7 @@ public class MaterialCategoryPermissionController { + + private final MaterialCategoryPermissionService permissionService; + +- @ApiOperation("获取角色的分类权限") ++ @ApiOperation(value = "获取角色的分类权限", notes = "仅超级管理员可操作。返回指定角色可访问的素材分类编码列表") + @GetMapping("/{roleCode}") + public Result> getPermissions( + @ApiParam("角色编码") @PathVariable String roleCode, +@@ -32,7 +32,7 @@ public class MaterialCategoryPermissionController { + return Result.success(permissionService.getPermissionsByRoleCode(roleCode)); + } + +- @ApiOperation("更新角色的分类权限") ++ @ApiOperation(value = "更新角色的分类权限", notes = "仅超级管理员可操作。全量替换指定角色的素材分类访问权限,传入允许访问的分类编码列表") + @PutMapping("/{roleCode}") + public Result updatePermissions( + @ApiParam("角色编码") @PathVariable String roleCode, +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java +index 0fa7c7e..d79def9 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialController.java +@@ -47,7 +47,7 @@ public class MaterialController { + + // ==================== Upload ==================== + +- @ApiOperation("获取上传凭证") ++ @ApiOperation(value = "获取上传凭证", notes = "上传素材第一步:获取OSS预签名URL和凭证。前端使用凭证直传OSS后调用确认上传。支持基于角色的分类权限校验") + @PostMapping("/upload/token") + public Result requestUploadToken( + @ApiParam("上传凭证请求") @Valid @RequestBody MaterialUploadTokenRequest request, +@@ -57,7 +57,7 @@ public class MaterialController { + return Result.success(materialService.requestUploadToken(request, adminId, role)); + } + +- @ApiOperation("确认上传完成") ++ @ApiOperation(value = "确认上传完成", notes = "上传素材第二步:前端直传OSS完成后调用此接口创建素材记录,支持MD5去重\n\n**关联字典**:\n- material_tag:素材标签(上传时可选标签)") + @PostMapping("/upload/confirm") + public Result confirmUpload( + @ApiParam("确认上传请求") @Valid @RequestBody MaterialUploadConfirmRequest request, +@@ -66,7 +66,7 @@ public class MaterialController { + return Result.success(materialService.confirmUpload(request, adminId)); + } + +- @ApiOperation("文件夹上传初始化(创建分类+批量获取凭证)") ++ @ApiOperation(value = "文件夹上传初始化(创建分类+批量获取凭证)", notes = "支持整个文件夹上传:自动根据文件夹名创建子分类,为每个文件批量获取上传凭证,前端逐一上传后批量确认") + @PostMapping("/upload/folder") + public Result folderUploadInit( + @ApiParam("文件夹上传初始化请求") @Valid @RequestBody FolderUploadInitRequest request, +@@ -79,7 +79,8 @@ public class MaterialController { + + // ==================== Chunk Upload (分片上传) ==================== + +- @ApiOperation("分片上传-初始化") ++ @ApiOperation(value = "分片上传-初始化", ++ notes = "大文件上传第一步:初始化分片上传任务,返回uploadId和每个分片的预签名URL。前端按分片并发上传后调用完成合并接口。\n\n**权限**:需管理员登录,受角色分类权限限制。") + @PostMapping("/upload/chunk/init") + public Result chunkUploadInit( + @ApiParam("分片上传初始化请求") @Valid @RequestBody ChunkUploadInitRequest request, +@@ -89,7 +90,8 @@ public class MaterialController { + return Result.success(chunkUploadService.initChunkUpload(request, adminId, role)); + } + +- @ApiOperation("分片上传-上传分片") ++ @ApiOperation(value = "分片上传-上传分片", ++ notes = "大文件上传第二步:逐个上传分片数据,分片索引从0开始。支持断点续传,已上传的分片无需重传。") + @PostMapping("/upload/chunk") + public Result chunkUploadPart( + @ApiParam("上传ID") @RequestParam("uploadId") String uploadId, +@@ -99,7 +101,8 @@ public class MaterialController { + return Result.success(chunkUploadService.uploadChunk(uploadId, chunkIndex, chunk)); + } + +- @ApiOperation("分片上传-完成合并") ++ @ApiOperation(value = "分片上传-完成合并", ++ notes = "大文件上传第三步:所有分片上传完成后调用,OSS端合并分片为完整文件并创建素材记录。") + @PostMapping("/upload/chunk/complete") + public Result chunkUploadComplete( + @ApiParam("分片上传完成请求") @Valid @RequestBody ChunkUploadCompleteRequest request, +@@ -108,7 +111,8 @@ public class MaterialController { + return Result.success(chunkUploadService.completeChunkUpload(request.getUploadId(), adminId)); + } + +- @ApiOperation("分片上传-取消") ++ @ApiOperation(value = "分片上传-取消", ++ notes = "取消分片上传任务,清理已上传的分片数据和OSS临时文件。仅上传发起者可取消。") + @PostMapping("/upload/chunk/cancel") + public Result chunkUploadCancel( + @ApiParam("分片上传取消请求") @Valid @RequestBody ChunkUploadCancelRequest request, +@@ -120,7 +124,7 @@ public class MaterialController { + + // ==================== CRUD ==================== + +- @ApiOperation("素材列表") ++ @ApiOperation(value = "素材列表", notes = "分页查询素材,支持按分类、标签、文件类型、关键词筛选。返回结果受角色分类权限限制\n\n**关联字典**:\n- file_type:文件类型(列表筛选+显示)") + @GetMapping("/list") + public Result> listMaterials( + @ApiParam("素材查询条件") @Valid MaterialQueryRequest query, +@@ -131,7 +135,8 @@ public class MaterialController { + return Result.success(materialService.listMaterials(query, adminId, role, categoryMap)); + } + +- @ApiOperation("素材详情") ++ @ApiOperation(value = "素材详情", ++ notes = "返回素材完整信息,包含文件名、URL、分类、标签、文件大小、上传者等。受角色分类权限限制。\n\n**关联字典**:\n- file_type:文件类型(显示)") + @GetMapping("/{materialId}") + public Result getMaterial( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -141,7 +146,7 @@ public class MaterialController { + return Result.success(materialService.getMaterial(materialId, role, categoryMap)); + } + +- @ApiOperation("更新素材信息") ++ @ApiOperation(value = "更新素材信息", notes = "**关联字典**:\n- material_tag:素材标签(编辑时选择标签)") + @PutMapping("/{materialId}") + public Result updateMaterial( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -153,7 +158,7 @@ public class MaterialController { + return Result.success(materialService.updateMaterial(materialId, request, adminId, role, categoryMap)); + } + +- @ApiOperation("删除素材") ++ @ApiOperation(value = "删除素材", notes = "删除素材记录。如果素材存在引用关系(被景区、酒店等使用),则不允许删除") + @DeleteMapping("/{materialId}") + public Result deleteMaterial( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -164,7 +169,7 @@ public class MaterialController { + return Result.success(); + } + +- @ApiOperation("批量删除素材") ++ @ApiOperation(value = "批量删除素材", notes = "批量删除素材,返回删除结果(成功数/失败数/失败原因)。有引用关系的素材会跳过并记录失败原因") + @DeleteMapping("/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +@@ -179,7 +184,7 @@ public class MaterialController { + + // ==================== Tags on Materials ==================== + +- @ApiOperation("更新素材标签") ++ @ApiOperation(value = "更新素材标签", notes = "全量替换单个素材的标签,传入新的标签ID列表") + @PutMapping("/{materialId}/tags") + public Result updateMaterialTags( + @ApiParam("素材ID") @PathVariable Long materialId, +@@ -192,7 +197,7 @@ public class MaterialController { + return Result.success(); + } + +- @ApiOperation("批量更新标签") ++ @ApiOperation(value = "批量更新标签", notes = "对多个素材同时添加和/或移除标签,支持增量操作(addTagIds新增,removeTagIds移除)") + @PutMapping("/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签更新请求") @Valid @RequestBody BatchTagRequest request, +@@ -212,7 +217,7 @@ public class MaterialController { + + // ==================== References ==================== + +- @ApiOperation("查看素材引用记录") ++ @ApiOperation(value = "查看素材引用记录", notes = "查看素材被哪些业务实体引用(如景区封面、酒店轮播图等),用于判断素材是否可安全删除") + @GetMapping("/{materialId}/refs") + public Result> getMaterialRefs(@ApiParam("素材ID") @PathVariable Long materialId) { + return Result.success(refService.getRefsByMaterialId(materialId)); +@@ -220,7 +225,7 @@ public class MaterialController { + + // ==================== Categories ==================== + +- @ApiOperation("获取有权限的分类列表(含素材数量)") ++ @ApiOperation(value = "获取有权限的分类列表(含素材数量)", notes = "返回当前角色有权限查看的素材分类树,每个分类包含素材数量统计。超级管理员可见全部分类") + @GetMapping("/categories") + public Result> getCategories(HttpServletRequest httpRequest) { + String role = getRole(httpRequest); +@@ -230,7 +235,7 @@ public class MaterialController { + + // ==================== Sub-categories ==================== + +- @ApiOperation("创建子分类") ++ @ApiOperation(value = "创建子分类", notes = "在一级分类下创建子分类,分类编码自动生成。子分类用于更细粒度的素材归档") + @PostMapping("/category/sub") + public Result createSubCategory( + @ApiParam("子分类创建请求") @Valid @RequestBody SubCategoryCreateRequest request, +@@ -241,7 +246,8 @@ public class MaterialController { + return Result.success(categoryService.createSubCategory(request, adminId, role, categoryMap)); + } + +- @ApiOperation("更新子分类") ++ @ApiOperation(value = "更新子分类", ++ notes = "更新子分类的名称或排序值。仅有该分类权限的管理员可操作。") + @PutMapping("/category/sub/{categoryId}") + public Result updateSubCategory( + @ApiParam("子分类ID") @PathVariable Long categoryId, +@@ -252,7 +258,7 @@ public class MaterialController { + return Result.success(categoryService.updateSubCategory(categoryId, request, adminId, role)); + } + +- @ApiOperation("删除子分类") ++ @ApiOperation(value = "删除子分类", notes = "删除子分类前需确保分类下无素材,否则删除失败") + @DeleteMapping("/category/sub/{categoryId}") + public Result deleteSubCategory( + @ApiParam("子分类ID") @PathVariable Long categoryId, +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java +index a90884f..31d53b5 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MaterialTagController.java +@@ -23,19 +23,22 @@ public class MaterialTagController { + + private final MaterialTagService tagService; + +- @ApiOperation("获取管理标签(标签管理用)") ++ @ApiOperation(value = "获取管理标签(标签管理用)", ++ notes = "返回管理员创建的系统标签列表(不含用户自定义标签),用于标签管理页的CRUD操作。") + @GetMapping("/tags") + public Result> listManagedTags() { + return Result.success(tagService.listManagedTags()); + } + +- @ApiOperation("获取全部标签(选择器用,含自定义标签)") ++ @ApiOperation(value = "获取全部标签(选择器用,含自定义标签)", ++ notes = "返回所有标签(含系统标签和用户自定义标签),用于素材上传/编辑时的标签选择器。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", ++ notes = "创建系统级素材标签,标签名称不可重复。创建后可用于素材分类和筛选。\n\n**权限**:需管理员登录。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("创建标签请求") @Valid @RequestBody TagCreateRequest request, +@@ -44,7 +47,8 @@ public class MaterialTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签(按名称查找或创建)") ++ @ApiOperation(value = "解析自定义标签(按名称查找或创建)", ++ notes = "按标签名称查找已有标签,不存在则自动创建为用户自定义标签。用于素材上传时输入自由标签文本的场景。\n\n**权限**:需管理员登录。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("自定义标签请求") @RequestBody TagCreateRequest request, +@@ -53,7 +57,8 @@ public class MaterialTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", ++ notes = "更新标签名称。标签名称不可与其他已有标签重复。\n\n**权限**:需管理员登录。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -61,7 +66,8 @@ public class MaterialTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", ++ notes = "删除标签并自动解除与所有素材的关联关系。\n\n**权限**:需管理员登录。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java b/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java +index a595577..17f64ac 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/controller/MpMaterialController.java +@@ -20,7 +20,7 @@ public class MpMaterialController { + + private final MaterialService materialService; + +- @ApiOperation("获取小程序分类下的全部素材") ++ @ApiOperation(value = "获取小程序分类下的全部素材", notes = "返回miniprogram分类下的所有素材,用于小程序端展示公共素材资源(如引导页图片、默认头像等)") + @GetMapping("/miniprogram") + public Result> listMiniprogramMaterials() { + return Result.success(materialService.listMaterialsByCategoryCode("miniprogram")); +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java +index 7adbe0a..93a06f8 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCancelRequest.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传取消请求") + public class ChunkUploadCancelRequest { + ++ @ApiModelProperty("上传ID") + private String uploadId; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java +index 712c15c..d876fcc 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadCompleteRequest.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传完成请求") + public class ChunkUploadCompleteRequest { + ++ @ApiModelProperty("上传ID") + private String uploadId; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java +index 2d94f04..939a630 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/ChunkUploadInitRequest.java +@@ -1,13 +1,25 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传初始化请求") + public class ChunkUploadInitRequest { + ++ @ApiModelProperty("文件名") + private String filename; ++ ++ @ApiModelProperty("文件大小(字节)") + private Long fileSize; ++ ++ @ApiModelProperty("文件MIME类型") + private String contentType; ++ ++ @ApiModelProperty("分组标识") + private String groupKey; ++ ++ @ApiModelProperty("文件哈希值") + private String fileHash; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java +index 96c2499..449c3b4 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileBatchIdsRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("文件批量ID请求") + public class FileBatchIdsRequest { + ++ @ApiModelProperty("文件ID列表") + private List fileIds; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java +index bb85acc..1b1d316 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadConfirmRequest.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("文件上传确认请求") + public class FileUploadConfirmRequest { + ++ @ApiModelProperty("文件ID") + private String fileId; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java +index 4d7a140..ee7cd4e 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/dto/FileUploadTokenRequest.java +@@ -1,13 +1,25 @@ + package com.hulalv.material.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("文件上传令牌请求") + public class FileUploadTokenRequest { + ++ @ApiModelProperty("文件名") + private String fileName; ++ ++ @ApiModelProperty("文件大小(字节)") + private Long fileSize; ++ ++ @ApiModelProperty("文件哈希值") + private String fileHash; ++ ++ @ApiModelProperty("分组标识") + private String groupKey; ++ ++ @ApiModelProperty("是否强制使用预签名URL") + private boolean forcePresigned; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java +index 6cd60b6..9f38bc4 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadInitVO.java +@@ -1,12 +1,22 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传初始化结果") + public class ChunkUploadInitVO { + ++ @ApiModelProperty("上传ID") + private String uploadId; ++ ++ @ApiModelProperty("分片大小(字节)") + private int chunkSize; ++ ++ @ApiModelProperty("文件ID") + private String fileId; ++ ++ @ApiModelProperty("OSS对象Key") + private String ossKey; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java +index 1628687..cc0df47 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/ChunkUploadPartVO.java +@@ -1,9 +1,13 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("分片上传片段结果") + public class ChunkUploadPartVO { + ++ @ApiModelProperty("分片ETag标识") + private String etag; + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java +index 779f74d..07b2068 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileUploadTokenVO.java +@@ -1,28 +1,58 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.time.LocalDateTime; + + @Data ++@ApiModel("文件上传令牌结果") + public class FileUploadTokenVO { + ++ @ApiModelProperty("文件ID") + private String fileId; ++ ++ @ApiModelProperty("文件MIME类型") + private String contentType; ++ ++ @ApiModelProperty("上传模式") + private String uploadMode; ++ ++ @ApiModelProperty("预签名上传URL") + private String presignedUrl; ++ ++ @ApiModelProperty("OSS对象Key") + private String ossKey; ++ ++ @ApiModelProperty("过期时间") + private LocalDateTime expireAt; ++ ++ @ApiModelProperty("STS临时凭证") + private StsTokenInfo stsToken; ++ ++ @ApiModelProperty("OSS存储桶名称") + private String bucket; ++ ++ @ApiModelProperty("OSS区域") + private String region; ++ ++ @ApiModelProperty("文件信息(秒传时返回)") + private FileVO file; + + @Data ++ @ApiModel("STS临时凭证信息") + public static class StsTokenInfo { ++ @ApiModelProperty("访问密钥ID") + private String accessKeyId; ++ ++ @ApiModelProperty("访问密钥Secret") + private String accessKeySecret; ++ ++ @ApiModelProperty("安全令牌") + private String securityToken; ++ ++ @ApiModelProperty("过期时间") + private String expiration; + } + } +``` + +### `hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java` (M) + +```diff +diff --git a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java +index a5e43b9..90612e6 100644 +--- a/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java ++++ b/hl-material-service/src/main/java/com/hulalv/material/feign/vo/FileVO.java +@@ -1,23 +1,51 @@ + package com.hulalv.material.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import java.time.LocalDateTime; + + @Data ++@ApiModel("文件信息VO") + public class FileVO { + ++ @ApiModelProperty("文件ID") + private String fileId; ++ ++ @ApiModelProperty("文件名") + private String fileName; ++ ++ @ApiModelProperty("文件类型") + private String fileType; ++ ++ @ApiModelProperty("MIME类型") + private String mimeType; ++ ++ @ApiModelProperty("文件大小(字节)") + private Long fileSize; ++ ++ @ApiModelProperty("文件哈希值") + private String fileHash; ++ ++ @ApiModelProperty("OSS访问URL") + private String ossUrl; ++ ++ @ApiModelProperty("缩略图URL") + private String thumbnailUrl; ++ ++ @ApiModelProperty("预览URL") + private String previewUrl; ++ ++ @ApiModelProperty("分组标识") + private String groupKey; ++ ++ @ApiModelProperty("文件状态") + private String status; ++ ++ @ApiModelProperty("引用次数") + private Integer refCount; ++ ++ @ApiModelProperty("创建时间") + private LocalDateTime createdAt; + } +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/config/Knife4jConfig.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/config/Knife4jConfig.java +index 23786d4..4e0d06b 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/config/Knife4jConfig.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/config/Knife4jConfig.java +@@ -19,7 +19,8 @@ public class Knife4jConfig { + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.monitor.controller")) +- .paths(PathSelectors.any()) ++ .paths(PathSelectors.ant("/internal/**").negate() ++ .and(PathSelectors.ant("/callback/**").negate())) + .build(); + } + +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java +index 6c26fc1..04d1ebd 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ApprovalLogController.java +@@ -19,7 +19,7 @@ public class ApprovalLogController { + + private final ApprovalLogService approvalLogService; + +- @ApiOperation("审批日志分页查询") ++ @ApiOperation(value = "审批日志分页查询", notes = "查询企微OA审批流程记录,支持按审批状态(1-审批中/2-已通过/3-已驳回/4-已撤销)、申请人、模板名称筛选\n\n**关联字典**:\n- approval_sp_status:审批状态(列表筛选+显示)") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,7 +32,7 @@ public class ApprovalLogController { + return Result.success(approvalLogService.queryPage(page, pageSize, spStatus, applyUserName, spName, startTime, endTime)); + } + +- @ApiOperation("审批日志详情") ++ @ApiOperation(value = "审批日志详情", notes = "**关联字典**:\n- approval_sp_status:审批状态(显示)") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + ApprovalLog approvalLog = approvalLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java +index 43d56d8..12117da 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/DataRetentionController.java +@@ -19,7 +19,7 @@ public class DataRetentionController { + + private final DataRetentionService dataRetentionService; + +- @ApiOperation("手动触发数据清理") ++ @ApiOperation(value = "手动触发数据清理", notes = "仅超级管理员可操作。按数据保留策略清理过期日志(操作日志/错误日志/通知日志等),返回各类型清理的记录数") + @PostMapping("/cleanup") + public Result> cleanup(HttpServletRequest request) { + requireSuperAdmin(request); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java +index 77046be..06bbdf5 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ErrorLogController.java +@@ -19,7 +19,7 @@ public class ErrorLogController { + + private final ErrorLogService errorLogService; + +- @ApiOperation("错误日志分页查询") ++ @ApiOperation(value = "错误日志分页查询", notes = "查询各微服务的异常记录,支持按服务名称、异常类名、时间范围筛选。堆栈信息仅保留com.hulalv包内的调用帧") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -31,7 +31,8 @@ public class ErrorLogController { + return Result.success(errorLogService.queryPage(page, pageSize, serviceName, exceptionClass, startTime, endTime)); + } + +- @ApiOperation("错误日志详情") ++ @ApiOperation(value = "错误日志详情", ++ notes = "返回单条错误日志的完整信息,包含异常类名、错误消息、过滤后的堆栈信息(仅com.hulalv包内调用帧)、请求URL、请求参数等。") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + ErrorLog errorLog = errorLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java +index 51e3999..44d463e 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/InternalLogController.java +@@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.*; + * Internal endpoints for receiving logs from other services. + * NOT exposed via gateway. + */ +-@Api(tags = "【内部接口】日志接收(Feign调用)") ++@Api(tags = "【内部接口】日志接收(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/monitor") + @RequiredArgsConstructor +@@ -29,35 +29,35 @@ public class InternalLogController { + private final NotificationLogService notificationLogService; + private final ApprovalLogService approvalLogService; + +- @ApiOperation("Receive operation log") ++ @ApiOperation(value = "接收操作日志", notes = "各微服务通过AOP拦截@OperationLog注解的方法,异步发送操作日志到此接口存储") + @PostMapping("/operation-log") +- public Result receiveOperationLog(@RequestBody OperationLogDTO dto) { ++ public Result receiveOperationLog(@RequestBody OperationLogDTO dto) { + operationLogService.saveFromDTO(dto); + return Result.success(); + } + +- @ApiOperation("Receive error log") ++ @ApiOperation(value = "接收错误日志", notes = "各微服务的GlobalExceptionHandler捕获异常后,异步发送错误日志到此接口存储") + @PostMapping("/error-log") +- public Result receiveErrorLog(@RequestBody ErrorLogDTO dto) { ++ public Result receiveErrorLog(@RequestBody ErrorLogDTO dto) { + errorLogService.saveFromDTO(dto); + return Result.success(); + } + +- @ApiOperation("Receive notification log") ++ @ApiOperation(value = "接收通知日志", notes = "通知服务发送消息(短信/站内信/企微等)后,记录发送结果到此接口") + @PostMapping("/notification-log") +- public Result receiveNotificationLog(@RequestBody NotificationLogDTO dto) { ++ public Result receiveNotificationLog(@RequestBody NotificationLogDTO dto) { + notificationLogService.saveFromDTO(dto); + return Result.success(); + } + +- @ApiOperation("Receive approval log") ++ @ApiOperation(value = "接收审批日志", notes = "企微回调服务接收审批事件后,发送审批日志到此接口。同一审批单号会更新已有记录(按thirdNo去重)") + @PostMapping("/approval-log") +- public Result receiveApprovalLog(@RequestBody ApprovalLogDTO dto) { ++ public Result receiveApprovalLog(@RequestBody ApprovalLogDTO dto) { + approvalLogService.saveOrUpdateByThirdNo(dto); + return Result.success(); + } + +- @ApiOperation("Get customer stats for a user (add/loss counts)") ++ @ApiOperation(value = "获取用户客户统计", notes = "统计指定用户的客户增减数据(新增客户数/流失客户数),用于客户管理看板") + @GetMapping("/notification-log/customer-stats") + public Result> getCustomerStats( + @RequestParam("userId") String userId) { +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java +index 52c9e86..bc58580 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/LoginLogController.java +@@ -19,7 +19,7 @@ public class LoginLogController { + + private final UserServiceClient userServiceClient; + +- @ApiOperation("登录日志分页查询") ++ @ApiOperation(value = "登录日志分页查询", notes = "查询管理员登录记录(代理到user-service),包含登录IP、设备信息、登录方式和登录结果\n\n**关联字典**:\n- login_status:登录状态(列表筛选+显示)") + @GetMapping + public Result list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java +index 029e317..0d29b88 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/MysqlMonitorController.java +@@ -21,20 +21,20 @@ public class MysqlMonitorController { + + private final MysqlMonitorService mysqlMonitorService; + +- @ApiOperation("MySQL实时监控数据") ++ @ApiOperation(value = "MySQL实时监控数据", notes = "返回MySQL实时状态:连接数、QPS、缓冲池命中率、线程状态、慢查询计数等核心指标") + @GetMapping + public Result> overview() { + return Result.success(mysqlMonitorService.getOverview()); + } + +- @ApiOperation("表空间列表") ++ @ApiOperation(value = "表空间列表", notes = "查询各数据库表的空间占用情况,包含数据大小、索引大小、行数等信息。可指定schema筛选,仅允许查询hl_前缀的数据库") + @GetMapping("/tables") + public Result>> tables( + @ApiParam("数据库名") @RequestParam(required = false) String schema) { + return Result.success(mysqlMonitorService.getTableSpaces(schema)); + } + +- @ApiOperation("慢SQL查询统计") ++ @ApiOperation(value = "慢SQL查询统计", notes = "仅超级管理员可操作。查询慢SQL统计信息,返回执行时间最长的SQL语句及其执行次数、平均耗时等") + @GetMapping("/slow-queries") + public Result>> slowQueries( + HttpServletRequest request, +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java +index 7e55cae..46d7b72 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/NotificationLogController.java +@@ -19,7 +19,7 @@ public class NotificationLogController { + + private final NotificationLogService notificationLogService; + +- @ApiOperation("消息通知日志分页查询") ++ @ApiOperation(value = "消息通知日志分页查询", notes = "查询各渠道(短信/站内信/企微/公众号)的通知发送记录,支持按通知类型、用户、发送状态筛选\n\n**关联字典**:\n- notification_send_status:发送状态(列表筛选+显示,0=待发送/1=成功/2=失败)") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,7 +32,8 @@ public class NotificationLogController { + return Result.success(notificationLogService.queryPage(page, pageSize, notificationType, userName, sendStatus, startTime, endTime)); + } + +- @ApiOperation("消息通知日志详情") ++ @ApiOperation(value = "消息通知日志详情", ++ notes = "返回单条通知发送日志的完整信息,包含通知类型、接收用户、发送渠道、发送状态、失败原因(如有)、消息内容等。") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + NotificationLog notificationLog = notificationLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java +index 43516e4..f620a50 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/OperationLogController.java +@@ -19,7 +19,7 @@ public class OperationLogController { + + private final OperationLogService operationLogService; + +- @ApiOperation("操作日志分页查询") ++ @ApiOperation(value = "操作日志分页查询", notes = "查询管理员的操作记录,支持按模块、管理员、状态、时间范围筛选。记录包含请求参数、响应结果和耗时信息\n\n**关联字典**:\n- operation_log_status:操作状态(列表筛选+显示,0=成功/1=失败)") + @GetMapping + public Result> list( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,7 +32,8 @@ public class OperationLogController { + return Result.success(operationLogService.queryPage(page, pageSize, module, adminId, status, startTime, endTime)); + } + +- @ApiOperation("操作日志详情") ++ @ApiOperation(value = "操作日志详情", ++ notes = "返回单条操作日志的完整信息,包含操作模块、操作描述、请求参数、响应结果、操作耗时、操作人信息、IP地址等。") + @GetMapping("/{id}") + public Result detail(@ApiParam("日志ID") @PathVariable Long id) { + OperationLog log = operationLogService.getById(id); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java +index e70ae11..ffc059f 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RedisMonitorController.java +@@ -17,7 +17,7 @@ public class RedisMonitorController { + + private final RedisMonitorService redisMonitorService; + +- @ApiOperation("Redis实时监控数据") ++ @ApiOperation(value = "Redis实时监控数据", notes = "返回Redis实时状态:内存使用量、连接数、Key数量、命中率、每秒命令数等核心指标") + @GetMapping + public Result> overview() { + return Result.success(redisMonitorService.getOverview()); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java +index 5d642cb..9f32297 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/RocketMqMonitorController.java +@@ -18,19 +18,19 @@ public class RocketMqMonitorController { + + private final RocketMqMonitorService rocketMqMonitorService; + +- @ApiOperation("RocketMQ概览") ++ @ApiOperation(value = "RocketMQ概览", notes = "返回RocketMQ集群状态:Broker状态、Topic数量、消息积压量、生产者/消费者连接数等核心指标") + @GetMapping + public Result> overview() { + return Result.success(rocketMqMonitorService.getOverview()); + } + +- @ApiOperation("Topic统计") ++ @ApiOperation(value = "Topic统计", notes = "返回各Topic的消息量、最新偏移量和消费进度等信息") + @GetMapping("/topics") + public Result>> topicStats() { + return Result.success(rocketMqMonitorService.getTopicStats()); + } + +- @ApiOperation("消费者组统计") ++ @ApiOperation(value = "消费者组统计", notes = "返回各消费者组的消费进度、积压量和在线消费者实例信息") + @GetMapping("/consumer-groups") + public Result>> consumerGroupStats() { + return Result.success(rocketMqMonitorService.getConsumerGroupStats()); +``` + +### `hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java` (M) + +```diff +diff --git a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java +index 63d09ef..11e5509 100644 +--- a/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java ++++ b/hl-monitor-service/src/main/java/com/hulalv/monitor/controller/ServiceMonitorController.java +@@ -18,7 +18,7 @@ public class ServiceMonitorController { + + private final ServiceMonitorService serviceMonitorService; + +- @ApiOperation("微服务列表和健康状态") ++ @ApiOperation(value = "微服务列表和健康状态", notes = "从Nacos注册中心获取所有微服务的实例列表和健康状态,包含IP、端口、注册时间和健康检查结果") + @GetMapping + public Result>> list() { + return Result.success(serviceMonitorService.getServiceList()); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java +index f7f787c..da96036 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpActivityController.java +@@ -22,7 +22,8 @@ public class MpActivityController { + private final MpResourceFeignClient resourceFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("活动列表") ++ @ApiOperation(value = "活动列表", ++ notes = "分页查询已上架的活动列表,支持关键词和分类筛选。聚合层透传resource-service的活动数据给小程序前端。") + @GetMapping("/list") + public Result>> listActivities( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -37,7 +38,8 @@ public class MpActivityController { + return resourceFeignClient.listActivities(query); + } + +- @ApiOperation("活动详情") ++ @ApiOperation(value = "活动详情", ++ notes = "获取活动完整信息(含图文详情、价格等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{activityId}") + public Result> getActivityDetail(@ApiParam("活动ID") @PathVariable Long activityId) { + Result> result = resourceFeignClient.getActivityDetail(activityId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java +index 9023792..61ad359 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBadgeController.java +@@ -18,7 +18,7 @@ public class MpBadgeController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取徽章数据") ++ @ApiOperation(value = "获取徽章数据", notes = "返回用户的徽章统计(未读消息数、待办事项数等),用于「我的」页面角标展示") + @GetMapping + public Result> getBadges(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java +index 6089f32..df4d3dd 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpBannerController.java +@@ -23,7 +23,8 @@ public class MpBannerController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取当前生效的轮播图列表") ++ @ApiOperation(value = "获取当前生效的轮播图列表", ++ notes = "返回当前处于有效期内的轮播图,按排序值排列。用于小程序首页顶部轮播展示,透传自user-service。") + @GetMapping("/active") + public Result>> listActiveBanners() { + return userFeignClient.listActiveBanners(); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java +index be29a79..84ec777 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpConfigController.java +@@ -22,13 +22,15 @@ public class MpConfigController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取所有非敏感前端配置") ++ @ApiOperation(value = "获取所有非敏感前端配置", ++ notes = "返回所有非SECRET类型的前端配置项(如主题色、客服电话、版本号等)。不含敏感配置,可安全传输给小程序端。") + @GetMapping + public Result>> listPublicConfigs() { + return userFeignClient.listAllFrontendConfigs(); + } + +- @ApiOperation("按分组获取非敏感前端配置") ++ @ApiOperation(value = "按分组获取非敏感前端配置", ++ notes = "按配置分组获取前端配置项,如UI分组、功能开关分组等。用于小程序按需加载特定分组的配置。") + @GetMapping("/group/{group}") + public Result>> listPublicConfigsByGroup( + @ApiParam("配置分组") @PathVariable String group) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java +index 4e34f66..c5b60cb 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpContractController.java +@@ -20,7 +20,7 @@ public class MpContractController { + + private final MpContractFeignClient contractFeignClient; + +- @ApiOperation("合同列表") ++ @ApiOperation(value = "合同列表", notes = "**关联字典(BFF透传)**:\n- contract_status:合同状态(列表筛选+显示)") + @GetMapping("/list") + public Result>> listContracts( + HttpServletRequest request, +@@ -31,7 +31,7 @@ public class MpContractController { + return contractFeignClient.listContracts(userId, status, page, pageSize); + } + +- @ApiOperation(value = "合同详情", notes = "返回合同基本信息、签署状态、出行人签署详情及合同文件下载链接") ++ @ApiOperation(value = "合同详情", notes = "返回合同基本信息、签署状态、出行人签署详情及合同文件下载链接\n\n**关联字典(BFF透传)**:\n- contract_status:合同状态(显示)") + @GetMapping("/{id}") + public Result> getContractDetail( + HttpServletRequest request, +@@ -40,7 +40,7 @@ public class MpContractController { + return contractFeignClient.getContractDetail(id, userId); + } + +- @ApiOperation(value = "按订单查合同", notes = "返回订单关联的最新有效合同(非作废)") ++ @ApiOperation(value = "按订单查合同", notes = "返回订单关联的最新有效合同(非作废)\n\n**关联字典(BFF透传)**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}") + public Result> getContractByOrder( + HttpServletRequest request, +@@ -49,7 +49,7 @@ public class MpContractController { + return contractFeignClient.getContractByOrder(orderId, userId); + } + +- @ApiOperation(value = "按订单查所有合同", notes = "返回订单关联的所有有效合同(TOUR+INSURANCE各一条)") ++ @ApiOperation(value = "按订单查所有合同", notes = "返回订单关联的所有有效合同(TOUR+INSURANCE各一条)\n\n**关联字典(BFF透传)**:\n- contract_status:合同状态(显示)") + @GetMapping("/by-order/{orderId}/all") + public Result>> getContractsByOrder( + HttpServletRequest request, +@@ -58,7 +58,8 @@ public class MpContractController { + return contractFeignClient.getContractsByOrder(orderId, userId); + } + +- @ApiOperation("重新发送合同签署短信") ++ @ApiOperation(value = "重新发送合同签署短信", ++ notes = "重新向出行人发送合同签署短信通知,适用于出行人未收到短信或短信过期的场景。\n\n**权限**:需登录。") + @PostMapping("/{contractId}/resend-sms") + public Result resendContractSms( + @ApiParam("合同ID") @PathVariable Long contractId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java +index ae62fb8..01d0115 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDesignerController.java +@@ -22,7 +22,8 @@ public class MpDesignerController { + private final MpUserFeignClient userFeignClient; + private final DesignerAggregationService designerAggregationService; + +- @ApiOperation("定制师列表(含真实产品数和评分,综合排序)") ++ @ApiOperation(value = "定制师列表(含真实产品数和评分,综合排序)", ++ notes = "获取定制师列表,聚合层会补充每个定制师的真实产品数量和评价评分。按综合排序(评分>路线数>咨询人数),用于小程序定制师推荐页。") + @SuppressWarnings("unchecked") + @GetMapping + public Result>> listDesigners( +@@ -37,7 +38,8 @@ public class MpDesignerController { + return result; + } + +- @ApiOperation("推荐定制师(综合排序第一名)") ++ @ApiOperation(value = "推荐定制师(综合排序第一名)", ++ notes = "获取综合排序排名第一的定制师信息(含产品数和评分),用于首页推荐定制师卡片展示。") + @GetMapping("/featured") + public Result> getFeaturedDesigner() { + // Fetch all designers, enrich and sort, return top one +@@ -74,7 +76,8 @@ public class MpDesignerController { + try { return Integer.parseInt(obj.toString()); } catch (NumberFormatException e) { return 0; } + } + +- @ApiOperation("定制师详情(含产品数量和评分)") ++ @ApiOperation(value = "定制师详情(含产品数量和评分)", ++ notes = "获取定制师完整个人信息,聚合层会补充该定制师的已发布产品数量和综合评分,用于定制师个人主页展示。") + @GetMapping("/{id}") + public Result> getDesignerDetail(@ApiParam("定制师ID") @PathVariable Long id) { + Map data = designerAggregationService.getDesignerDetailWithStats(id); +@@ -84,7 +87,7 @@ public class MpDesignerController { + return Result.success(data); + } + +- @ApiOperation("定制师已发布产品列表") ++ @ApiOperation(value = "定制师已发布产品列表", notes = "**关联字典(BFF透传)**:\n- product_type:产品类型(显示)") + @GetMapping("/{id}/products") + public Result>> getDesignerProducts( + @ApiParam("定制师ID") @PathVariable Long id, +@@ -93,7 +96,7 @@ public class MpDesignerController { + return designerAggregationService.getDesignerProducts(id, page, pageSize); + } + +- @ApiOperation("定制师产品评价列表") ++ @ApiOperation(value = "定制师产品评价列表", notes = "**关联字典(BFF透传)**:\n- rating_level:评价等级(显示)") + @GetMapping("/{id}/reviews") + public Result>> getDesignerReviews( + @ApiParam("定制师ID") @PathVariable Long id, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java +index b57cfd7..e689361 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpDictController.java +@@ -23,7 +23,7 @@ public class MpDictController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("获取所有字典数据") ++ @ApiOperation(value = "获取所有字典数据", notes = "获取系统全部字典数据(按字典类型分组),用于小程序端的下拉选项、枚举映射等。建议前端缓存此数据") + @GetMapping("/all") + public Result>> getAllDict() { + return userFeignClient.getAllDict(); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java +index ba1fcaa..5aa4cfc 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpExploreController.java +@@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; + import org.springframework.web.bind.annotation.*; + + import javax.servlet.http.HttpServletRequest; ++import java.util.Map; + + @Api(tags = "C端 - 探索接口") + @RestController +@@ -18,9 +19,10 @@ public class MpExploreController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("探索列表") ++ @ApiOperation(value = "探索列表", ++ notes = "获取已启用的探索分类列表(图文攻略内容),支持综合/最新/最热排序,分页返回。用于小程序探索频道首页瀑布流展示。") + @GetMapping("/list") +- public Result list( ++ public Result> list( + @ApiParam("排序方式:comprehensive/newest/hottest") @RequestParam(defaultValue = "comprehensive") String sortType, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, + @ApiParam("每页条数") @RequestParam(defaultValue = "20") int pageSize) { +@@ -29,7 +31,7 @@ public class MpExploreController { + + @ApiOperation(value = "探索详情", notes = "自动增加浏览量,已登录时返回点赞/收藏状态") + @GetMapping("/{id}") +- public Result detail(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { ++ public Result> detail(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { + // optional auth: userId may be null if not logged in + Long userId = null; + String userIdHeader = request.getHeader("X-User-Id"); +@@ -42,22 +44,25 @@ public class MpExploreController { + return userFeignClient.getExploreCategoryDetail(id, userId); + } + +- @ApiOperation("浏览+1") ++ @ApiOperation(value = "浏览+1", ++ notes = "增加探索内容的浏览计数。前端进入探索详情页时调用,无需登录。") + @PostMapping("/{id}/view") +- public Result view(@ApiParam("探索分类ID") @PathVariable Long id) { ++ public Result view(@ApiParam("探索分类ID") @PathVariable Long id) { + return userFeignClient.incrementExploreViewCount(id); + } + +- @ApiOperation("切换点赞") ++ @ApiOperation(value = "切换点赞", ++ notes = "对探索内容点赞/取消点赞,返回当前点赞状态(true=已点赞)。\n\n**权限**:需登录。") + @PostMapping("/{id}/like") +- public Result toggleLike(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { ++ public Result toggleLike(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.toggleExploreLike(id, userId); + } + +- @ApiOperation("切换收藏") ++ @ApiOperation(value = "切换收藏", ++ notes = "对探索内容收藏/取消收藏,返回当前收藏状态(true=已收藏)。收藏后可在'我的收藏'中查看。\n\n**权限**:需登录。") + @PostMapping("/{id}/favorite") +- public Result toggleFavorite(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { ++ public Result toggleFavorite(@ApiParam("探索分类ID") @PathVariable Long id, HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.toggleExploreFavorite(id, userId); + } +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java +index 94c53e4..d596692 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFavoriteController.java +@@ -27,7 +27,7 @@ public class MpFavoriteController { + private final MpUserFeignClient userFeignClient; + private final FavoriteAggregationService favoriteAggregationService; + +- @ApiOperation("添加收藏") ++ @ApiOperation(value = "添加收藏", notes = "将产品/景区/餐厅/活动加入收藏。同一目标重复收藏会返回已有收藏记录") + @PostMapping + public Result> addFavorite(HttpServletRequest request, + @Valid @RequestBody MpFavoriteRequest body) { +@@ -38,7 +38,8 @@ public class MpFavoriteController { + return userFeignClient.addFavorite(userId, map); + } + +- @ApiOperation("收藏列表(含资源摘要)") ++ @ApiOperation(value = "收藏列表(含资源摘要)", ++ notes = "分页查询收藏列表,聚合层会补充每个收藏项对应资源的摘要信息(名称、封面图、价格等)。支持按目标类型筛选。\n\n**权限**:需登录。\n\n**关联字典**:\n- favorite_resource_type:收藏资源类型(PRODUCT/SCENIC/RESTAURANT/ACTIVITY)") + @GetMapping + public Result> listFavorites(HttpServletRequest request, + @ApiParam("目标类型筛选(字典:favorite_resource_type):PRODUCT/SCENIC/RESTAURANT/ACTIVITY") +@@ -49,7 +50,8 @@ public class MpFavoriteController { + return Result.success(favoriteAggregationService.listFavorites(userId, targetType, page, pageSize)); + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", ++ notes = "检查当前用户是否已收藏指定资源,用于详情页收藏按钮状态显示。\n\n**权限**:需登录。") + @GetMapping("/check") + public Result checkFavorite(HttpServletRequest request, + @ApiParam("目标类型(字典:favorite_resource_type)") @RequestParam String targetType, +@@ -58,7 +60,8 @@ public class MpFavoriteController { + return userFeignClient.checkFavorite(userId, targetType, targetId); + } + +- @ApiOperation("批量删除收藏") ++ @ApiOperation(value = "批量删除收藏", ++ notes = "批量删除多条收藏记录,传入收藏记录ID列表。用于收藏管理页面的批量操作。\n\n**权限**:需登录,仅能删除自己的收藏。") + @DeleteMapping("/batch") + public Result batchDeleteFavorites(HttpServletRequest request, + @ApiParam("收藏ID列表") @RequestBody List ids) { +@@ -66,7 +69,8 @@ public class MpFavoriteController { + return userFeignClient.batchDeleteFavorites(userId, ids); + } + +- @ApiOperation("按目标取消收藏") ++ @ApiOperation(value = "按目标取消收藏", ++ notes = "通过目标类型+目标ID取消收藏,适用于详情页点击取消收藏的场景(不需要知道收藏记录ID)。\n\n**权限**:需登录。") + @DeleteMapping("/by-target") + public Result deleteFavoriteByTarget(HttpServletRequest request, + @ApiParam("目标类型") @RequestParam String targetType, +@@ -75,7 +79,8 @@ public class MpFavoriteController { + return userFeignClient.deleteFavoriteByTarget(userId, targetType, targetId); + } + +- @ApiOperation("取消收藏") ++ @ApiOperation(value = "取消收藏", ++ notes = "通过收藏记录ID取消收藏,适用于收藏列表页的删除操作。\n\n**权限**:需登录,仅能删除自己的收藏。") + @DeleteMapping("/{id}") + public Result deleteFavorite(HttpServletRequest request, + @ApiParam("收藏记录ID") @PathVariable Long id) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java +index c25ed9b..ab02f01 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpFootprintController.java +@@ -26,7 +26,7 @@ public class MpFootprintController { + private final MpUserFeignClient userFeignClient; + private final FootprintAggregationService footprintAggregationService; + +- @ApiOperation("记录足迹") ++ @ApiOperation(value = "记录足迹", notes = "记录用户浏览资源的足迹,同一资源重复浏览会更新浏览时间而非新增记录") + @PostMapping + public Result> addFootprint(HttpServletRequest request, + @RequestBody MpFootprintAddRequest body) { +@@ -37,7 +37,8 @@ public class MpFootprintController { + return userFeignClient.addFootprint(userId, map); + } + +- @ApiOperation("足迹列表(含资源摘要)") ++ @ApiOperation(value = "足迹列表(含资源摘要)", ++ notes = "分页查询浏览足迹列表,聚合层会补充每条足迹对应资源的摘要信息(名称、封面图等)。支持按资源类型筛选,按浏览时间倒序。\n\n**权限**:需登录。") + @GetMapping + public Result> listFootprints(HttpServletRequest request, + @ApiParam("资源类型筛选:PRODUCT/SCENIC/RESTAURANT/ACTIVITY") @RequestParam(required = false) String resourceType, +@@ -47,14 +48,16 @@ public class MpFootprintController { + return Result.success(footprintAggregationService.listFootprints(userId, resourceType, page, pageSize)); + } + +- @ApiOperation("删除足迹") ++ @ApiOperation(value = "删除足迹", ++ notes = "删除单条浏览足迹记录。\n\n**权限**:需登录,仅能删除自己的足迹。") + @DeleteMapping("/{id}") + public Result deleteFootprint(HttpServletRequest request, @ApiParam("足迹ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.deleteFootprint(userId, id); + } + +- @ApiOperation("批量删除足迹") ++ @ApiOperation(value = "批量删除足迹", ++ notes = "批量删除多条浏览足迹记录,传入足迹ID列表。用于足迹管理页面的批量清理。\n\n**权限**:需登录,仅能删除自己的足迹。") + @DeleteMapping("/batch") + public Result batchDeleteFootprints(HttpServletRequest request, + @ApiParam("足迹ID列表") @RequestBody List ids) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java +index 8e7cdc5..0c6487f 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHomeController.java +@@ -18,7 +18,7 @@ public class MpHomeController { + + private final HomeAggregationService homeAggregationService; + +- @ApiOperation(value = "首页数据", notes = "聚合流程:并行获取推荐产品列表+产品线列表+轮播图 → Redis缓存5分钟 → 返回聚合数据") ++ @ApiOperation(value = "首页数据", notes = "聚合流程:并行获取推荐产品列表+产品线列表+轮播图 → Redis缓存5分钟 → 返回聚合数据\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(产品卡片显示)\n- product_status:产品状态(透传自product-service)") + @GetMapping + public Result getHomeData() { + return Result.success(homeAggregationService.getHomeData()); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java +index d820bba..2d649e1 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpHotelController.java +@@ -22,7 +22,8 @@ public class MpHotelController { + private final MpResourceFeignClient resourceFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("酒店列表") ++ @ApiOperation(value = "酒店列表", ++ notes = "分页查询已上架的酒店列表,支持按关键词、城市、星级筛选。聚合层透传resource-service的酒店数据。") + @GetMapping("/list") + public Result>> listHotels( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -39,7 +40,8 @@ public class MpHotelController { + return resourceFeignClient.listHotels(query); + } + +- @ApiOperation("酒店详情") ++ @ApiOperation(value = "酒店详情", ++ notes = "获取酒店完整信息(含房型列表、图文详情、价格等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{hotelId}") + public Result> getHotelDetail(@ApiParam("酒店ID") @PathVariable Long hotelId) { + Result> result = resourceFeignClient.getHotelDetail(hotelId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java +index 3941bc4..d1403a0 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInsuranceController.java +@@ -18,7 +18,7 @@ public class MpInsuranceController { + + private final MpInsuranceFeignClient insuranceFeignClient; + +- @ApiOperation(value = "获取订单所有保单PDF", notes = "合并所有出行人的有效保单为一个PDF,返回base64") ++ @ApiOperation(value = "获取订单所有保单PDF", notes = "合并所有出行人的有效保单为一个PDF,返回base64\n\n**关联字典(BFF透传)**:\n- insurance_status:保险状态(返回字段)") + @GetMapping("/policy-pdf/{orderId}") + public Result> getPolicyPdf( + @ApiParam("订单ID") @PathVariable Long orderId) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java +index bda90ad..a42a662 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpInvoiceController.java +@@ -31,7 +31,7 @@ public class MpInvoiceController { + return orderFeignClient.applyInvoice(userId, body); + } + +- @ApiOperation("发票详情") ++ @ApiOperation(value = "发票详情", notes = "获取发票的完整信息,包含开票状态、发票抬头、税号、金额、电子发票文件链接等") + @GetMapping("/{id}") + public Result> getInvoiceDetail(@ApiParam("发票ID") @PathVariable Long id, + HttpServletRequest request) { +@@ -39,7 +39,7 @@ public class MpInvoiceController { + return orderFeignClient.getInvoiceDetail(id, userId); + } + +- @ApiOperation("通过订单ID查询发票") ++ @ApiOperation(value = "通过订单ID查询发票", notes = "查询指定订单的发票信息,如果订单未开票则返回null") + @GetMapping("/order/{orderId}") + public Result> getInvoiceByOrderId(@ApiParam("订单ID") @PathVariable Long orderId, + HttpServletRequest request) { +@@ -47,7 +47,7 @@ public class MpInvoiceController { + return orderFeignClient.getInvoiceByOrderId(orderId, userId); + } + +- @ApiOperation("发票换开") ++ @ApiOperation(value = "发票换开", notes = "对已开发票申请换开(修改抬头/税号等),原发票作废后重新开具新发票") + @PostMapping("/{invoiceId}/reissue") + public Result> reissueInvoice( + @ApiParam("发票ID") @PathVariable Long invoiceId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java +index d60be9e..c8d50b5 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpLikeController.java +@@ -57,7 +57,8 @@ public class MpLikeController { + return result; + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "检查当前用户是否已对指定目标点赞,用于前端点赞按钮状态展示。\n\n**权限**:需登录。") + @GetMapping("/{targetType}/{targetId}/check") + public Result checkLike( + @ApiParam("目标类型") @PathVariable String targetType, +@@ -67,7 +68,8 @@ public class MpLikeController { + return userFeignClient.checkLikeStatus(targetType.toUpperCase(), targetId, userId); + } + +- @ApiOperation("批量检查点赞状态") ++ @ApiOperation(value = "批量检查点赞状态", ++ notes = "批量检查当前用户是否已对多个目标点赞,返回已点赞的目标ID列表。用于列表页批量展示点赞状态。\n\n**权限**:需登录。") + @PostMapping("/{targetType}/batch-check") + public Result> batchCheckLiked( + @ApiParam("目标类型") @PathVariable String targetType, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java +index bc4abe0..e1f7fa6 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpOrderController.java +@@ -37,7 +37,7 @@ public class MpOrderController { + return orderFeignClient.createOrder(userId, body); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "分页查询当前用户的订单列表,支持按状态筛选。返回订单摘要信息(不含详细出行人信息)\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(列表筛选+显示)\n- product_type:产品类型(订单卡片显示)") + @GetMapping("/list") + public Result> listOrders(HttpServletRequest request, + @ApiParam("状态") @RequestParam(required = false) String status, +@@ -51,7 +51,7 @@ public class MpOrderController { + return orderFeignClient.listOrders(userId, query); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "获取订单完整信息,包含产品快照、出行人列表、支付信息、合同状态等\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(显示)\n- product_type:产品类型(显示)\n- contract_status:合同状态(显示)") + @GetMapping("/{orderId}") + public Result getOrder(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -86,9 +86,10 @@ public class MpOrderController { + return orderFeignClient.cancelOrder(userId, orderId, body != null ? body : new MpCancelOrderRequest()); + } + +- @ApiOperation("通过联系人手机号+姓名查找订单(无需登录)") ++ @ApiOperation(value = "通过联系人手机号+姓名查找订单(无需登录)", ++ notes = "无需登录即可查询。用于管理员代下单场景:管理员创建订单后,用户通过联系人手机号+姓名查找订单并绑定到自己账号。仅返回尚未绑定用户(userId=NULL)的订单。") + @GetMapping("/lookup") +- public Result lookupByContact(@ApiParam("联系人手机号") @RequestParam String contactPhone, ++ public Result>> lookupByContact(@ApiParam("联系人手机号") @RequestParam String contactPhone, + @ApiParam("联系人姓名") @RequestParam String contactName) { + return orderFeignClient.lookupByContact(contactPhone, contactName); + } +@@ -101,7 +102,7 @@ public class MpOrderController { + return orderFeignClient.bindByContact(userId, body); + } + +- @ApiOperation("同意解锁订单") ++ @ApiOperation(value = "同意解锁订单", notes = "用户同意管理员的修改请求,解除订单锁定状态,允许管理员继续修改订单") + @PostMapping("/{orderId}/approve-unlock") + public Result approveUnlock(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -116,7 +117,7 @@ public class MpOrderController { + return orderFeignClient.getUpcomingDepartures(userId); + } + +- @ApiOperation("各状态订单数量") ++ @ApiOperation(value = "各状态订单数量", notes = "统计当前用户各状态的订单数量,用于「我的」页面的订单状态角标展示\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(状态分类统计)") + @GetMapping("/count") + public Result> countByStatus(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java +index 6ddf62a..274102d 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpPaymentController.java +@@ -21,7 +21,7 @@ public class MpPaymentController { + private final MpPaymentFeignClient paymentFeignClient; + + @PostMapping("/prepay") +- @ApiOperation(value = "发起支付", notes = "支付流程:选择支付方式(JSAPI/H5) → 调用微信支付API → 返回支付参数 → 前端调起微信支付") ++ @ApiOperation(value = "发起支付", notes = "支付流程:选择支付方式(JSAPI/H5) → 调用微信支付API → 返回支付参数 → 前端调起微信支付\n\n**关联字典(BFF透传)**:\n- payment_status:支付状态(返回字段)") + public Result> prepay( + HttpServletRequest httpRequest, + @ApiParam("支付请求体") @RequestBody MpPaymentPrepayRequest request) { +@@ -30,7 +30,7 @@ public class MpPaymentController { + } + + @GetMapping("/status/{orderId}") +- @ApiOperation("查询支付状态") ++ @ApiOperation(value = "查询支付状态", notes = "**关联字典(BFF透传)**:\n- payment_status:支付状态(显示)") + public Result> getStatus(@ApiParam("订单ID") @PathVariable Long orderId, + HttpServletRequest httpRequest) { + Long userId = (Long) httpRequest.getAttribute("userId"); +@@ -38,8 +38,8 @@ public class MpPaymentController { + } + + @GetMapping("/transactions/{orderId}") +- @ApiOperation("订单交易记录列表") +- public Result listTransactions(@ApiParam("订单ID") @PathVariable Long orderId, ++ @ApiOperation(value = "订单交易记录列表", notes = "**关联字典(BFF透传)**:\n- payment_status:支付状态(显示)") ++ public Result>> listTransactions(@ApiParam("订单ID") @PathVariable Long orderId, + HttpServletRequest httpRequest) { + Long userId = (Long) httpRequest.getAttribute("userId"); + return paymentFeignClient.listTransactions(userId, orderId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java +index 6aa9542..1aa236f 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpProductController.java +@@ -34,7 +34,7 @@ public class MpProductController { + private final MpOrderFeignClient orderFeignClient; + private final ProductAggregationService productAggregationService; + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", notes = "分页查询已上架产品,支持按关键词、产品类型(CORE/ROUTE/CUSTOM/GROUP)、季节、天数、目的地、产品线筛选和排序\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(列表筛选+显示)\n- product_status:产品状态(透传自product-service)") + @GetMapping("/list") + public Result>> listProducts( + @ApiParam("搜索关键词") @RequestParam(required = false) String keyword, +@@ -63,7 +63,7 @@ public class MpProductController { + return productFeignClient.listProducts(query); + } + +- @ApiOperation(value = "产品详情(聚合收藏状态)", notes = "聚合流程:获取产品详情 → 并行查询收藏状态 → 异步记录足迹 → 返回聚合数据。支持未登录访问(不返回收藏状态)") ++ @ApiOperation(value = "产品详情(聚合收藏状态)", notes = "聚合流程:获取产品详情 → 并行查询收藏状态 → 异步记录足迹 → 返回聚合数据。支持未登录访问(不返回收藏状态)\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(显示)\n- product_status:产品状态(透传自product-service)") + @GetMapping("/{productId}") + public Result getProduct(HttpServletRequest request, + @ApiParam("产品ID") @PathVariable Long productId) { +@@ -256,7 +256,7 @@ public class MpProductController { + } + } + +- @ApiOperation("产品线列表") ++ @ApiOperation(value = "产品线列表", notes = "返回所有已启用的产品线,用于小程序首页或筛选栏展示") + @GetMapping("/lines") + public Result>> listLines() { + return productFeignClient.listActiveLines(); +@@ -284,7 +284,7 @@ public class MpProductController { + return productFeignClient.listBatchCombos(batchId); + } + +- @ApiOperation("价格日历") ++ @ApiOperation(value = "价格日历", notes = "返回产品指定日期范围内的每日价格,用于日历组件展示。不传日期时默认返回未来一个月") + @GetMapping("/{productId}/price-calendar") + public Result>> getPriceCalendar( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java +index 5a72099..71890d6 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRefundController.java +@@ -32,7 +32,7 @@ public class MpRefundController { + return orderFeignClient.refundPreview(userId, orderId); + } + +- @ApiOperation("退款原因列表") ++ @ApiOperation(value = "退款原因列表", notes = "返回系统预设的退款原因选项,用于退款申请页面的原因选择") + @GetMapping("/refund-reasons") + public Result> listRefundReasons() { + return orderFeignClient.listRefundReasons(); +@@ -48,7 +48,7 @@ public class MpRefundController { + return orderFeignClient.applyRefund(userId, userName, orderId, body); + } + +- @ApiOperation("退款申请详情") ++ @ApiOperation(value = "退款申请详情", notes = "获取退款申请的完整信息,包含审核状态、退款金额、退款进度和操作记录\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(显示)\n- payment_status:支付/退款状态(显示)") + @GetMapping("/refund/{applicationId}") + public Result getRefundDetail(@ApiParam("退款申请ID") @PathVariable Long applicationId, + HttpServletRequest request) { +@@ -56,7 +56,7 @@ public class MpRefundController { + return orderFeignClient.getRefundDetail(userId, applicationId); + } + +- @ApiOperation("根据订单ID获取最新退款详情") ++ @ApiOperation(value = "根据订单ID获取最新退款详情", notes = "查询订单关联的最新一条退款申请详情,无退款记录时返回null\n\n**关联字典(BFF透传)**:\n- order_status:订单状态(显示)\n- payment_status:支付/退款状态(显示)") + @GetMapping("/{orderId}/refund-detail") + public Result getRefundDetailByOrder(@ApiParam("订单ID") @PathVariable String orderId, + HttpServletRequest request) { +@@ -84,7 +84,7 @@ public class MpRefundController { + return orderFeignClient.refundAppeal(userId, applicationId, body); + } + +- @ApiOperation("撤回退款申请") ++ @ApiOperation(value = "撤回退款申请", notes = "仅PENDING状态的退款申请可撤回,撤回后订单恢复到原状态") + @PostMapping("/refund/{applicationId}/cancel") + public Result cancelRefund(@ApiParam("退款申请ID") @PathVariable Long applicationId, + HttpServletRequest request) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java +index 4b75e9b..38fa21b 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpRestaurantController.java +@@ -22,7 +22,8 @@ public class MpRestaurantController { + private final MpResourceFeignClient resourceFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("餐厅列表") ++ @ApiOperation(value = "餐厅列表", ++ notes = "分页查询已上架的餐厅列表,支持按关键词和城市筛选。聚合层透传resource-service的餐厅数据。") + @GetMapping("/list") + public Result>> listRestaurants( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -37,7 +38,8 @@ public class MpRestaurantController { + return resourceFeignClient.listRestaurants(query); + } + +- @ApiOperation("餐厅详情") ++ @ApiOperation(value = "餐厅详情", ++ notes = "获取餐厅完整信息(含菜品、图文详情等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{restaurantId}") + public Result> getRestaurantDetail(@ApiParam("餐厅ID") @PathVariable Long restaurantId) { + Result> result = resourceFeignClient.getRestaurantDetail(restaurantId); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java +index 1f44df4..1cf55b2 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpReviewController.java +@@ -55,7 +55,7 @@ public class MpReviewController { + return Result.success(categories); + } + +- @ApiOperation(value = "创建评价", notes = "评价流程:订单完成后 → 查询可评价目标列表 → 对每个目标(酒店/景区/活动等)提交评价 → 自动内容审核 → 审核通过后公开展示") ++ @ApiOperation(value = "创建评价", notes = "评价流程:订单完成后 → 查询可评价目标列表 → 对每个目标(酒店/景区/活动等)提交评价 → 自动内容审核 → 审核通过后公开展示\n\n**关联字典(BFF透传)**:\n- review_status:评价审核状态(返回字段)\n- rating_level:评价等级(返回字段)") + @PostMapping("/create") + public Result> createReview(@ApiParam("评价请求体") @RequestBody MpReviewCreateRequest body, + HttpServletRequest request) { +@@ -65,7 +65,7 @@ public class MpReviewController { + return reviewFeignClient.createReview(body, userId); + } + +- @ApiOperation("我的评价列表") ++ @ApiOperation(value = "我的评价列表", notes = "**关联字典(BFF透传)**:\n- review_status:评价审核状态(显示)\n- rating_level:评价等级(显示)") + @GetMapping("/my") + public Result>> getMyReviews( + @ApiParam("页码") @RequestParam(defaultValue = "1") Integer page, +@@ -75,7 +75,7 @@ public class MpReviewController { + return reviewFeignClient.getMyReviews(page, pageSize, userId); + } + +- @ApiOperation(value = "关键词搜索评价(公开)", notes = "按关键词搜索已通过的评价内容,支持按目标类型和目标ID筛选") ++ @ApiOperation(value = "关键词搜索评价(公开)", notes = "按关键词搜索已通过的评价内容,支持按目标类型和目标ID筛选\n\n**关联字典(BFF透传)**:\n- rating_level:评价等级(显示)") + @GetMapping("/search") + public Result>> searchReviews( + @ApiParam(value = "搜索关键词", required = true) @RequestParam String keyword, +@@ -86,7 +86,7 @@ public class MpReviewController { + return reviewFeignClient.searchReviews(keyword, targetType, targetId, page, pageSize); + } + +- @ApiOperation("某目标的已通过评价(公开)") ++ @ApiOperation(value = "某目标的已通过评价(公开)", notes = "**关联字典(BFF透传)**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/target") + public Result>> getTargetReviews( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -102,7 +102,7 @@ public class MpReviewController { + return reviewFeignClient.getTargetReviews(targetType, targetId, ratingLevel, hasImage, hasVideo, page, pageSize); + } + +- @ApiOperation(value = "按产品ID查看评价列表", notes = "返回评价列表+统计数据,支持好中差评/有图/有视频筛选") ++ @ApiOperation(value = "按产品ID查看评价列表", notes = "返回评价列表+统计数据,支持好中差评/有图/有视频筛选\n\n**关联字典(BFF透传)**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/product/{productId}") + public Result> getProductReviews( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -144,7 +144,8 @@ public class MpReviewController { + return reviewFeignClient.getProductHighlights(productId); + } + +- @ApiOperation("评价统计(平均分、数量)") ++ @ApiOperation(value = "评价统计(平均分、数量)", ++ notes = "获取指定目标的评价统计数据(平均评分、总评价数等),用于详情页评价区域展示。产品showReview关闭时返回空统计。") + @GetMapping("/stats") + public Result> getTargetStats( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -174,21 +175,23 @@ public class MpReviewController { + return true; // 查询失败时默认显示 + } + +- @ApiOperation(value = "精选评价列表(公开)", notes = "无需登录,返回精选评价数组,用于评价浏览页") ++ @ApiOperation(value = "精选评价列表(公开)", notes = "无需登录,返回精选评价数组,用于评价浏览页\n\n**关联字典(BFF透传)**:\n- rating_level:评价等级(显示)") + @GetMapping("/featured") + public Result>> getFeaturedReviews( + @ApiParam("数量限制") @RequestParam(defaultValue = "50") Integer limit) { + return reviewFeignClient.getFeaturedReviews(limit); + } + +- @ApiOperation("检查订单是否已评价") ++ @ApiOperation(value = "检查订单是否已评价", ++ notes = "检查指定订单是否已提交评价,用于订单详情页决定是否显示'去评价'按钮。") + @GetMapping("/order/{orderId}/reviewed") + public Result isOrderReviewed( + @ApiParam("订单ID") @PathVariable Long orderId) { + return reviewFeignClient.isOrderReviewed(orderId); + } + +- @ApiOperation("订单可评价目标列表") ++ @ApiOperation(value = "订单可评价目标列表", ++ notes = "返回订单中可评价的资源目标列表(景区/酒店/活动等),用于评价页面展示可评价项。已评价的目标不会重复出现。\n\n**权限**:需登录。") + @GetMapping("/order/{orderId}/reviewable-targets") + public Result>> getReviewableTargets( + @ApiParam("订单ID") @PathVariable Long orderId, HttpServletRequest request) { +@@ -196,7 +199,8 @@ public class MpReviewController { + return reviewFeignClient.getReviewableTargets(orderId, userId); + } + +- @ApiOperation("点赞/取消点赞评价") ++ @ApiOperation(value = "点赞/取消点赞评价", ++ notes = "对评价进行点赞或取消点赞操作,返回当前点赞状态和点赞总数。\n\n**权限**:需登录。") + @PostMapping("/{reviewId}/like") + public Result> toggleLike( + @ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { +@@ -204,7 +208,8 @@ public class MpReviewController { + return reviewFeignClient.toggleLike(reviewId, userId); + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "检查当前用户是否已点赞指定评价,用于评价列表/详情的点赞按钮状态展示。\n\n**权限**:需登录。") + @GetMapping("/{reviewId}/like/check") + public Result checkLiked( + @ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java +index 96a4529..8f59647 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpScenicController.java +@@ -27,7 +27,8 @@ public class MpScenicController { + private final MpUserFeignClient userFeignClient; + private final ResourceMapService resourceMapService; + +- @ApiOperation("景区列表") ++ @ApiOperation(value = "景区列表", ++ notes = "分页查询已上架的景区列表,支持按关键词和城市筛选。聚合层透传resource-service的景区数据。") + @GetMapping("/list") + public Result>> listScenic( + @ApiParam("关键词") @RequestParam(required = false) String keyword, +@@ -42,7 +43,8 @@ public class MpScenicController { + return resourceFeignClient.listScenic(query); + } + +- @ApiOperation("景区详情") ++ @ApiOperation(value = "景区详情", ++ notes = "获取景区完整信息(含季节素材、图文详情、价格等),自动注入静态地图图片URL用于详情页地图展示。") + @GetMapping("/{scenicId}") + public Result> getScenicDetail(@ApiParam("景区ID") @PathVariable Long scenicId) { + Result> result = resourceFeignClient.getScenicDetail(scenicId); +@@ -52,7 +54,8 @@ public class MpScenicController { + return result; + } + +- @ApiOperation("附近景区(地理+探索分类聚合)") ++ @ApiOperation(value = "附近景区(地理+探索分类聚合)", ++ notes = "聚合两个数据源:1.基于经纬度的地理位置附近景区(resource-service);2.探索分类关联的景区(user-service)。去重合并后返回,用于景区详情页底部'附近推荐'展示。") + @GetMapping("/{scenicId}/nearby") + public Result>> getNearbyScenic( + @ApiParam("景区ID") @PathVariable Long scenicId, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java +index 7a2362a..689c544 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpSearchController.java +@@ -20,7 +20,7 @@ public class MpSearchController { + + private final MpProductFeignClient productFeignClient; + +- @ApiOperation("搜索产品") ++ @ApiOperation(value = "搜索产品", notes = "按关键词搜索已上架产品(匹配产品名称和描述),支持按产品类型进一步筛选\n\n**关联字典(BFF透传)**:\n- product_type:产品类型(筛选+显示)") + @GetMapping + public Result>> search( + @ApiParam("搜索关键词") @RequestParam String keyword, +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java +index 8831fd0..4f8f4d9 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTravelerController.java +@@ -22,7 +22,7 @@ public class MpTravelerController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("添加出行人") ++ @ApiOperation(value = "添加出行人", notes = "添加常用出行人信息(姓名/证件/联系方式等),下单时可快速选择。单个用户最多50个出行人") + @PostMapping + public Result> addTraveler(HttpServletRequest request, + @RequestBody MpTravelerRequest body) { +@@ -31,21 +31,23 @@ public class MpTravelerController { + return userFeignClient.addTraveler(userId, map); + } + +- @ApiOperation("出行人列表") ++ @ApiOperation(value = "出行人列表", notes = "返回当前用户的所有出行人列表。如果用户已完善实名信息,列表中会自动包含一条「本人」虚拟记录(travelerId=0)") + @GetMapping + public Result>> listTravelers(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.listTravelers(userId); + } + +- @ApiOperation("出行人详情") ++ @ApiOperation(value = "出行人详情", ++ notes = "获取单个出行人的完整信息(姓名、证件信息、联系方式等)。\n\n**权限**:需登录,仅能查看自己的出行人。") + @GetMapping("/{id}") + public Result> getTraveler(HttpServletRequest request, @ApiParam("出行人ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.getTraveler(userId, id); + } + +- @ApiOperation("更新出行人") ++ @ApiOperation(value = "更新出行人", ++ notes = "修改出行人信息,支持部分更新(只传需要修改的字段)。已关联订单的出行人修改不影响历史订单记录。\n\n**权限**:需登录。") + @PutMapping("/{id}") + public Result> updateTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long id, +@@ -55,14 +57,15 @@ public class MpTravelerController { + return userFeignClient.updateTraveler(userId, id, map); + } + +- @ApiOperation("删除出行人") ++ @ApiOperation(value = "删除出行人", ++ notes = "删除常用出行人记录。默认出行人不可删除,需先取消默认后再删除。\n\n**权限**:需登录。") + @DeleteMapping("/{id}") + public Result deleteTraveler(HttpServletRequest request, @ApiParam("出行人ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.deleteTraveler(userId, id); + } + +- @ApiOperation("设为默认出行人") ++ @ApiOperation(value = "设为默认出行人", notes = "设为默认出行人后,下单时自动作为第一个出行人。每个用户只能有一个默认出行人") + @PutMapping("/{id}/default") + public Result setDefaultTraveler(HttpServletRequest request, @ApiParam("出行人ID") @PathVariable Long id) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java +index 5247c6f..9870345 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpTripController.java +@@ -22,14 +22,14 @@ public class MpTripController { + private final MpOrderFeignClient orderFeignClient; + private final WeatherService weatherService; + +- @ApiOperation(value = "行程列表", notes = "获取当前登录用户的行程列表(已确认及进行中的订单对应的行程)") ++ @ApiOperation(value = "行程列表", notes = "获取当前登录用户的行程列表(已确认及进行中的订单对应的行程)\n\n**关联字典(BFF透传)**:\n- order_status:订单/行程状态(显示)") + @GetMapping("/list") + public Result>> getTripList(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return orderFeignClient.getTripList(userId); + } + +- @ApiOperation(value = "行程详情", notes = "获取订单对应的行程详情,含每日行程节点信息(景点/酒店/餐厅等)") ++ @ApiOperation(value = "行程详情", notes = "获取订单对应的行程详情,含每日行程节点信息(景点/酒店/餐厅等)\n\n**关联字典(BFF透传)**:\n- order_status:订单/行程状态(显示)") + @GetMapping("/{orderId}") + public Result> getTripDetail(HttpServletRequest request, + @ApiParam(value = "订单ID", required = true) @PathVariable Long orderId) { +@@ -37,7 +37,7 @@ public class MpTripController { + return orderFeignClient.getTripDetail(userId, orderId); + } + +- @ApiOperation(value = "今日行程", notes = "获取今日行程(如果有正在进行中的行程),无行程时data为null") ++ @ApiOperation(value = "今日行程", notes = "获取今日行程(如果有正在进行中的行程),无行程时data为null\n\n**关联字典(BFF透传)**:\n- order_status:订单/行程状态(显示)") + @GetMapping("/today") + public Result> getTodayTrip(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java +index 26146f8..249591a 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpUserController.java +@@ -20,7 +20,7 @@ public class MpUserController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("发送短信验证码") ++ @ApiOperation(value = "发送短信验证码", notes = "向指定手机号发送登录验证码,有效期5分钟,60秒内不可重复发送") + @PostMapping("/sms/send") + public Result sendSmsCode(@RequestBody MpSmsSendRequest request) { + Map map = new java.util.HashMap<>(); +@@ -45,14 +45,14 @@ public class MpUserController { + return userFeignClient.login(map); + } + +- @ApiOperation("获取用户信息") ++ @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的个人资料,包含头像、昵称、手机号、实名信息等") + @GetMapping("/profile") + public Result> getProfile(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.getProfile(userId); + } + +- @ApiOperation("更新用户信息") ++ @ApiOperation(value = "更新用户信息", notes = "更新当前用户的个人资料,支持部分更新(只传需要修改的字段)。首次完善资料时realName为必填") + @PutMapping("/profile") + public Result> updateProfile(HttpServletRequest request, + @RequestBody MpUserProfileUpdateRequest body) { +@@ -69,7 +69,8 @@ public class MpUserController { + return userFeignClient.updateProfile(userId, map); + } + +- @ApiOperation("用户登出") ++ @ApiOperation(value = "用户登出", ++ notes = "清除用户登录状态和服务端缓存的令牌信息。登出后需重新登录获取新令牌。\n\n**权限**:需登录。") + @PostMapping("/logout") + public Result logout(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java +index 9341450..592fba5 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWeatherController.java +@@ -19,21 +19,21 @@ public class MpWeatherController { + + private final MpOrderFeignClient orderFeignClient; + +- @ApiOperation("获取订单行程天气") ++ @ApiOperation(value = "获取订单行程天气", notes = "根据订单行程中的目的地城市,批量查询每日天气信息,用于行程详情页展示") + @GetMapping("/itinerary/{orderId}") + public Result>> getItineraryWeather( + @ApiParam("订单ID") @PathVariable Long orderId) { + return orderFeignClient.getItineraryWeather(orderId); + } + +- @ApiOperation("获取指定城市实况天气") ++ @ApiOperation(value = "获取指定城市实况天气", notes = "通过高德天气API查询指定城市的实时天气(温度、湿度、风向等)") + @GetMapping("/live") + public Result> getLiveWeather( + @ApiParam("城市名称") @RequestParam String city) { + return orderFeignClient.getLiveWeather(city); + } + +- @ApiOperation("获取指定城市天气预报") ++ @ApiOperation(value = "获取指定城市天气预报", notes = "通过高德天气API查询指定城市未来3天的天气预报信息") + @GetMapping("/forecast") + public Result> getForecastWeather( + @ApiParam("城市名称") @RequestParam String city) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java +index 26fe4ac..c70bd36 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWikiController.java +@@ -20,13 +20,15 @@ public class MpWikiController { + + private final MpWikiFeignClient wikiFeignClient; + +- @ApiOperation("攻略分类列表") ++ @ApiOperation(value = "攻略分类列表", ++ notes = "获取所有已启用的攻略分类,按排序值排列。用于小程序攻略频道的分类导航展示。") + @GetMapping("/categories") + public Result>> listCategories() { + return wikiFeignClient.listEnabledCategories(); + } + +- @ApiOperation("分类文章列表") ++ @ApiOperation(value = "分类文章列表", ++ notes = "分页查询指定攻略分类下已发布的文章列表,按发布时间倒序排列。用于攻略分类详情页。") + @GetMapping("/category/{categoryId}/articles") + public Result>> listCategoryArticles( + @ApiParam("攻略分类ID") @PathVariable Long categoryId, +@@ -35,13 +37,14 @@ public class MpWikiController { + return wikiFeignClient.listCategoryArticles(categoryId, page, pageSize); + } + +- @ApiOperation("文章详情") ++ @ApiOperation(value = "文章详情", notes = "**关联字典(BFF透传)**:\n- wiki_status:文章状态(返回字段)") + @GetMapping("/article/{articleId}") + public Result> getArticle(@ApiParam("文章ID") @PathVariable Long articleId) { + return wikiFeignClient.getArticle(articleId); + } + +- @ApiOperation("推荐文章列表") ++ @ApiOperation(value = "推荐文章列表", ++ notes = "获取编辑推荐的攻略文章列表(按推荐权重排序),用于首页或攻略频道的推荐位展示。") + @GetMapping("/recommend-articles") + public Result>> listRecommendArticles( + @ApiParam("返回条数") @RequestParam(defaultValue = "10") Integer limit) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java +index f9abab8..d9d2416 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/controller/MpWishController.java +@@ -21,14 +21,14 @@ public class MpWishController { + + private final MpUserFeignClient userFeignClient; + +- @ApiOperation("心愿单列表") ++ @ApiOperation(value = "心愿单列表", notes = "返回当前用户的心愿单列表,按创建时间倒序排列") + @GetMapping + public Result>> listWishes(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); + return userFeignClient.listWishes(userId); + } + +- @ApiOperation("创建心愿") ++ @ApiOperation(value = "创建心愿", notes = "创建旅行心愿,描述想去的地方和时间偏好,定制师可据此推荐产品") + @PostMapping + public Result> createWish(@ApiParam("心愿请求体") @RequestBody MpWishCreateRequest body, + HttpServletRequest request) { +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignClient.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignClient.java b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignClient.java +index b722dd7..d30f577 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignClient.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignClient.java +@@ -19,6 +19,6 @@ public interface MpPaymentFeignClient { + @PathVariable("orderId") Long orderId); + + @GetMapping("/internal/payment/transactions/{orderId}") +- Result listTransactions(@RequestParam("userId") Long userId, ++ Result>> listTransactions(@RequestParam("userId") Long userId, + @PathVariable("orderId") Long orderId); + } +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignFallbackFactory.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignFallbackFactory.java b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignFallbackFactory.java +index 48fc044..28c303b 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignFallbackFactory.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpPaymentFeignFallbackFactory.java +@@ -27,7 +27,7 @@ public class MpPaymentFeignFallbackFactory implements FallbackFactory listTransactions(Long userId, Long orderId) { ++ public Result>> listTransactions(Long userId, Long orderId) { + return Result.error("支付服务不可用,请稍后重试"); + } + }; +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignClient.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignClient.java b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignClient.java +index 3ccc5b3..9927e9a 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignClient.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignClient.java +@@ -189,36 +189,36 @@ public interface MpUserFeignClient { + // ==================== Explore ==================== + + @GetMapping("/internal/mp/explore/active") +- Result listActiveExploreCategories( ++ Result> listActiveExploreCategories( + @RequestParam(defaultValue = "comprehensive") String sortType, + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "20") int pageSize); + + @GetMapping("/internal/mp/explore/{id}") +- Result getExploreCategoryDetail( ++ Result> getExploreCategoryDetail( + @PathVariable("id") Long id, + @RequestHeader(value = "X-User-Id", required = false) Long userId); + + @PostMapping("/internal/mp/explore/{id}/view") +- Result incrementExploreViewCount(@PathVariable("id") Long id); ++ Result incrementExploreViewCount(@PathVariable("id") Long id); + + @PostMapping("/internal/mp/explore/{id}/like") +- Result toggleExploreLike( ++ Result toggleExploreLike( + @PathVariable("id") Long id, + @RequestHeader("X-User-Id") Long userId); + + @GetMapping("/internal/mp/explore/{id}/like/check") +- Result checkExploreLike( ++ Result checkExploreLike( + @PathVariable("id") Long id, + @RequestHeader("X-User-Id") Long userId); + + @PostMapping("/internal/mp/explore/{id}/favorite") +- Result toggleExploreFavorite( ++ Result toggleExploreFavorite( + @PathVariable("id") Long id, + @RequestHeader("X-User-Id") Long userId); + + @GetMapping("/internal/mp/explore/{id}/favorite/check") +- Result checkExploreFavorite( ++ Result checkExploreFavorite( + @PathVariable("id") Long id, + @RequestHeader("X-User-Id") Long userId); + +``` + +### `hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignFallbackFactory.java` (M) + +```diff +diff --git a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignFallbackFactory.java b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignFallbackFactory.java +index c9b9a72..517c974 100644 +--- a/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignFallbackFactory.java ++++ b/hl-mp-service/src/main/java/com/hulalv/mp/feign/MpUserFeignFallbackFactory.java +@@ -215,37 +215,37 @@ public class MpUserFeignFallbackFactory implements FallbackFactory listActiveExploreCategories(String sortType, int page, int pageSize) { ++ public Result> listActiveExploreCategories(String sortType, int page, int pageSize) { + return Result.error("用户服务不可用,请稍后重试"); + } + + @Override +- public Result getExploreCategoryDetail(Long id, Long userId) { ++ public Result> getExploreCategoryDetail(Long id, Long userId) { + return Result.error("用户服务不可用,请稍后重试"); + } + + @Override +- public Result incrementExploreViewCount(Long id) { ++ public Result incrementExploreViewCount(Long id) { + return Result.error("用户服务不可用,请稍后重试"); + } + + @Override +- public Result toggleExploreLike(Long id, Long userId) { ++ public Result toggleExploreLike(Long id, Long userId) { + return Result.error("用户服务不可用,请稍后重试"); + } + + @Override +- public Result checkExploreLike(Long id, Long userId) { ++ public Result checkExploreLike(Long id, Long userId) { + return Result.error("用户服务不可用,请稍后重试"); + } + + @Override +- public Result toggleExploreFavorite(Long id, Long userId) { ++ public Result toggleExploreFavorite(Long id, Long userId) { + return Result.error("用户服务不可用,请稍后重试"); + } + + @Override +- public Result checkExploreFavorite(Long id, Long userId) { ++ public Result checkExploreFavorite(Long id, Long userId) { + return Result.error("用户服务不可用,请稍后重试"); + } + +``` + +### `hl-order-service/src/main/java/com/hulalv/order/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/config/Knife4jConfig.java b/hl-order-service/src/main/java/com/hulalv/order/config/Knife4jConfig.java +index 6e9ee90..1e90666 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/config/Knife4jConfig.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/config/Knife4jConfig.java +@@ -39,17 +39,6 @@ public class Knife4jConfig { + .build(); + } + +- @Bean +- public Docket internalApi() { +- return new Docket(DocumentationType.SWAGGER_2) +- .groupName("3.3 内部接口(Feign)") +- .apiInfo(apiInfo()) +- .select() +- .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE)) +- .paths(PathSelectors.ant("/internal/**")) +- .build(); +- } +- + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("呼籁旅行 - 订单服务 API") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java +index 9b8e419..dce7686 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminAlbumController.java +@@ -28,7 +28,7 @@ public class AdminAlbumController { + + // ==================== 文件夹管理 ==================== + +- @ApiOperation("创建相册文件夹") ++ @ApiOperation(value = "创建相册文件夹", notes = "为订单创建旅行相册文件夹(如'第一天风景'、'合影'等),用于组织旅途照片/视频") + @PostMapping("/{orderId}/album/folder") + public Result createFolder( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -38,7 +38,7 @@ public class AdminAlbumController { + return Result.success(albumService.createFolder(orderId, request, adminId)); + } + +- @ApiOperation("编辑相册文件夹") ++ @ApiOperation(value = "编辑相册文件夹", notes = "修改文件夹名称或描述。仅创建者或超级管理员可操作") + @PutMapping("/album/folder/{folderId}") + public Result updateFolder( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -49,7 +49,7 @@ public class AdminAlbumController { + return Result.success(albumService.updateFolder(folderId, request, adminId, roleKey)); + } + +- @ApiOperation("删除相册文件夹") ++ @ApiOperation(value = "删除相册文件夹", notes = "删除文件夹及其下所有文件。仅创建者或超级管理员可操作。删除后C端用户不再可见") + @DeleteMapping("/album/folder/{folderId}") + public Result deleteFolder( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -60,7 +60,8 @@ public class AdminAlbumController { + return Result.success(null); + } + +- @ApiOperation("查询订单的文件夹列表") ++ @ApiOperation(value = "查询订单的文件夹列表", ++ notes = "获取指定订单的所有相册文件夹,含文件夹名称、描述、封面图、文件数量等信息。") + @GetMapping("/{orderId}/album/folders") + public Result> listFolders( + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -69,7 +70,11 @@ public class AdminAlbumController { + + // ==================== 文件管理 ==================== + +- @ApiOperation("批量添加文件到文件夹") ++ @ApiOperation(value = "批量添加文件到文件夹", notes = "一次添加多个照片/视频到指定文件夹。文件需先通过文件服务上传获取OSS URL\n\n" + ++ "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/album/folder/{folderId}/files") + public Result> addFiles( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -80,7 +85,10 @@ public class AdminAlbumController { + return Result.success(albumService.addFiles(folderId, request, adminId, roleKey)); + } + +- @ApiOperation("编辑文件信息") ++ @ApiOperation(value = "编辑文件信息", notes = "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PutMapping("/album/file/{albumFileId}") + public Result updateFile( + @ApiParam("相册文件ID") @PathVariable Long albumFileId, +@@ -91,7 +99,8 @@ public class AdminAlbumController { + return Result.success(albumService.updateFile(albumFileId, request, adminId, roleKey)); + } + +- @ApiOperation("删除文件") ++ @ApiOperation(value = "删除文件", ++ notes = "删除相册中的单个文件(照片/视频)。仅上传者或超级管理员可操作,删除后C端用户不再可见。") + @DeleteMapping("/album/file/{albumFileId}") + public Result deleteFile( + @ApiParam("相册文件ID") @PathVariable Long albumFileId, +@@ -102,7 +111,10 @@ public class AdminAlbumController { + return Result.success(null); + } + +- @ApiOperation("查询文件夹下的文件列表") ++ @ApiOperation(value = "查询文件夹下的文件列表", notes = "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/album/folder/{folderId}/files") + public Result> listFiles( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -111,7 +123,8 @@ public class AdminAlbumController { + return Result.success(albumService.listFiles(folderId, page, size)); + } + +- @ApiOperation("设置文件夹封面") ++ @ApiOperation(value = "设置文件夹封面", ++ notes = "将文件夹中的指定文件设为封面图,封面图会在文件夹列表中展示。仅上传者或超级管理员可操作。") + @PutMapping("/album/folder/{folderId}/cover") + public Result setCover( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -123,7 +136,11 @@ public class AdminAlbumController { + return Result.success(null); + } + +- @ApiOperation("我的上传(当前管理员上传的所有相册文件)") ++ @ApiOperation(value = "我的上传", notes = "查询当前管理员上传的所有相册文件(跨订单),方便管理自己上传的内容\n\n" + ++ "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/album/my-uploads") + public Result> listMyUploads( + HttpServletRequest httpRequest, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java +index 261c457..85b97c1 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminEarlyBirdController.java +@@ -31,7 +31,7 @@ public class AdminEarlyBirdController { + } + } + +- @ApiOperation("早鸟优惠计划列表") ++ @ApiOperation(value = "早鸟优惠计划列表", notes = "分页查询所有早鸟优惠计划。权限:仅超级管理员(SUPER_ADMIN)") + @GetMapping("/list") + public Result> list(HttpServletRequest request, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -41,7 +41,7 @@ public class AdminEarlyBirdController { + return Result.success(result); + } + +- @ApiOperation("早鸟优惠计划详情") ++ @ApiOperation(value = "早鸟优惠计划详情", notes = "权限:仅超级管理员(SUPER_ADMIN)") + @GetMapping("/{planId}") + public Result detail(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId) { +@@ -50,7 +50,8 @@ public class AdminEarlyBirdController { + return Result.success(vo); + } + +- @ApiOperation("创建早鸟优惠计划") ++ @ApiOperation(value = "创建早鸟优惠计划", notes = "创建一个早鸟优惠计划,在指定日期范围内下单且满足最低人数条件的订单可享受优惠。\n" + ++ "下单时系统自动匹配最优的早鸟计划。权限:仅超级管理员(SUPER_ADMIN)") + @PostMapping + public Result create(HttpServletRequest request, + @ApiParam("创建早鸟计划请求") @Valid @RequestBody EarlyBirdPlanRequest planRequest) { +@@ -61,7 +62,7 @@ public class AdminEarlyBirdController { + return Result.success(vo); + } + +- @ApiOperation("修改早鸟优惠计划") ++ @ApiOperation(value = "修改早鸟优惠计划", notes = "权限:仅超级管理员(SUPER_ADMIN)。修改不影响已下单的订单优惠") + @PutMapping("/{planId}") + public Result update(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId, +@@ -71,7 +72,7 @@ public class AdminEarlyBirdController { + return Result.success(); + } + +- @ApiOperation("删除早鸟优惠计划") ++ @ApiOperation(value = "删除早鸟优惠计划", notes = "权限:仅超级管理员(SUPER_ADMIN)。删除不影响已下单的订单优惠") + @DeleteMapping("/{planId}") + public Result delete(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId) { +@@ -80,7 +81,7 @@ public class AdminEarlyBirdController { + return Result.success(); + } + +- @ApiOperation("启用/禁用早鸟优惠计划") ++ @ApiOperation(value = "启用/禁用早鸟优惠计划", notes = "禁用后该计划不再参与自动匹配。权限:仅超级管理员(SUPER_ADMIN)") + @PutMapping("/{planId}/toggle") + public Result toggle(HttpServletRequest request, + @ApiParam("早鸟计划ID") @PathVariable Long planId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java +index de26a0f..d79934d 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderConfigController.java +@@ -27,7 +27,8 @@ public class AdminOrderConfigController { + @Value("${order.expiry.redis-key:order:config:expiry-minutes}") + private String expiryRedisKey; + +- @ApiOperation("获取订单过期配置") ++ @ApiOperation(value = "获取订单过期配置", notes = "获取当前的订单未支付自动过期时间(分钟)。\n" + ++ "返回当前值、默认值和配置来源(redis=已自定义, default=使用默认值)") + @GetMapping("/expiry-minutes") + public Result> getExpiryMinutes() { + String val = stringRedisTemplate.opsForValue().get(expiryRedisKey); +@@ -45,7 +46,8 @@ public class AdminOrderConfigController { + )); + } + +- @ApiOperation("设置订单过期时间(分钟)") ++ @ApiOperation(value = "设置订单过期时间(分钟)", notes = "修改订单未支付自动取消的等待时间。存储在Redis中,即时生效。\n" + ++ "仅影响新创建的订单,已有订单的过期时间不变") + @PutMapping("/expiry-minutes") + public Result setExpiryMinutes(@ApiParam("修改订单过期时间请求") @Valid @RequestBody UpdateExpiryMinutesRequest expiryRequest) { + stringRedisTemplate.opsForValue().set(expiryRedisKey, String.valueOf(expiryRequest.getMinutes())); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java +index e7f09ce..72bdfc8 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderController.java +@@ -47,7 +47,18 @@ public class AdminOrderController { + private static final String ORDER_CREATE_DEDUP = "order:admin:create:dedup:"; + + @ApiOperation(value = "创建订单(定制师代下单)", notes = "创建订单流程:选择产品 → 填写联系人和出行人 → 系统计算报价 → 生成订单(PENDING_PAY状态)\n\n" + +- "权限:CUSTOM产品仅创建者可下单,CORE/ROUTE产品所有管理员可下单") ++ "权限:CUSTOM产品仅创建者可下单,CORE/ROUTE产品所有管理员可下单\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)") + @PostMapping("/create") + public Result createOrder(HttpServletRequest request, + @ApiParam("创建订单请求") @Valid @RequestBody AdminCreateOrderRequest createRequest) { +@@ -69,21 +80,41 @@ public class AdminOrderController { + } + } + +- @ApiOperation("报价预览") ++ @ApiOperation(value = "报价预览", notes = "根据产品、出发日期、人数组合实时计算报价。\n" + ++ "返回各资源明细价格和合计金额,前端据此展示报价清单。\n\n" + ++ "注意:报价仅供参考,最终价格以创建订单时为准(价格日历可能变动)") + @PostMapping("/quote") + public Result> quotePreview(@ApiParam("报价预览请求") @Valid @RequestBody QuotePreviewRequest quoteRequest) { + Map result = orderService.quotePreview(quoteRequest); + return Result.success(result); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "支持按关键词(订单号/联系人/产品名)、状态、内部流程状态、产品类型筛选。\n" + ++ "支持按创建时间/出发日期/总价排序。\n\n" + ++ "返回分页结果,包含订单基本信息、状态、支付信息和产品封面\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 筛选参数 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 筛选参数 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> listOrders(@ApiParam("订单查询请求") AdminOrderQueryRequest request) { + PageResult result = orderService.listAdminOrders(request); + return Result.success(result); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "返回订单完整信息,包括:基本信息、产品快照、联系人、出行人列表、支付记录、优惠明细、时间线、内部流程状态等\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 timeline[].action → 字典:order_timeline_action(订单操作类型)\n" + ++ "- 返回字段 todos[].todoType → 字典:order_todo_type(订单待办类型)") + @GetMapping("/{orderId}") + public Result getOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + OrderDetailVO detail = orderService.getAdminOrderDetail(orderId); +@@ -111,7 +142,9 @@ public class AdminOrderController { + "- 旅行中 → 已完成\n" + + "- 已完成 → 售后中\n" + + "- 售后中 → 退款中\n" + +- "- 退款中 → 已退款") ++ "- 退款中 → 已退款\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 status → 字典:order_status(订单状态)") + @PutMapping("/{orderId}/status") + public Result updateStatus(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -134,7 +167,7 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("添加备注") ++ @ApiOperation(value = "添加备注", notes = "向订单时间线添加一条管理员备注。备注会记录操作人和时间,可用于内部沟通和订单跟踪") + @PostMapping("/{orderId}/remark") + public Result addRemark(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -145,7 +178,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("修改定金金额") ++ @ApiOperation(value = "修改定金金额", notes = "修改订单的定金金额。仅待支付(PENDING_PAY)状态可修改。\n\n" + ++ "定金金额不能超过订单总价,修改后影响用户支付页面显示的应付金额") + @PutMapping("/{orderId}/deposit") + public Result updateDeposit(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -156,7 +190,14 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("编辑订单") ++ @ApiOperation(value = "编辑订单", notes = "修改订单的联系人、人数、出发日期、售价、成本、备注等信息。\n" + ++ "仅传入需要修改的字段,未传入的字段不会被修改。\n\n" + ++ "如果提供了出行人列表(travelers),将替换订单的全部出行人。\n" + ++ "已锁定的订单需先调用'申请修改'接口解锁后才能编辑\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)") + @PutMapping("/{orderId}") + public Result editOrder(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -167,7 +208,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("更新房间信息(仅房务管理员/超级管理员)") ++ @ApiOperation(value = "更新房间信息(仅房务管理员/超级管理员)", ++ notes = "更新订单的房间分配信息(房型、房间号、入住安排等)。\n\n**权限**:仅ROOM_MANAGER(房务管理员)或SUPER_ADMIN(超级管理员)可操作。") + @PutMapping("/{orderId}/room-info") + public Result updateRoomInfo(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -183,7 +225,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("更新车辆信息(仅车务管理员/超级管理员)") ++ @ApiOperation(value = "更新车辆信息(仅车务管理员/超级管理员)", ++ notes = "更新订单的车辆分配信息(车型、车牌号、司机等)。\n\n**权限**:仅VEHICLE_MANAGER(车务管理员)或SUPER_ADMIN(超级管理员)可操作。") + @PutMapping("/{orderId}/vehicle-info") + public Result updateVehicleInfo(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -210,7 +253,9 @@ public class AdminOrderController { + } + + @ApiOperation(value = "推进内部流程", notes = "内部流程推进顺序:待配房(PENDING_ROOM) → 待配车(PENDING_VEHICLE) → 待核算(PENDING_FINANCE) → 就绪(READY)\n\n" + +- "仅在订单状态为已确认(CONFIRMED)时有效,每次调用自动推进到下一步") ++ "仅在订单状态为已确认(CONFIRMED)时有效,每次调用自动推进到下一步\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 processStatus → 字典:order_process_status(订单内部流程状态)") + @PutMapping("/{orderId}/process-status") + public Result advanceProcessStatus(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -220,7 +265,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("添加优惠项") ++ @ApiOperation(value = "添加优惠项", notes = "为订单添加手动优惠(如会员折扣、老客优惠等)。\n" + ++ "添加后系统自动重算订单应付金额。一个订单可添加多个优惠项") + @PostMapping("/{orderId}/discount") + public Result addDiscount(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -231,7 +277,7 @@ public class AdminOrderController { + return Result.success(discount); + } + +- @ApiOperation("修改优惠项") ++ @ApiOperation(value = "修改优惠项", notes = "修改已添加的优惠项名称或金额,修改后自动重算订单应付金额") + @PutMapping("/{orderId}/discount/{discountId}") + public Result updateDiscount(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -243,7 +289,7 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("删除优惠项") ++ @ApiOperation(value = "删除优惠项", notes = "删除已添加的优惠项,删除后自动重算订单应付金额") + @DeleteMapping("/{orderId}/discount/{discountId}") + public Result removeDiscount(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -296,7 +342,8 @@ public class AdminOrderController { + return Result.success(diff); + } + +- @ApiOperation("分配车辆信息") ++ @ApiOperation(value = "分配车辆信息", notes = "为订单分配具体的车辆和司机信息(车型、品牌、车牌号、司机姓名和电话)。\n" + ++ "分配后信息将展示在订单详情和C端行程中") + @PutMapping("/{orderId}/vehicle-assignment") + public Result assignVehicle(@ApiParam("订单ID") @PathVariable Long orderId, + @RequestBody @Valid VehicleAssignmentRequest request) { +@@ -304,7 +351,8 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("分配酒店信息") ++ @ApiOperation(value = "分配酒店信息", notes = "按家庭为订单分配具体的酒店房间(酒店名称、房型、入住/退房日期)。\n" + ++ "每个家庭对应一条分配记录,分配后信息将展示在订单详情和C端行程中") + @PutMapping("/{orderId}/hotel-assignment") + public Result assignHotel(@ApiParam("订单ID") @PathVariable Long orderId, + @RequestBody @Valid HotelAssignmentRequest request) { +@@ -312,7 +360,7 @@ public class AdminOrderController { + return Result.success(); + } + +- @ApiOperation("设置尾款支付方式") ++ @ApiOperation(value = "设置尾款支付方式", notes = "设置订单尾款的支付方式。ONLINE=线上微信支付,OFFLINE=线下转账(需管理员手动记录尾款到账)") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java +index 83ae39c..9ab5d5e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderItineraryController.java +@@ -31,7 +31,11 @@ public class AdminOrderItineraryController { + private final OrderItineraryEditService itineraryEditService; + private final OrderPriceDiffService priceDiffService; + +- @ApiOperation(value = "跳过节点", notes = "将行程中的某个节点标记为跳过(客户不去)") ++ @ApiOperation(value = "跳过节点", notes = "将行程中的某个节点标记为跳过(客户不去)\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/skip") + public Result skipNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -43,7 +47,10 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.skipNode(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "恢复跳过的节点", notes = "取消跳过,恢复为正常状态") ++ @ApiOperation(value = "恢复跳过的节点", notes = "取消跳过,恢复为正常状态\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/skip/{editId}") + public Result unskipNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -58,7 +65,11 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation(value = "新增节点", notes = "在某一天的行程中新增一个节点") ++ @ApiOperation(value = "新增节点", notes = "在某一天的行程中新增一个节点\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/add") + public Result addNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -76,7 +87,10 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.addNode(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "删除新增的节点", notes = "删除通过编辑新增的节点") ++ @ApiOperation(value = "删除新增的节点", notes = "删除通过编辑新增的节点\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/add/{editId}") + public Result removeAddedNode( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -91,7 +105,10 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation("获取合并后的行程(原始+编辑)") ++ @ApiOperation(value = "获取合并后的行程(原始+编辑)", notes = "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/merged") + public Result>> getMergedItinerary( + @ApiParam("订单ID") @PathVariable Long orderId) { +@@ -105,14 +122,19 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.getBalanceAdjustmentSummary(orderId)); + } + +- @ApiOperation("获取行程编辑记录列表") ++ @ApiOperation(value = "获取行程编辑记录列表", notes = "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/edits") + public Result> getEditList( + @ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(itineraryEditService.getEditList(orderId)); + } + +- @ApiOperation(value = "房型切换差价预览", notes = "预览房型切换的差价,不创建记录") ++ @ApiOperation(value = "房型切换差价预览", notes = "预览房型切换的差价,不创建记录\n\n" + ++ "**关联字典**:\n" + ++ "- resource_type(资源类型,返回字段resourceType):HOTEL=酒店") + @PostMapping("/room-type-change/preview") + public Result previewRoomTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -120,7 +142,11 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.previewRoomTypeDiff(orderId, request)); + } + +- @ApiOperation(value = "房型切换", notes = "执行房型切换,自动计算差价,创建待确认记录") ++ @ApiOperation(value = "房型切换", notes = "执行房型切换,自动计算差价,创建待确认记录\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):ROOM_CHANGE=房型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):HOTEL=酒店") + @PostMapping("/room-type-change") + public Result roomTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -132,7 +158,9 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.executeRoomTypeChange(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "车型切换差价预览", notes = "预览车型切换的差价,不创建记录") ++ @ApiOperation(value = "车型切换差价预览", notes = "预览车型切换的差价,不创建记录\n\n" + ++ "**关联字典**:\n" + ++ "- resource_type(资源类型,返回字段resourceType):VEHICLE=车辆") + @PostMapping("/vehicle-type-change/preview") + public Result previewVehicleTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -140,7 +168,11 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.previewVehicleTypeDiff(orderId, request)); + } + +- @ApiOperation(value = "车型切换", notes = "执行车型切换,自动计算差价,创建待确认记录") ++ @ApiOperation(value = "车型切换", notes = "执行车型切换,自动计算差价,创建待确认记录\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):VEHICLE=车辆") + @PostMapping("/vehicle-type-change") + public Result vehicleTypeChange( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -152,7 +184,11 @@ public class AdminOrderItineraryController { + return Result.success(priceDiffService.executeVehicleTypeChange(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "新增整天行程", notes = "在订单行程中新增一整天(含多个节点)") ++ @ApiOperation(value = "新增整天行程", notes = "在订单行程中新增一整天(含多个节点)\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):ADD_DAY=新增整天\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PostMapping("/add-day") + public Result> addDay( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -164,7 +200,9 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.addDay(orderId, request, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "删除新增的整天行程", notes = "删除通过新增操作添加的整天行程及其所有子节点,已确认的天不允许删除") ++ @ApiOperation(value = "删除新增的整天行程", notes = "删除通过新增操作添加的整天行程及其所有子节点,已确认的天不允许删除\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/day/{editId}") + public Result removeDay( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -179,7 +217,11 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation(value = "修改编辑记录", notes = "修改待确认状态的编辑记录(如调整价格、名称等)") ++ @ApiOperation(value = "修改编辑记录", notes = "修改待确认状态的编辑记录(如调整价格、名称等)\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_edit_action(操作类型,返回字段action):SKIP=跳过, ADD=新增节点, ADD_DAY=新增整天, ROOM_CHANGE=房型切换, VEHICLE_CHANGE=车型切换\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @PutMapping("/edit/{editId}") + public Result updateEdit( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -192,7 +234,9 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.updateEdit(orderId, editId, updates, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "确认单条修改", notes = "确认一条待确认的行程编辑") ++ @ApiOperation(value = "确认单条修改", notes = "确认一条待确认的行程编辑\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @PostMapping("/confirm/{editId}") + public Result confirmEdit( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -205,7 +249,9 @@ public class AdminOrderItineraryController { + return Result.success(); + } + +- @ApiOperation(value = "批量确认所有待确认修改", notes = "确认该订单所有待确认的行程编辑") ++ @ApiOperation(value = "批量确认所有待确认修改", notes = "确认该订单所有待确认的行程编辑\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @PostMapping("/confirm-all") + public Result confirmAllPending( + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -216,7 +262,9 @@ public class AdminOrderItineraryController { + return Result.success(itineraryEditService.confirmAllPending(orderId, adminId, adminName, roleKey)); + } + +- @ApiOperation(value = "撤回待确认的修改", notes = "软删除一条待确认的编辑记录") ++ @ApiOperation(value = "撤回待确认的修改", notes = "软删除一条待确认的编辑记录\n\n" + ++ "**关联字典**:\n" + ++ "- itinerary_confirm_status(确认状态,返回字段confirmStatus):PENDING_CONFIRM=待确认, CONFIRMED=已确认") + @DeleteMapping("/pending/{editId}") + public Result withdrawPendingEdit( + @ApiParam("订单ID") @PathVariable Long orderId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java +index d7339d2..f708a7f 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminOrderTodoController.java +@@ -29,14 +29,21 @@ public class AdminOrderTodoController { + private final OrderService orderService; + private final UserFeignClient userFeignClient; + +- @ApiOperation("获取订单待办列表") ++ @ApiOperation(value = "获取订单待办列表", notes = "返回指定订单的所有待办项(含已完成和未完成)。\n" + ++ "待办类型包括:配房、配车、签合同、购保险、核算等,随内部流程自动生成\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 todoType → 字典:order_todo_type(订单待办类型)") + @GetMapping("/{orderId}/todos") + public Result> getOrderTodos(@ApiParam("订单ID") @PathVariable Long orderId) { + List todos = orderTodoService.listByOrderId(orderId); + return Result.success(todos); + } + +- @ApiOperation("完成待办") ++ @ApiOperation(value = "完成待办", notes = "将指定待办标记为已完成。\n" + ++ "需要对应角色权限:如配房待办需ROOM_MANAGER角色,配车待办需VEHICLE_MANAGER角色。\n\n" + ++ "完成后系统自动检查是否所有必要待办已完成,若是则推进内部流程\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 todoType → 字典:order_todo_type(订单待办类型)") + @PutMapping("/todo/{todoId}/complete") + public Result completeTodo(HttpServletRequest request, + @ApiParam("待办ID") @PathVariable Long todoId) { +@@ -47,7 +54,11 @@ public class AdminOrderTodoController { + return Result.success(); + } + +- @ApiOperation("我的待办列表") ++ @ApiOperation(value = "我的待办列表", notes = "根据当前管理员ID和角色,查询分配给自己的未完成待办。\n" + ++ "超级管理员可看到所有待办,其他角色只能看到对应类型的待办\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 todoType → 字典:order_todo_type(订单待办类型)\n" + ++ "- 返回字段 orderStatus → 字典:order_status(订单状态)") + @GetMapping("/todo/my-list") + public Result> getMyTodos(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -56,7 +67,7 @@ public class AdminOrderTodoController { + return Result.success(todos); + } + +- @ApiOperation("我的待办数量") ++ @ApiOperation(value = "我的待办数量", notes = "返回当前管理员未完成的待办总数,用于首页角标/红点提醒") + @GetMapping("/todo/my-count") + public Result getMyTodosCount(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -65,7 +76,7 @@ public class AdminOrderTodoController { + return Result.success(count); + } + +- @ApiOperation("定制师列表") ++ @ApiOperation(value = "定制师列表", notes = "获取所有定制师(CUSTOMIZER角色)的列表,用于更换定制师时选择目标定制师") + @GetMapping("/todo/customizer-list") + public Result> getCustomizerList() { + try { +@@ -79,7 +90,7 @@ public class AdminOrderTodoController { + return Result.success(Collections.emptyList()); + } + +- @ApiOperation("更换定制师") ++ @ApiOperation(value = "更换定制师", notes = "将订单转派给另一位定制师。更换后原定制师的待办自动转移,订单时间线会记录此操作") + @PutMapping("/{orderId}/customizer") + public Result changeCustomizer(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId, +@@ -90,7 +101,11 @@ public class AdminOrderTodoController { + return Result.success(); + } + +- @ApiOperation("可签合同订单列表(保险已完成)") ++ @ApiOperation(value = "可签合同订单列表(保险已完成)", notes = "查询保险待办已完成、可以进入签合同环节的订单列表。\n" + ++ "用于合同管理页面展示待签合同的订单\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 todoType → 字典:order_todo_type(订单待办类型)\n" + ++ "- 返回字段 orderStatus → 字典:order_status(订单状态)") + @GetMapping("/todo/contract-eligible") + public Result> getContractEligibleOrders(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java +index fddef53..eb92d44 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundController.java +@@ -31,7 +31,11 @@ public class AdminRefundController { + + // ==================== Refund Applications ==================== + +- @ApiOperation("退款申请列表") ++ @ApiOperation(value = "退款申请列表", notes = "分页查询退款申请,支持按状态筛选。\n" + ++ "状态包括:PENDING(待审批)、APPROVED(已通过)、REJECTED(已拒绝)、REFUNDING(退款中)、REFUNDED(已退款)、CANCELLED(已撤回)、APPEAL(申诉中)\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:refund_status(退款状态)\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/list") + public Result> listApplications( + @ApiParam("状态") @RequestParam(required = false) String status, +@@ -40,14 +44,18 @@ public class AdminRefundController { + return Result.success(refundApplicationService.listApplications(status, page, pageSize)); + } + +- @ApiOperation("退款申请详情") ++ @ApiOperation(value = "退款申请详情", notes = "返回退款申请的完整信息,包括退款原因、申请金额、实退金额、审批记录、申诉信息等\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/{applicationId}") + public Result getDetail(@ApiParam("退款申请ID") @PathVariable Long applicationId) { + return Result.success(refundApplicationService.getDetail(applicationId)); + } + + @ApiOperation(value = "审批退款申请", notes = "退款审批流程:查看退款申请 → 决定通过/拒绝 → 通过时填写实退金额 → 系统自动调起微信退款\n\n" + +- "拒绝后用户可发起申诉") ++ "拒绝后用户可发起申诉\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @PutMapping("/{applicationId}/review") + public Result review(HttpServletRequest request, + @ApiParam("退款申请ID") @PathVariable Long applicationId, +@@ -79,20 +87,26 @@ public class AdminRefundController { + + // ==================== Refund Reasons ==================== + +- @ApiOperation("退款原因列表") ++ @ApiOperation(value = "退款原因列表", notes = "获取所有退款原因选项(含禁用的),用于退款原因管理页面\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 category → 字典:refund_reason_category(退款原因分类)") + @GetMapping("/reason/list") + public Result> listReasons() { + return Result.success(refundReasonService.listReasons(false)); + } + +- @ApiOperation("创建退款原因") ++ @ApiOperation(value = "创建退款原因", notes = "新增退款原因选项,C端用户申请退款时可选择。按sortOrder排序展示\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 category → 字典:refund_reason_category(退款原因分类)") + @PostMapping("/reason") + public Result createReason(@ApiParam("创建退款原因请求") @Valid @RequestBody CreateRefundReasonRequest createRequest) { + return Result.success(refundReasonService.createReason( + createRequest.getReasonText(), createRequest.getCategory(), createRequest.getSortOrder())); + } + +- @ApiOperation("修改退款原因") ++ @ApiOperation(value = "修改退款原因", notes = "修改退款原因的文本、分类或排序,不影响已使用该原因的历史退款申请\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 category → 字典:refund_reason_category(退款原因分类)") + @PutMapping("/reason/{reasonId}") + public Result updateReason(@ApiParam("退款原因ID") @PathVariable Long reasonId, + @ApiParam("修改退款原因请求") @Valid @RequestBody UpdateRefundReasonRequest updateRequest) { +@@ -100,7 +114,7 @@ public class AdminRefundController { + reasonId, updateRequest.getReasonText(), updateRequest.getCategory(), updateRequest.getSortOrder())); + } + +- @ApiOperation("删除退款原因") ++ @ApiOperation(value = "删除退款原因", notes = "软删除退款原因,删除后C端不再展示。不影响已使用该原因的历史退款申请") + @DeleteMapping("/reason/{reasonId}") + public Result deleteReason(@ApiParam("退款原因ID") @PathVariable Long reasonId) { + refundReasonService.deleteReason(reasonId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java +index 9ff5005..e1bc0c8 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminRefundPolicyController.java +@@ -22,13 +22,17 @@ public class AdminRefundPolicyController { + + private final RefundPolicyService refundPolicyService; + +- @ApiOperation("退款政策列表") ++ @ApiOperation(value = "退款政策列表", notes = "【关联字典】\n" + ++ "- 返回字段 refundType → 字典:refund_type(退款类型)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> list() { + return Result.success(refundPolicyService.listPolicies()); + } + +- @ApiOperation("退款政策详情") ++ @ApiOperation(value = "退款政策详情", notes = "【关联字典】\n" + ++ "- 返回字段 refundType → 字典:refund_type(退款类型)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/{policyId}") + public Result detail(@ApiParam("退款政策ID") @PathVariable Long policyId) { + return Result.success(refundPolicyService.getDetail(policyId)); +@@ -36,7 +40,10 @@ public class AdminRefundPolicyController { + + @ApiOperation(value = "创建退款政策", notes = "退款政策定义按产品类型和距出发天数的退款比例阶梯\n\n" + + "例如:出发前30天退90%,前15天退70%,前7天退50%,7天内不可退\n\n" + +- "每种产品类型可配置独立的退款政策,用户申请退款时系统自动匹配") ++ "每种产品类型可配置独立的退款政策,用户申请退款时系统自动匹配\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 refundType → 字典:refund_type(退款类型)\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)") + @PostMapping + public Result create(HttpServletRequest request, + @ApiParam("创建退款政策请求") @Valid @RequestBody RefundPolicyRequest policyRequest) { +@@ -44,14 +51,17 @@ public class AdminRefundPolicyController { + return Result.success(refundPolicyService.createPolicy(policyRequest, adminId)); + } + +- @ApiOperation("修改退款政策") ++ @ApiOperation(value = "修改退款政策", notes = "【关联字典】\n" + ++ "- 请求参数 refundType → 字典:refund_type(退款类型)\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)") + @PutMapping("/{policyId}") + public Result update(@ApiParam("退款政策ID") @PathVariable Long policyId, + @ApiParam("修改退款政策请求") @Valid @RequestBody RefundPolicyRequest policyRequest) { + return Result.success(refundPolicyService.updatePolicy(policyId, policyRequest)); + } + +- @ApiOperation("删除退款政策") ++ @ApiOperation(value = "删除退款政策", ++ notes = "软删除退款政策。删除后该产品类型将使用默认退款规则。不影响已使用该政策处理的历史退款申请。") + @DeleteMapping("/{policyId}") + public Result delete(@ApiParam("退款政策ID") @PathVariable Long policyId) { + refundPolicyService.deletePolicy(policyId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java +index 949f142..faf973b 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/AdminWorkOrderController.java +@@ -25,7 +25,15 @@ public class AdminWorkOrderController { + + private final WorkOrderService workOrderService; + +- @ApiOperation("工单列表") ++ @ApiOperation(value = "工单列表", notes = "分页查询工单,支持按状态/类型/优先级/订单编号/处理人筛选。\n" + ++ "工单用于处理旅行中的突发变更需求(如换房、换车、加景点等)\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:work_order_status(工单状态)\n" + ++ "- 筛选参数 type → 字典:work_order_type(工单类型)\n" + ++ "- 筛选参数 priority → 字典:work_order_priority(工单优先级)\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)\n" + ++ "- 返回字段 type → 字典:work_order_type(工单类型)\n" + ++ "- 返回字段 priority → 字典:work_order_priority(工单优先级)") + @GetMapping("/list") + public Result> list( + @ApiParam("状态: PENDING/PROCESSING/RESOLVED/REJECTED") @RequestParam(required = false) String status, +@@ -38,19 +46,32 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.listWorkOrders(status, type, priority, orderNo, assigneeAdminId, page, pageSize)); + } + +- @ApiOperation("工单详情") ++ @ApiOperation(value = "工单详情", notes = "返回工单完整信息,包括关联订单、资源详情、处理记录和备注列表\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)\n" + ++ "- 返回字段 type → 字典:work_order_type(工单类型)\n" + ++ "- 返回字段 priority → 字典:work_order_priority(工单优先级)") + @GetMapping("/{workOrderId}") + public Result getDetail(@ApiParam("工单ID") @PathVariable Long workOrderId) { + return Result.success(workOrderService.getDetail(workOrderId)); + } + +- @ApiOperation("工单统计(待处理数等)") ++ @ApiOperation(value = "工单统计", notes = "返回各状态的工单数量和紧急工单数,用于工单管理页面顶部统计卡片\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:work_order_status(工单状态)") + @GetMapping("/stats") + public Result> getStats() { + return Result.success(workOrderService.getStats()); + } + +- @ApiOperation("创建工单") ++ @ApiOperation(value = "创建工单", notes = "创建旅途中的变更工单,需关联订单ID。\n" + ++ "可指定处理人,未指定则进入待分配状态。可附带差价信息和资源详情JSON\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 type → 字典:work_order_type(工单类型)\n" + ++ "- 请求参数 priority → 字典:work_order_priority(工单优先级)\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)\n" + ++ "- 返回字段 type → 字典:work_order_type(工单类型)\n" + ++ "- 返回字段 priority → 字典:work_order_priority(工单优先级)") + @PostMapping + public Result create(HttpServletRequest request, + @Valid @RequestBody CreateWorkOrderRequest body) { +@@ -59,7 +80,10 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.createWorkOrder(adminId, adminName, body)); + } + +- @ApiOperation("处理工单(解决/驳回)") ++ @ApiOperation(value = "处理工单(解决/驳回)", notes = "解决时需填写处理结果(resolution),驳回时需填写驳回原因(rejectReason)。\n" + ++ "可调整差价(costDifference),正数表示加价,负数表示退费\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:work_order_status(工单状态)") + @PutMapping("/{workOrderId}/process") + public Result process(HttpServletRequest request, + @ApiParam("工单ID") @PathVariable Long workOrderId, +@@ -69,7 +93,7 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.processWorkOrder(workOrderId, adminId, adminName, body)); + } + +- @ApiOperation("指派工单") ++ @ApiOperation(value = "指派工单", notes = "将工单分配给指定管理员处理。被指派人将在待办列表中看到该工单") + @PutMapping("/{workOrderId}/assign") + public Result assign(HttpServletRequest request, + @ApiParam("工单ID") @PathVariable Long workOrderId, +@@ -80,7 +104,7 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.assignWorkOrder(workOrderId, adminId, adminName, assigneeId, assigneeName)); + } + +- @ApiOperation("添加备注") ++ @ApiOperation(value = "添加工单备注", notes = "在工单中追加备注信息,用于内部沟通和处理过程记录") + @PostMapping("/{workOrderId}/comment") + public Result addComment(HttpServletRequest request, + @ApiParam("工单ID") @PathVariable Long workOrderId, +@@ -94,7 +118,7 @@ public class AdminWorkOrderController { + return Result.success(workOrderService.addComment(workOrderId, adminId, adminName, content)); + } + +- @ApiOperation("按订单查工单数量") ++ @ApiOperation(value = "按订单查工单数量", notes = "返回指定订单关联的工单总数,用于订单详情页展示工单角标") + @GetMapping("/count-by-order/{orderId}") + public Result countByOrder(@ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(workOrderService.countByOrderId(orderId)); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java +index 0d65e46..e8684ef 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalAlbumController.java +@@ -16,7 +16,7 @@ import java.util.List; + /** + * 相册内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序相册(Feign调用)") ++@Api(tags = "【内部接口】小程序相册(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/album") + @RequiredArgsConstructor +@@ -24,13 +24,14 @@ public class InternalAlbumController { + + private final AlbumService albumService; + +- @ApiOperation("用户有相册的订单列表") ++ @ApiOperation(value = "用户有相册的订单列表", notes = "返回用户所有有相册文件夹的订单(含订单基本信息和相册封面),用于C端'我的相册'入口") + @GetMapping("/orders") + public Result> listAlbumOrders(@RequestParam Long userId) { + return Result.success(albumService.listUserAlbumOrders(userId)); + } + +- @ApiOperation("订单的文件夹列表") ++ @ApiOperation(value = "订单的文件夹列表", ++ notes = "内部服务间调用。返回指定用户指定订单下的相册文件夹列表,会校验订单归属权限。") + @GetMapping("/order/{orderId}/folders") + public Result> listFolders( + @RequestParam Long userId, +@@ -38,7 +39,10 @@ public class InternalAlbumController { + return Result.success(albumService.listUserFolders(userId, orderId)); + } + +- @ApiOperation("文件夹下的文件列表") ++ @ApiOperation(value = "文件夹下的文件列表", notes = "**关联字典**:\n" + ++ "- album_file_type(文件类型,返回字段fileType):IMAGE=图片, VIDEO=视频\n" + ++ "- album_location_type(地点类型,返回字段locationType):RESOURCE=关联资源, CUSTOM=自定义地点\n" + ++ "- resource_type(资源类型,返回字段resourceType):SCENIC_SPOT=景区, ACTIVITY=活动, RESTAURANT=餐厅, HOTEL=酒店, VEHICLE=车辆") + @GetMapping("/folder/{folderId}/files") + public Result> listFiles( + @RequestParam Long userId, +@@ -48,7 +52,7 @@ public class InternalAlbumController { + return Result.success(albumService.listUserFiles(userId, folderId, page, size)); + } + +- @ApiOperation("获取文件下载链接") ++ @ApiOperation(value = "获取文件下载链接", notes = "生成带签名的临时下载URL(有效期1小时),用于C端用户下载原图/视频") + @GetMapping("/file/{albumFileId}/download-url") + public Result getDownloadUrl( + @RequestParam Long userId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java +index 0fd0c6a..110daf9 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDashboardController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】工作台统计(Feign调用)") ++@Api(tags = "【内部接口】工作台统计(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order/dashboard") + @RequiredArgsConstructor +@@ -19,7 +19,9 @@ public class InternalDashboardController { + + private final DashboardStatsService dashboardStatsService; + +- @ApiOperation("概览统计(支持定制师/全局,支持今日/本周/本月)") ++ @ApiOperation(value = "概览统计", notes = "返回订单量、成交金额、待处理订单数等概览数据。\n" + ++ "传customizerId则返回该定制师的数据,不传则返回全局数据。\n" + ++ "period支持: today(今日)、week(本周)、month(本月)") + @GetMapping("/overview-stats") + public Result> getOverviewStats( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -27,7 +29,9 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getOverviewStats(customizerId, period)); + } + +- @ApiOperation("待办分类汇总") ++ @ApiOperation(value = "待办分类汇总", notes = "按待办类型分组统计当前管理员的未完成待办数量,用于工作台待办卡片展示\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的待办类型key → 字典:order_todo_type(订单待办类型)") + @GetMapping("/todo-summary") + public Result> getTodoSummary( + @ApiParam("管理员ID") @RequestParam Long adminId, +@@ -35,7 +39,7 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getTodoSummary(adminId, roleKey)); + } + +- @ApiOperation("数据趋势(按天聚合)") ++ @ApiOperation(value = "数据趋势", notes = "按天聚合的订单量和金额趋势数据,用于折线图展示。支持最近7天或30天") + @GetMapping("/trend") + public Result>> getTrend( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -46,7 +50,9 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getTrend(customizerId, days)); + } + +- @ApiOperation("转化漏斗") ++ @ApiOperation(value = "转化漏斗", notes = "展示订单从创建→支付→确认→完成的转化率漏斗数据\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 订单状态 → 字典:order_status(订单状态)") + @GetMapping("/funnel") + public Result> getFunnel( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -54,7 +60,10 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getFunnel(customizerId, period)); + } + +- @ApiOperation("即将出行列表") ++ @ApiOperation(value = "即将出行列表", notes = "返回最近即将出发的订单列表,按出发日期升序。用于工作台提醒关注即将出行的客户\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/upcoming-trips") + public Result>> getUpcomingTrips( + @ApiParam("定制师ID,不传则为全局") @RequestParam(required = false) Long customizerId, +@@ -62,14 +71,14 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getUpcomingTrips(customizerId, limit)); + } + +- @ApiOperation("业绩排行(本月定制师排名)") ++ @ApiOperation(value = "业绩排行", notes = "按定制师维度统计成交金额排名,支持本周/本月周期。用于工作台排行榜展示") + @GetMapping("/ranking") + public Result>> getRanking( + @ApiParam("时间范围: month/week") @RequestParam(defaultValue = "month") String period) { + return Result.success(dashboardStatsService.getRanking(period)); + } + +- @ApiOperation("日历事件") ++ @ApiOperation(value = "日历事件", notes = "返回指定月份的出发日期事件列表,用于工作台日历组件展示。每个事件包含订单基本信息") + @GetMapping("/calendar-events") + public Result>> getCalendarEvents( + @ApiParam("定制师ID") @RequestParam(required = false) Long customizerId, +@@ -78,14 +87,14 @@ public class InternalDashboardController { + return Result.success(dashboardStatsService.getCalendarEvents(customizerId, year, month)); + } + +- @ApiOperation("财务统计") ++ @ApiOperation(value = "财务统计", notes = "返回收入、成本、利润等财务汇总数据,支持按时间周期统计") + @GetMapping("/finance-stats") + public Result> getFinanceStats( + @ApiParam("时间范围") @RequestParam(defaultValue = "today") String period) { + return Result.success(dashboardStatsService.getFinanceStats(period)); + } + +- @ApiOperation("退款汇总") ++ @ApiOperation(value = "退款汇总", notes = "返回退款总额、退款笔数、退款率等汇总信息。传customizerId可查看单个定制师的退款数据") + @GetMapping("/refund-summary") + public Result> getRefundSummary( + @ApiParam("定制师ID") @RequestParam(required = false) Long customizerId) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java +index bb7a01e..cd52e45 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalDesignerOrderController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; + + import java.util.Map; + +-@Api(tags = "【内部接口】定制师订单(Feign调用)") ++@Api(tags = "【内部接口】定制师订单(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order") + @RequiredArgsConstructor +@@ -20,20 +20,29 @@ public class InternalDesignerOrderController { + + private final OrderService orderService; + +- @ApiOperation("获取定制师订单统计") ++ @ApiOperation(value = "获取定制师订单统计", notes = "返回指定定制师的订单统计数据(各状态数量、总金额等),用于定制师工作台概览\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:order_status(订单状态)") + @GetMapping("/designer-stats") + public Result> getDesignerOrderStats( + @ApiParam("定制师管理员ID") @RequestParam Long customizerId) { + return Result.success(orderService.getDesignerOrderStats(customizerId)); + } + +- @ApiOperation("获取全局订单统计") ++ @ApiOperation(value = "获取全局订单统计", notes = "返回全平台的订单统计数据(各状态数量、总金额等),用于管理层工作台概览\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:order_status(订单状态)") + @GetMapping("/global-stats") + public Result> getGlobalOrderStats() { + return Result.success(orderService.getGlobalOrderStats()); + } + +- @ApiOperation("定制师订单列表") ++ @ApiOperation(value = "定制师订单列表", notes = "分页查询指定定制师负责的订单,支持按状态和关键词筛选\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/designer-list") + public Result> listDesignerOrders( + @ApiParam("定制师管理员ID") @RequestParam Long customizerId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java +index 97b3871..b1bf9e7 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalEarlyBirdController.java +@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController; + import java.math.BigDecimal; + import java.util.List; + +-@Api(tags = "【内部接口】早鸟优惠(Feign调用)") ++@Api(tags = "【内部接口】早鸟优惠(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/early-bird") + @RequiredArgsConstructor +@@ -23,14 +23,17 @@ public class InternalEarlyBirdController { + + private final EarlyBirdPlanService earlyBirdPlanService; + +- @ApiOperation("获取当前有效的早鸟优惠计划列表") ++ @ApiOperation(value = "获取当前有效的早鸟优惠计划列表", notes = "返回当前日期处于生效期内且已启用的早鸟计划,C端下单时展示可用优惠") + @GetMapping("/active") + public Result> listActivePlans() { + List plans = earlyBirdPlanService.listActivePlans(); + return Result.success(plans); + } + +- @ApiOperation("匹配最优早鸟优惠计划") ++ @ApiOperation(value = "匹配最优早鸟优惠计划", notes = "根据产品类型、出行人数、订单总价匹配优惠金额最大的早鸟计划。\n" + ++ "无匹配返回null。供下单时自动匹配调用\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 productType → 字典:product_type(产品类型)") + @GetMapping("/match") + public Result matchPlan( + @RequestParam String productType, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java +index e84a0e6..310b627 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalInvoiceController.java +@@ -15,7 +15,7 @@ import javax.validation.Valid; + * C端发票内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序发票(Feign调用)") ++@Api(tags = "【内部接口】小程序发票(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/invoice") + @RequiredArgsConstructor +@@ -23,21 +23,33 @@ public class InternalInvoiceController { + + private final InvoiceService invoiceService; + +- @ApiOperation("申请开票") ++ @ApiOperation(value = "申请开票", notes = "用户对已支付订单申请开具电子发票。支持个人和企业抬头。\n" + ++ "同一订单只能开一次发票(可换开)\n\n" + ++ "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,请求/返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @PostMapping("/apply") + public Result applyInvoice(@RequestParam Long userId, + @Valid @RequestBody InvoiceApplyRequest request) { + return Result.success(invoiceService.applyInvoice(userId, request)); + } + +- @ApiOperation("发票详情") ++ @ApiOperation(value = "发票详情", notes = "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @GetMapping("/{id}") + public Result getInvoiceDetail(@RequestParam Long userId, + @PathVariable Long id) { + return Result.success(invoiceService.getInvoiceDetail(userId, id)); + } + +- @ApiOperation("通过订单ID查询发票") ++ @ApiOperation(value = "通过订单ID查询发票", notes = "查询订单关联的发票信息。未开票时返回null\n\n" + ++ "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @GetMapping("/order/{orderId}") + public Result getInvoiceByOrderId(@RequestParam Long userId, + @PathVariable Long orderId) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java +index c27da3a..ec5f305 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpOrderController.java +@@ -24,7 +24,7 @@ import java.util.Map; + * C端订单内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序订单(Feign调用)") ++@Api(tags = "【内部接口】小程序订单(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/order") + @RequiredArgsConstructor +@@ -32,7 +32,13 @@ public class InternalMpOrderController { + + private final OrderService orderService; + +- @ApiOperation("创建订单") ++ @ApiOperation(value = "创建订单", notes = "供BFF层调用的C端下单接口。创建后返回订单详情(含支付信息),前端可直接跳转支付\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @PostMapping("/create") + public Result createOrder(@RequestParam Long userId, + @Valid @RequestBody CreateOrderRequest request) { +@@ -41,21 +47,32 @@ public class InternalMpOrderController { + return Result.success(detail); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> listOrders(@RequestParam Long userId, + MpOrderQueryRequest query) { + return Result.success(orderService.listUserOrders(userId, query)); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 timeline[].action → 字典:order_timeline_action(订单操作类型)") + @GetMapping("/{orderId}") + public Result getOrder(@RequestParam Long userId, + @PathVariable Long orderId) { + return Result.success(orderService.getUserOrderDetail(userId, orderId)); + } + +- @ApiOperation("取消订单") ++ @ApiOperation(value = "取消订单", ++ notes = "内部服务间调用,供BFF层调用的用户取消订单接口。仅允许取消待支付/已付定金状态的订单。") + @PostMapping("/{orderId}/cancel") + public Result cancelOrder(@RequestParam Long userId, + @PathVariable Long orderId, +@@ -65,7 +82,8 @@ public class InternalMpOrderController { + return Result.success(); + } + +- @ApiOperation("订单资源详情(按分类)") ++ @ApiOperation(value = "订单资源详情(按分类)", ++ notes = "内部服务间调用。解析订单的产品快照JSON,按资源类型分类提取资源详情(景区/酒店/活动/餐厅等),返回Map结构。") + @GetMapping("/{orderId}/resources") + public Result>>> getOrderResources( + @RequestParam Long userId, +@@ -73,7 +91,7 @@ public class InternalMpOrderController { + return Result.success(orderService.getOrderSnapshotResources(userId, orderId)); + } + +- @ApiOperation("通过联系人手机号+姓名查找订单(无需登录)") ++ @ApiOperation(value = "通过联系人手机号+姓名查找订单", notes = "无需登录。用于管理员代下单场景:管理员创建订单后用户通过手机号+姓名查找并绑定订单") + @GetMapping("/lookup") + public Result> lookupByContact( + @RequestParam String contactPhone, +@@ -81,7 +99,8 @@ public class InternalMpOrderController { + return Result.success(orderService.lookupByContact(contactPhone, contactName)); + } + +- @ApiOperation("绑定未绑定的订单(通过联系人手机号+姓名)") ++ @ApiOperation(value = "绑定未绑定的订单", notes = "将userId=NULL且联系人手机号+姓名匹配的订单绑定到当前用户。\n" + ++ "用于管理员代下单后用户登录自动关联订单。返回绑定的订单数量") + @PostMapping("/bind-by-contact") + public Result bindByContact(@RequestParam Long userId, + @Valid @RequestBody BindByContactRequest request) { +@@ -89,7 +108,7 @@ public class InternalMpOrderController { + return Result.success(bindCount); + } + +- @ApiOperation("客户同意解锁订单") ++ @ApiOperation(value = "客户同意解锁订单", notes = "管理员申请修改锁定订单后,C端用户确认同意解锁。解锁后管理员可重新编辑订单") + @PostMapping("/{orderId}/approve-unlock") + public Result approveUnlock(@RequestParam Long userId, + @PathVariable Long orderId) { +@@ -103,13 +122,16 @@ public class InternalMpOrderController { + return Result.success(orderService.getUpcomingDepartures(userId)); + } + +- @ApiOperation("各状态订单数量") ++ @ApiOperation(value = "各状态订单数量", notes = "返回用户各状态的订单数量Map,用于小程序订单页Tab角标显示\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段中的状态key → 字典:order_status(订单状态)") + @GetMapping("/count") + public Result> countByStatus(@RequestParam Long userId) { + return Result.success(orderService.countByStatusForUser(userId)); + } + +- @ApiOperation("标记订单已评价(评价服务回调)") ++ @ApiOperation(value = "标记订单已评价", notes = "评价服务(review-service)在用户发布评价后回调此接口,将订单标记为已评价。\n" + ++ "标记后订单详情不再显示'去评价'按钮") + @PutMapping("/{orderId}/mark-reviewed") + public Result markReviewed(@PathVariable Long orderId) { + orderService.markReviewed(orderId); +@@ -118,7 +140,13 @@ public class InternalMpOrderController { + + @ApiOperation(value = "用户修改订单", notes = "用户可修改出发日期和出行人,修改后重走内部流程(级联检测+价格重算)。" + + "仅待支付/已付定金/已支付/已确认/待付尾款/待出发状态可修改。" + +- "内部流程已启动的订单修改后会通知定制师,返回message中包含提示") ++ "内部流程已启动的订单修改后会通知定制师,返回message中包含提示\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @PutMapping("/{orderId}/edit") + public Result userEditOrder(@RequestParam Long userId, + @PathVariable Long orderId, +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java +index db0d1cc..8e4b990 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalMpTripController.java +@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】小程序行程(Feign调用)") ++@Api(tags = "【内部接口】小程序行程(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/trip") + @RequiredArgsConstructor +@@ -18,20 +18,29 @@ public class InternalMpTripController { + + private final TripService tripService; + +- @ApiOperation("行程列表") ++ @ApiOperation(value = "行程列表", notes = "返回用户所有有效订单的行程概要列表(已确认/待出发/出行中/已完成),按出发日期排序\n\n" + ++ "**关联字典**:\n" + ++ "- order_status(订单状态,返回字段status):CONFIRMED=已确认, PENDING_DEPARTURE=待出发, TRAVELLING=出行中, COMPLETED=已完成\n" + ++ "- trip_phase(行程阶段,返回字段tripPhase):BEFORE_START=出发前, IN_PROGRESS=出行中, ENDED=已结束") + @GetMapping("/list") + public Result>> getTripList(@RequestParam Long userId) { + return Result.success(tripService.getTripList(userId)); + } + +- @ApiOperation("行程详情") ++ @ApiOperation(value = "行程详情", notes = "返回订单的完整行程信息,包括每日行程节点、酒店安排、车辆安排、天气预报等\n\n" + ++ "**关联字典**:\n" + ++ "- order_status(订单状态,返回字段status):CONFIRMED=已确认, PENDING_DEPARTURE=待出发, TRAVELLING=出行中, COMPLETED=已完成\n" + ++ "- trip_phase(行程阶段,返回字段tripPhase):BEFORE_START=出发前, IN_PROGRESS=出行中, ENDED=已结束") + @GetMapping("/{orderId}") + public Result> getTripDetail(@RequestParam Long userId, + @PathVariable Long orderId) { + return Result.success(tripService.getTripDetail(userId, orderId)); + } + +- @ApiOperation("今日行程") ++ @ApiOperation(value = "今日行程", notes = "返回用户今天的行程安排。如果今天有正在出行的订单,返回当天的行程节点和安排;否则返回null\n\n" + ++ "**关联字典**:\n" + ++ "- order_status(订单状态,返回字段status):CONFIRMED=已确认, PENDING_DEPARTURE=待出发, TRAVELLING=出行中, COMPLETED=已完成\n" + ++ "- trip_phase(行程阶段,返回字段tripPhase):BEFORE_START=出发前, IN_PROGRESS=出行中, ENDED=已结束") + @GetMapping("/today") + public Result> getTodayTrip(@RequestParam Long userId) { + Map trip = tripService.getTodayTrip(userId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java +index 887cf27..38d3022 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderStatsController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; + + import javax.validation.Valid; + +-@Api(tags = "内部-订单统计") ++@Api(tags = "内部-订单统计", hidden = true) + @RestController + @RequestMapping("/internal/mp/order") + @RequiredArgsConstructor +@@ -21,19 +21,24 @@ public class InternalOrderStatsController { + private final OrderService orderService; + private final InvoiceService invoiceService; + +- @ApiOperation("获取产品已购出行人总数") ++ @ApiOperation(value = "获取产品已购出行人总数", notes = "统计指定产品的有效订单(非取消/非退款)出行人总数,用于产品详情页显示'已报名X人'") + @GetMapping("/product-sold-count") + public Result getProductSoldCount(@RequestParam Long productId) { + return Result.success(orderService.getProductSoldCount(productId)); + } + +- @ApiOperation("获取产品参与家庭数") ++ @ApiOperation(value = "获取产品参与家庭数", notes = "统计指定产品的有效订单数(一个订单视为一个家庭),用于产品详情页显示'已有X个家庭参与'") + @GetMapping("/participant-family-count") + public Result getParticipantFamilyCount(@RequestParam Long productId) { + return Result.success(orderService.getParticipantFamilyCount(productId)); + } + +- @ApiOperation("发票换开") ++ @ApiOperation(value = "发票换开", notes = "已开发票更换抬头信息(如个人改企业、更换公司名称等)。\n" + ++ "原发票作废,重新生成新发票\n\n" + ++ "**关联字典**:\n" + ++ "- invoice_title_type(抬头类型,请求/返回字段titleType):PERSONAL=个人, COMPANY=企业\n" + ++ "- invoice_type(发票类型,返回字段invoiceType):NORMAL=普通发票, SPECIAL=专用发票\n" + ++ "- invoice_status(发票状态,返回字段status):PENDING=待开票, ISSUED=已开票, FAILED=开票失败, CANCELLED=已作废") + @PostMapping("/invoice/reissue") + public Result reissueInvoice(@RequestBody @Valid InvoiceReissueRequest request) { + return Result.success(invoiceService.reissueInvoice(request)); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java +index 2b39654..656382a 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalOrderTravelerController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + /** + * Internal API for payment service - 出行人验证 + */ +-@Api(tags = "【内部接口】订单出行人(Feign调用)") ++@Api(tags = "【内部接口】订单出行人(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order/traveler") + @RequiredArgsConstructor +@@ -19,7 +19,11 @@ public class InternalOrderTravelerController { + + private final OrderTravelerService orderTravelerService; + +- @ApiOperation("验证订单出行人信息(供支付服务调用)") ++ @ApiOperation(value = "验证订单出行人信息", notes = "供支付服务在发起支付前调用。验证出行人数量是否满足订单要求、证件信息是否完整。\n" + ++ "返回验证结果,包含是否通过和具体错误信息列表\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 出行人证件类型 → 字典:id_card_type(证件类型)\n" + ++ "- 涉及字段 出行人类型 → 字典:traveler_type(出行人类型)") + @GetMapping("/validate/{orderId}") + public Result validateTravelers(@PathVariable Long orderId) { + TravelerValidationDTO validation = orderTravelerService.validateTravelers(orderId); +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java +index b708e85..be4a57c 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalPaymentOrderController.java +@@ -21,7 +21,7 @@ import java.util.stream.Collectors; + * Internal endpoints for payment-service to call via Feign. + * Not exposed through gateway, no authentication interceptor. + */ +-@Api(tags = "【内部接口】订单-支付/合同/保险(Feign调用)") ++@Api(tags = "【内部接口】订单-支付/合同/保险(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order") + @RequiredArgsConstructor +@@ -30,13 +30,16 @@ public class InternalPaymentOrderController { + private final OrderService orderService; + private final OrderTodoService orderTodoService; + +- @ApiOperation("获取订单支付信息") ++ @ApiOperation(value = "获取订单支付信息", notes = "供支付服务调用。返回订单号、应付金额、定金金额、已付金额等支付所需信息") + @GetMapping("/{orderId}/pay-info") + public Result getPayInfo(@PathVariable Long orderId) { + return Result.success(orderService.getPayInfo(orderId)); + } + +- @ApiOperation("通知支付成功") ++ @ApiOperation(value = "通知支付成功", notes = "支付服务收到微信支付回调后调用。更新订单状态(PENDING_PAY→DEPOSIT_PAID/PAID)和已付金额。\n" + ++ "幂等处理:重复调用不会重复更新\n\n" + ++ "【关联字典】\n" + ++ "- 涉及字段 订单status → 字典:order_status(订单状态)") + @PostMapping("/payment-result") + public Result notifyPaymentResult(@RequestBody PaymentResultDTO dto) { + orderService.handlePaymentSuccess(dto.getOrderId(), dto.getPayType(), +@@ -44,14 +47,16 @@ public class InternalPaymentOrderController { + return Result.success(); + } + +- @ApiOperation("通知退款成功") ++ @ApiOperation(value = "通知退款成功", notes = "支付服务收到微信退款回调后调用。更新订单已退金额,若全额退款则将订单状态改为已退款(REFUNDED)") + @PostMapping("/refund-result") + public Result notifyRefundResult(@RequestBody RefundResultDTO dto) { + orderService.handleRefundSuccess(dto.getOrderId(), dto.getRefundAmount()); + return Result.success(); + } + +- @ApiOperation("获取订单基本信息(供合同服务调用)") ++ @ApiOperation(value = "获取订单基本信息(供合同服务调用)", notes = "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/{orderId}/basic") + public Result> getOrderBasic(@PathVariable Long orderId) { + OrderInfo order = orderService.getById(orderId); +@@ -80,7 +85,8 @@ public class InternalPaymentOrderController { + return Result.success(data); + } + +- @ApiOperation("获取用户订单ID列表(供合同服务调用)") ++ @ApiOperation(value = "获取用户订单ID列表(供合同服务调用)", ++ notes = "内部服务间调用。返回指定用户的所有订单ID列表,供合同服务查询用户关联合同时使用。") + @GetMapping("/ids-by-user") + public Result> getOrderIdsByUser(@RequestParam Long userId) { + List orders = orderService.list( +@@ -94,7 +100,8 @@ public class InternalPaymentOrderController { + return Result.success(ids); + } + +- @ApiOperation("完成待办项(供合同/保险服务调用)") ++ @ApiOperation(value = "完成待办项(供合同/保险服务调用)", ++ notes = "内部服务间调用。合同服务签约完成或保险服务投保完成后调用此接口,将对应待办标记为已完成。系统自动检查是否所有必要待办已完成并推进内部流程。") + @PostMapping("/{orderId}/complete-todo/{todoType}") + public Result completeTodoByType(@PathVariable Long orderId, + @PathVariable String todoType) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java +index 2464f08..f7c334f 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/InternalRefundController.java +@@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*; + import javax.validation.Valid; + import java.util.List; + +-@Api(tags = "【内部接口】退款(Feign调用)") ++@Api(tags = "【内部接口】退款(Feign调用)", hidden = true) + @RestController + @RequiredArgsConstructor + public class InternalRefundController { +@@ -27,20 +27,26 @@ public class InternalRefundController { + + // ==================== C-end (BFF → order-service) ==================== + +- @ApiOperation(value = "退款金额预览", notes = "退款预览:根据退款政策和距出发天数,计算可退金额和退款比例") ++ @ApiOperation(value = "退款金额预览", notes = "退款预览:根据退款政策和距出发天数,计算可退金额和退款比例\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 refundType → 字典:refund_type(退款类型)") + @GetMapping("/internal/mp/order/{orderId}/refund-preview") + public Result preview(@RequestParam("userId") Long userId, + @PathVariable Long orderId) { + return Result.success(refundApplicationService.previewRefund(orderId, userId)); + } + +- @ApiOperation("退款原因列表") ++ @ApiOperation(value = "退款原因列表(C端)", notes = "返回启用中的退款原因选项,供C端用户申请退款时选择\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 category → 字典:refund_reason_category(退款原因分类)") + @GetMapping("/internal/mp/order/refund-reasons") + public Result> listReasons() { + return Result.success(refundReasonService.listReasons(true)); + } + +- @ApiOperation(value = "提交退款申请", notes = "退款申请流程:用户选择退款原因 → 填写退款说明 → 系统根据退款政策计算可退金额 → 生成退款申请(PENDING状态) → 等待管理员审批") ++ @ApiOperation(value = "提交退款申请", notes = "退款申请流程:用户选择退款原因 → 填写退款说明 → 系统根据退款政策计算可退金额 → 生成退款申请(PENDING状态) → 等待管理员审批\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @PostMapping("/internal/mp/order/{orderId}/refund") + public Result apply(@RequestParam("userId") Long userId, + @RequestParam(value = "userName", required = false) String userName, +@@ -49,14 +55,18 @@ public class InternalRefundController { + return Result.success(refundApplicationService.apply(orderId, userId, userName, request)); + } + +- @ApiOperation("退款申请详情") ++ @ApiOperation(value = "退款申请详情(C端)", notes = "返回退款申请信息,仅允许查看自己的退款申请\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/internal/mp/order/refund/{applicationId}") + public Result getDetail(@RequestParam("userId") Long userId, + @PathVariable Long applicationId) { + return Result.success(refundApplicationService.getDetailForUser(applicationId, userId)); + } + +- @ApiOperation("根据订单ID获取最新退款申请详情") ++ @ApiOperation(value = "根据订单ID获取最新退款申请", notes = "返回订单关联的最新一条退款申请,用于订单详情页展示退款进度。无退款申请时返回null\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:refund_status(退款状态)") + @GetMapping("/internal/mp/order/{orderId}/refund-detail") + public Result getDetailByOrder(@RequestParam("userId") Long userId, + @PathVariable Long orderId) { +@@ -72,7 +82,7 @@ public class InternalRefundController { + return Result.success(refundApplicationService.appeal(applicationId, userId, request)); + } + +- @ApiOperation("撤回退款申请") ++ @ApiOperation(value = "撤回退款申请", notes = "用户主动撤回退款申请。仅在待审批(PENDING)状态下可撤回。撤回后订单恢复原状态") + @PostMapping("/internal/mp/order/refund/{applicationId}/cancel") + public Result cancel(@RequestParam("userId") Long userId, + @PathVariable Long applicationId) { +@@ -82,16 +92,18 @@ public class InternalRefundController { + + // ==================== Approval callback ==================== + +- @ApiOperation("企微退款申诉审批结果回调") ++ @ApiOperation(value = "企微退款申诉审批结果回调", notes = "企微OA审批完成后由callback-service调用。\n" + ++ "审批通过则退款申请状态变为APPEAL_APPROVED,等待管理员确认实退金额后执行退款") + @PostMapping("/internal/order/refund-appeal-result") +- public Result handleRefundAppealResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleRefundAppealResult(@RequestBody ApprovalResultDTO dto) { + refundApplicationService.handleAppealResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); + } + +- @ApiOperation("企微退款申请审批结果回调") ++ @ApiOperation(value = "企微退款申请审批结果回调", notes = "企微OA审批完成后由callback-service调用。\n" + ++ "审批通过则自动执行微信退款,审批拒绝则退款申请状态变为REJECTED") + @PostMapping("/internal/order/refund-application-result") +- public Result handleRefundApplicationResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleRefundApplicationResult(@RequestBody ApprovalResultDTO dto) { + refundApplicationService.handleApplicationApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java +index f29e8f9..9b3806e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/MpOrderController.java +@@ -35,7 +35,13 @@ public class MpOrderController { + private static final String ORDER_CREATE_DEDUP = "order:create:dedup:"; + + @ApiOperation(value = "创建订单", notes = "C端下单流程:选择产品 → 填写联系人信息和出行人 → 系统报价 → 生成订单(PENDING_PAY状态)\n\n" + +- "联系人和出行人是独立概念,联系人不必是出行人之一") ++ "联系人和出行人是独立概念,联系人不必是出行人之一\n\n" + ++ "【关联字典】\n" + ++ "- 请求参数 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 请求参数 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 请求参数 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @PostMapping("/create") + public Result createOrder(HttpServletRequest request, + @ApiParam("创建订单请求") @Valid @RequestBody CreateOrderRequest createRequest) { +@@ -55,7 +61,12 @@ public class MpOrderController { + } + } + +- @ApiOperation("我的订单列表") ++ @ApiOperation(value = "我的订单列表", notes = "查询当前用户的订单列表,支持按状态筛选。\n" + ++ "用户需先完善个人资料(realName)后才能看到订单\n\n" + ++ "【关联字典】\n" + ++ "- 筛选参数 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)") + @GetMapping("/list") + public Result> listOrders(HttpServletRequest request, + @ApiParam("订单查询请求") MpOrderQueryRequest queryRequest) { +@@ -64,7 +75,15 @@ public class MpOrderController { + return Result.success(result); + } + +- @ApiOperation("订单详情") ++ @ApiOperation(value = "订单详情", notes = "获取订单完整信息。仅能查看自己的订单,查看他人订单会返回权限错误\n\n" + ++ "【关联字典】\n" + ++ "- 返回字段 status → 字典:order_status(订单状态)\n" + ++ "- 返回字段 processStatus → 字典:order_process_status(订单内部流程状态)\n" + ++ "- 返回字段 productType → 字典:product_type(产品类型)\n" + ++ "- 返回字段 travelers[].travelerType → 字典:traveler_type(出行人类型)\n" + ++ "- 返回字段 travelers[].idCardType → 字典:id_card_type(证件类型)\n" + ++ "- 返回字段 travelers[].gender → 字典:gender(性别)\n" + ++ "- 返回字段 timeline[].action → 字典:order_timeline_action(订单操作类型)") + @GetMapping("/{orderId}") + public Result getOrder(HttpServletRequest request, + @ApiParam("订单ID") @PathVariable Long orderId) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java b/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java +index 9e92157..1df079f 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/controller/MpWeatherController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "内部天气接口(Feign)") ++@Api(tags = "内部天气接口(Feign)", hidden = true) + @RestController + @RequestMapping("/internal/mp/weather") + @RequiredArgsConstructor +@@ -20,21 +20,21 @@ public class MpWeatherController { + + private final WeatherService weatherService; + +- @ApiOperation("获取订单行程天气") ++ @ApiOperation(value = "获取订单行程天气", notes = "根据订单行程中的城市和日期,批量查询天气信息。返回每天每个城市的天气数据列表") + @GetMapping("/itinerary/{orderId}") + public Result>> getItineraryWeather( + @ApiParam("订单ID") @PathVariable Long orderId) { + return Result.success(weatherService.getItineraryWeather(orderId)); + } + +- @ApiOperation("获取指定城市实况天气") ++ @ApiOperation(value = "获取指定城市实况天气", notes = "调用高德天气API查询城市实时天气(温度、湿度、风向等),结果缓存30分钟") + @GetMapping("/live") + public Result getLiveWeather( + @ApiParam("城市名称") @RequestParam String city) { + return Result.success(weatherService.getLiveWeather(city)); + } + +- @ApiOperation("获取指定城市天气预报") ++ @ApiOperation(value = "获取指定城市天气预报", notes = "调用高德天气API查询城市未来3天天气预报,结果缓存2小时") + @GetMapping("/forecast") + public Result getForecastWeather( + @ApiParam("城市名称") @RequestParam String city) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java +index 8fb0223..48d0a18 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminCreateOrderRequest.java +@@ -35,7 +35,7 @@ public class AdminCreateOrderRequest { + @Min(value = 0) + private int babyCount = 0; + +- @ApiModelProperty(value = "儿童是否需要床位", example = "false") ++ @ApiModelProperty(value = "儿童是否需要床位(影响房间分配和报价计算)", example = "false") + private Boolean childNeedBed = false; + + @ApiModelProperty(value = "团期ID(GROUP产品必填)") +@@ -59,14 +59,14 @@ public class AdminCreateOrderRequest { + @Size(max = 500, message = "备注不能超过500个字符") + private String remark; + +- @ApiModelProperty(value = "用户手机号(可选,用于关联C端用户)", example = "13800138000") ++ @ApiModelProperty(value = "用户手机号(可选,用于关联C端用户)。如匹配到已注册用户则自动绑定订单", example = "13800138000") + @Size(max = 20) + private String userPhone; + + @ApiModelProperty(value = "定制师ID(可选,默认为创建人)", example = "1760000000000010") + private Long customizerId; + +- @ApiModelProperty(value = "支付时限(分钟),不传则使用全局默认值", example = "30") ++ @ApiModelProperty(value = "支付时限(分钟),不传则使用全局默认值。超时未支付订单自动取消", example = "30") + @Min(value = 1, message = "支付时限最少1分钟") + @Max(value = 1440, message = "支付时限最多1440分钟") + private Integer expiryMinutes; +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java +index dfdbe7d..3eb5db1 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminRefundReviewRequest.java +@@ -11,11 +11,11 @@ import java.math.BigDecimal; + @Data + @ApiModel("管理员退款审批请求") + public class AdminRefundReviewRequest { +- @ApiModelProperty(value = "审批结果(APPROVE/REJECT)", required = true, example = "APPROVE") ++ @ApiModelProperty(value = "审批结果:APPROVE=通过(自动调起微信退款)、REJECT=拒绝(用户可发起申诉)", required = true, example = "APPROVE") + @NotBlank(message = "审批结果不能为空") + private String action; + +- @ApiModelProperty(value = "实际退款金额(审批通过时可调整)", example = "1500.00") ++ @ApiModelProperty(value = "实际退款金额(审批通过时可调整,不传则使用申请金额)。不能超过订单已付金额", example = "1500.00") + private BigDecimal actualAmount; + + @ApiModelProperty(value = "审批备注", example = "同意全额退款") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java +index 2d1c10e..44a424e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/AdminUpdateOrderRequest.java +@@ -44,7 +44,7 @@ public class AdminUpdateOrderRequest { + @Min(value = 0, message = "幼童数不能为负") + private Integer babyCount; + +- @ApiModelProperty(value = "商户号", example = "1246532201") ++ @ApiModelProperty(value = "商户号(微信支付商户号,多商户场景使用)", example = "1246532201") + @Size(max = 32, message = "商户号不能超过32个字符") + private String mchId; + +@@ -62,6 +62,6 @@ public class AdminUpdateOrderRequest { + + // Note: discount is now managed via separate discount CRUD endpoints (POST/PUT/DELETE /admin/order/{orderId}/discount) + +- @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人)") ++ @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人,不传则不修改出行人)") + private List travelers; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java +index aeb8c8c..b984863 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/CreateWorkOrderRequest.java +@@ -13,11 +13,12 @@ public class CreateWorkOrderRequest { + @NotNull(message = "订单ID不能为空") + private Long orderId; + +- @ApiModelProperty(value = "工单类型: ROOM_CHANGE/ROOM_ADD/CHECKOUT_CHANGE/HOTEL_ISSUE/VEHICLE_CHANGE/SCENIC_ADD/SCENIC_REMOVE/OTHER", required = true) ++ @ApiModelProperty(value = "工单类型: ROOM_CHANGE(换房)/ROOM_ADD(加房)/CHECKOUT_CHANGE(改退房日期)/" + ++ "HOTEL_ISSUE(酒店问题)/VEHICLE_CHANGE(换车)/SCENIC_ADD(加景点)/SCENIC_REMOVE(减景点)/OTHER(其他)", required = true) + @NotBlank(message = "工单类型不能为空") + private String type; + +- @ApiModelProperty(value = "优先级: URGENT/NORMAL", required = true) ++ @ApiModelProperty(value = "优先级: URGENT(紧急,如当天出发需处理)/NORMAL(普通)", required = true) + @NotBlank(message = "优先级不能为空") + private String priority; + +@@ -31,7 +32,7 @@ public class CreateWorkOrderRequest { + @ApiModelProperty("资源详情JSON(酒店/车辆/景点信息)") + private String resourceDetail; + +- @ApiModelProperty("差价(正数=加价, 负数=退费)") ++ @ApiModelProperty("差价(正数=客户需补差价, 负数=需退费给客户)") + private BigDecimal costDifference; + + @ApiModelProperty("指定处理人ID") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java +index f2f451c..a678aff 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/EarlyBirdPlanRequest.java +@@ -24,12 +24,12 @@ public class EarlyBirdPlanRequest { + @NotNull(message = "生效结束日期不能为空") + private LocalDate endDate; + +- @ApiModelProperty(value = "最低人数", required = true, example = "2") ++ @ApiModelProperty(value = "最低出行人数(含成人+儿童),订单人数>=此值才能享受优惠", required = true, example = "2") + @NotNull(message = "最低人数不能为空") + @Min(value = 1, message = "最低人数至少为1") + private Integer minPeople; + +- @ApiModelProperty(value = "优惠金额", required = true, example = "200.00") ++ @ApiModelProperty(value = "优惠金额(从订单总价中扣减的固定金额)", required = true, example = "200.00") + @NotNull(message = "优惠金额不能为空") + @DecimalMin(value = "0.01", message = "优惠金额必须大于0") + private BigDecimal discountAmount; +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java +index 125cd6a..9a93336 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/InvoiceApplyRequest.java +@@ -13,7 +13,7 @@ public class InvoiceApplyRequest { + @NotNull(message = "orderId is required") + private Long orderId; + +- @ApiModelProperty(value = "抬头类型(personal=个人/company=企业)", example = "personal") ++ @ApiModelProperty(value = "抬头类型:personal=个人(默认)、company=企业(需填写税号)", example = "personal") + private String titleType = "personal"; + + @ApiModelProperty(value = "发票抬头", required = true, example = "张三") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java +index 98b28d5..c28453b 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/MpOrderQueryRequest.java +@@ -10,7 +10,7 @@ import javax.validation.constraints.Min; + @Data + @ApiModel("C端订单查询请求") + public class MpOrderQueryRequest { +- @ApiModelProperty(value = "订单状态", example = "PAID") ++ @ApiModelProperty(value = "订单状态(不传则查全部)。可选值:PENDING_PAY/DEPOSIT_PAID/PAID/CONFIRMED/PENDING_BALANCE/PENDING_DEPARTURE/TRAVELLING/COMPLETED/AFTER_SALE/REFUNDING/REFUNDED/CANCELLED", example = "PAID") + private String status; + + @ApiModelProperty(value = "页码", example = "1") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java +index 9782f64..0b13f71 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/MpUpdateOrderRequest.java +@@ -9,12 +9,12 @@ import java.time.LocalDate; + import java.util.List; + + @Data +-@ApiModel("小程序修改订单请求") ++@ApiModel(value = "小程序修改订单请求", description = "用户可修改出发日期和出行人。修改后系统自动重算价格,内部流程已启动的订单会通知定制师") + public class MpUpdateOrderRequest { + +- @ApiModelProperty(value = "出发日期", example = "2026-05-01") ++ @ApiModelProperty(value = "出发日期(修改出发日期会触发价格重算)", example = "2026-05-01") + private LocalDate departureDate; + +- @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人)") ++ @ApiModelProperty(value = "出行人列表(如提供则替换全部出行人,不传则不修改出行人)") + private List travelers; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java +index 4d8aa75..7c32a24 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundApplyRequest.java +@@ -11,11 +11,11 @@ import javax.validation.constraints.Size; + @Data + @ApiModel("退款申请请求") + public class RefundApplyRequest { +- @ApiModelProperty(value = "退款类型(字典:refund_type)", required = true, example = "FULL") ++ @ApiModelProperty(value = "退款类型:FULL=全额退款、PARTIAL=部分退款", required = true, example = "FULL") + @NotBlank(message = "退款类型不能为空") + private String refundType; + +- @ApiModelProperty(value = "退款原因ID", example = "1760000000000001") ++ @ApiModelProperty(value = "退款原因ID(从退款原因列表接口获取)", example = "1760000000000001") + private Long reasonId; + + @ApiModelProperty(value = "退款原因", required = true, example = "行程有变,无法出行") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java +index cb0873c..a6a18a7 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/RefundPolicyRequest.java +@@ -42,12 +42,12 @@ public class RefundPolicyRequest { + @Data + @ApiModel("退款规则项") + public static class RuleItem { +- @ApiModelProperty(value = "距出发最少天数", required = true, example = "7") ++ @ApiModelProperty(value = "距出发最少天数(含当天)。例如:minDays=7表示出发前7天及以上适用此规则", required = true, example = "7") + @NotNull(message = "最少天数不能为空") + @Min(value = 0, message = "最少天数不能小于0") + private Integer minDays; + +- @ApiModelProperty(value = "退款比例(百分比)", required = true, example = "80") ++ @ApiModelProperty(value = "退款比例(百分比,0-100)。例如:80表示退已付金额的80%", required = true, example = "80") + @NotNull(message = "退款比例不能为空") + @Min(value = 0, message = "退款比例不能小于0") + @Max(value = 100, message = "退款比例不能超过100") +``` + +### `hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java b/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java +index f290109..c40fb91 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/dto/UpdateOrderStatusRequest.java +@@ -9,7 +9,10 @@ import javax.validation.constraints.NotBlank; + @Data + @ApiModel("更新订单状态请求") + public class UpdateOrderStatusRequest { +- @ApiModelProperty(value = "目标状态(字典:order_status)", required = true, example = "CONFIRMED") ++ @ApiModelProperty(value = "目标状态。可选值:PENDING_PAY(待支付)/DEPOSIT_PAID(已付定金)/PAID(已全额支付)/" + ++ "CONFIRMED(已确认)/PENDING_BALANCE(待付尾款)/PENDING_DEPARTURE(待出行)/" + ++ "TRAVELLING(旅行中)/COMPLETED(已完成)/AFTER_SALE(售后中)/REFUNDING(退款中)/" + ++ "REFUNDED(已退款)/CANCELLED(已取消)", required = true, example = "CONFIRMED") + @NotBlank(message = "状态不能为空") + private String status; + } +``` + +### `hl-order-service/src/main/java/com/hulalv/order/service/WeatherService.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/service/WeatherService.java b/hl-order-service/src/main/java/com/hulalv/order/service/WeatherService.java +index 74d4a55..f5b652e 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/service/WeatherService.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/service/WeatherService.java +@@ -127,7 +127,11 @@ public class WeatherService { + * 获取指定城市的天气预报(带缓存) + */ + public WeatherInfo getCachedForecast(String cityName) { +- if (!StringUtils.hasText(cityName) || !StringUtils.hasText(amapKey)) { ++ if (!StringUtils.hasText(amapKey)) { ++ log.error("天气服务未配置: amap.key为空"); ++ return null; ++ } ++ if (!StringUtils.hasText(cityName)) { + return null; + } + String cacheKey = WEATHER_CACHE_PREFIX + cityName; +@@ -141,7 +145,10 @@ public class WeatherService { + } + + String adcode = getCachedAdcode(cityName); +- if (adcode == null) return null; ++ if (adcode == null) { ++ log.warn("无法获取城市adcode: city={}, 可能是城市名不正确或API Key无效", cityName); ++ return null; ++ } + + WeatherInfo weather = amapWeatherClient.getForecastWeather(adcode, amapKey); + if (weather != null) { +``` + +### `hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java` (M) + +```diff +diff --git a/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java b/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java +index 58106e0..f6bcd64 100644 +--- a/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java ++++ b/hl-order-service/src/main/java/com/hulalv/order/vo/WorkOrderVO.java +@@ -82,12 +82,24 @@ public class WorkOrderVO { + private List logs; + + @Data ++ @io.swagger.annotations.ApiModel("工单操作日志VO") + public static class WorkOrderLogVO { ++ @ApiModelProperty("日志ID") + private String logId; ++ ++ @ApiModelProperty("操作动作") + private String action; ++ ++ @ApiModelProperty("操作动作标签") + private String actionLabel; ++ ++ @ApiModelProperty("操作内容") + private String content; ++ ++ @ApiModelProperty("操作人姓名") + private String operatorName; ++ ++ @ApiModelProperty("操作时间") + private LocalDateTime createdAt; + } + } +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/config/Knife4jConfig.java b/hl-payment-service/src/main/java/com/hulalv/payment/config/Knife4jConfig.java +index 35ae74b..be0e684 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/config/Knife4jConfig.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.payment.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.spi.DocumentationType; + import springfox.documentation.spring.web.plugins.Docket; +@@ -11,6 +11,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket paymentApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -22,7 +27,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.payment.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java` (M) + +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java b/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java +index 3392e72..10a9ea4 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/controller/AdminPaymentController.java +@@ -27,13 +27,13 @@ public class AdminPaymentController { + private final RefundService refundService; + + @GetMapping("/list") +- @ApiOperation(value = "支付交易列表", notes = "分页查询支付交易记录,支持按订单号、交易状态、交易类型筛选") ++ @ApiOperation(value = "支付交易列表", notes = "分页查询支付交易记录,支持按订单号、交易状态、交易类型筛选\n\n**关联字典**:\n- payment_mode:支付模式(列表筛选+显示)") + public Result> listTransactions(@ApiParam("支付查询条件") @Valid PaymentQueryRequest request) { + return Result.success(paymentService.listTransactions(request)); + } + + @GetMapping("/{transactionId}") +- @ApiOperation(value = "交易详情", notes = "获取单笔交易的完整信息,包含微信支付流水号") ++ @ApiOperation(value = "交易详情", notes = "获取单笔交易的完整信息,包含微信支付流水号\n\n**关联字典**:\n- payment_mode:支付模式(显示)") + public Result getDetail(@ApiParam("交易ID") @PathVariable Long transactionId) { + return Result.success(paymentService.getDetail(transactionId)); + } +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java` (M) + +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java b/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java +index d195a48..dbdfc84 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/controller/InternalPaymentController.java +@@ -25,14 +25,14 @@ import java.util.List; + @RestController + @RequestMapping("/internal/payment") + @RequiredArgsConstructor +-@Api(tags = "【内部接口】支付(Feign调用)") ++@Api(tags = "【内部接口】支付(Feign调用)", hidden = true) + public class InternalPaymentController { + + private final PaymentService paymentService; + private final RefundService refundService; + + @PostMapping("/prepay") +- @ApiOperation("Create prepay order (called by BFF)") ++ @ApiOperation(value = "创建预支付订单", notes = "由BFF层调用,向微信支付API发起预支付请求,返回前端调起支付所需的参数(prepay_id等)") + public Result prepay( + @RequestParam("userId") Long userId, + @Valid @RequestBody PrepayRequest request) { +@@ -41,7 +41,7 @@ public class InternalPaymentController { + } + + @GetMapping("/status/{orderId}") +- @ApiOperation("Query payment status (called by BFF)") ++ @ApiOperation(value = "查询支付状态", notes = "查询订单的支付状态,含用户权限校验(userId不匹配时拒绝访问)\n\n**关联字典**:\n- payment_status:支付状态(返回字段)") + public Result getStatus(@RequestParam(value = "userId", required = false) Long userId, + @PathVariable Long orderId) { + PaymentVO vo = paymentService.getPaymentStatus(orderId); +@@ -53,7 +53,7 @@ public class InternalPaymentController { + } + + @GetMapping("/transactions/{orderId}") +- @ApiOperation("List all transactions for an order (called by BFF)") ++ @ApiOperation(value = "订单交易记录列表", notes = "查询指定订单的所有支付交易记录(含支付和退款),含用户权限校验\n\n**关联字典**:\n- payment_status:支付状态(返回字段)") + public Result> listTransactions(@RequestParam(value = "userId", required = false) Long userId, + @PathVariable Long orderId) { + List list = paymentService.listByOrder(orderId); +@@ -67,7 +67,7 @@ public class InternalPaymentController { + } + + @PostMapping("/refund") +- @ApiOperation("Create refund (called by order-service)") ++ @ApiOperation(value = "创建退款", notes = "由订单服务调用,向微信支付API发起退款请求。退款金额不能超过原支付金额,退款结果通过微信回调异步通知") + public Result createRefund(@Valid @RequestBody PaymentRefundRequest refundRequest) { + RefundRequest request = new RefundRequest(); + request.setOrderId(refundRequest.getOrderId()); +``` + +### `hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java` (M) + +```diff +diff --git a/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java b/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java +index d950113..8b8106b 100644 +--- a/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java ++++ b/hl-payment-service/src/main/java/com/hulalv/payment/controller/PaymentCallbackController.java +@@ -23,14 +23,14 @@ import java.util.Map; + @RestController + @RequestMapping("/pay/callback") + @RequiredArgsConstructor +-@Api(tags = "【回调接口】支付回调") ++@Api(tags = "【回调接口】支付回调", hidden = true) + public class PaymentCallbackController { + + private final PaymentService paymentService; + private final RefundService refundService; + + @PostMapping("/notify/{mchId}") +- @ApiOperation("支付成功回调") ++ @ApiOperation(value = "支付成功回调", notes = "微信支付成功后的异步通知回调(无需认证,通过微信签名验证安全性)。验证签名 → 更新支付状态 → 发送MQ消息通知订单服务") + public ResponseEntity> payNotify( + @PathVariable String mchId, + HttpServletRequest request) { +@@ -49,7 +49,7 @@ public class PaymentCallbackController { + } + + @PostMapping("/refund-notify/{mchId}") +- @ApiOperation("退款回调") ++ @ApiOperation(value = "退款回调", notes = "微信退款结果的异步通知回调(无需认证,通过微信签名验证安全性)。验证签名 → 更新退款状态 → 发送MQ消息通知订单服务") + public ResponseEntity> refundNotify( + @PathVariable String mchId, + HttpServletRequest request) { +``` + +### `hl-product-service/src/main/java/com/hulalv/product/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/config/Knife4jConfig.java b/hl-product-service/src/main/java/com/hulalv/product/config/Knife4jConfig.java +index 746c86e..f483fa8 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/config/Knife4jConfig.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/config/Knife4jConfig.java +@@ -1,9 +1,9 @@ + package com.hulalv.product.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +-import springfox.documentation.builders.PathSelectors; + import springfox.documentation.builders.RequestHandlerSelectors; + import springfox.documentation.spi.DocumentationType; + import springfox.documentation.spring.web.plugins.Docket; +@@ -11,6 +11,11 @@ import springfox.documentation.spring.web.plugins.Docket; + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口和回调接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + @Bean + public Docket productApi() { + return new Docket(DocumentationType.SWAGGER_2) +@@ -22,7 +27,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.product.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java +index 3d92709..5a21261 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/DistrictController.java +@@ -21,7 +21,12 @@ public class DistrictController { + + private final AmapDistrictService amapDistrictService; + +- @ApiOperation("搜索行政区划(城市/区县)") ++ @ApiOperation(value = "搜索行政区划(城市/区县)", ++ notes = "通过高德地图 API 搜索行政区划,用于产品的出发城市和目的地城市选择。\n" ++ + "输入关键词(如\"丽江\"、\"昆明\"),返回匹配的城市/区县列表,包含行政区划编码。\n\n" ++ + "**关联字典**:\n" ++ + "- cities(城市):搜索结果可用于产品行程中的城市预览\n" ++ + "- city(城市筛选):搜索结果可用于资源面板城市筛选") + @GetMapping("/search") + public Result> search( + @ApiParam("搜索关键词") @RequestParam String keywords) { +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java +index b1bba5b..8e8827f 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/FamilyController.java +@@ -21,13 +21,19 @@ public class FamilyController { + + private final ProductFamilyService familyService; + +- @ApiOperation("获取家庭分组列表") ++ @ApiOperation(value = "获取家庭分组列表", ++ notes = "获取产品的家庭分组列表,按排序序号升序。\n\n" ++ + "**仅适用于 CUSTOM(定制)产品**。\n" ++ + "家庭分组用于将定制产品的行程按家庭单位分配,每个家庭可以有不同的人数和行程安排。\n" ++ + "行程节点通过 familyIds 字段关联到具体的家庭分组。") + @GetMapping("/families") + public Result> listFamilies(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(familyService.listFamilies(productId)); + } + +- @ApiOperation("添加家庭分组") ++ @ApiOperation(value = "添加家庭分组", ++ notes = "为 CUSTOM 定制产品添加一个家庭分组,指定家庭名称和各类型人数。\n" ++ + "添加后可在行程节点中关联此家庭,实现按家庭分配行程。") + @PostMapping("/family") + public Result addFamily( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -35,7 +41,9 @@ public class FamilyController { + return Result.success(familyService.addFamily(productId, request)); + } + +- @ApiOperation("更新家庭分组") ++ @ApiOperation(value = "更新家庭分组", ++ notes = "更新家庭分组的名称、各类型人数等信息。\n" ++ + "**仅适用于 CUSTOM(定制)产品**。") + @PutMapping("/family/{familyId}") + public Result updateFamily( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -44,7 +52,9 @@ public class FamilyController { + return Result.success(familyService.updateFamily(familyId, request)); + } + +- @ApiOperation("删除家庭分组") ++ @ApiOperation(value = "删除家庭分组", ++ notes = "删除家庭分组。如果有行程节点通过 familyIds 关联了该分组,需要手动移除关联。\n" ++ + "**仅适用于 CUSTOM(定制)产品**。") + @DeleteMapping("/family/{familyId}") + public Result deleteFamily( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java +index 9d4395e..6cc32f3 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/FormulaController.java +@@ -32,20 +32,34 @@ public class FormulaController { + + // ===== Group endpoints ===== + +- @ApiOperation("公式组列表") ++ @ApiOperation(value = "公式组列表", ++ notes = "获取定价公式组列表,可按产品类型筛选。\n\n" ++ + "**公式引擎说明**:定价公式用于自动计算产品的成本价和售价。\n" ++ + "每种产品类型可以有多个公式组,但同一时间只能有一个激活的公式组。\n" ++ + "公式组包含多个步骤,按顺序执行,每步计算一个中间变量或最终结果。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选条件):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/group/list") + public Result> listGroups( + @RequestParam(required = false) String productType) { + return Result.success(groupService.listGroups(productType)); + } + +- @ApiOperation("公式组详情") ++ @ApiOperation(value = "公式组详情", ++ notes = "获取公式组完整信息。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/group/{groupId}") + public Result getGroup(@PathVariable Long groupId) { + return Result.success(groupService.getGroup(groupId)); + } + +- @ApiOperation("创建公式组") ++ @ApiOperation(value = "创建公式组", ++ notes = "创建一个新的定价公式组。创建后默认为未激活状态。\n\n" ++ + "公式组编码(groupCode)在同一产品类型下必须唯一。\n" ++ + "建议命名规范:{产品类型}_PRICING_V{版本号},如 CORE_PRICING_V2。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,公式组所属类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/group") + public Result createGroup(@Valid @RequestBody FormulaGroupRequest request, + HttpServletRequest httpRequest) { +@@ -53,21 +67,31 @@ public class FormulaController { + return Result.success(groupService.createGroup(request, adminId)); + } + +- @ApiOperation("更新公式组") ++ @ApiOperation(value = "更新公式组", ++ notes = "更新公式组信息。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PutMapping("/group/{groupId}") + public Result updateGroup(@PathVariable Long groupId, + @Valid @RequestBody FormulaGroupRequest request) { + return Result.success(groupService.updateGroup(groupId, request)); + } + +- @ApiOperation("激活公式组") ++ @ApiOperation(value = "激活公式组", ++ notes = "激活指定公式组,同时自动停用同产品类型下的其他公式组。\n\n" ++ + "同一产品类型下只能有一个激活的公式组,激活操作具有排他性。\n" ++ + "激活后,该产品类型的自动成本计算将使用此公式组。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,同类型排他激活):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PutMapping("/group/{groupId}/activate") + public Result activateGroup(@PathVariable Long groupId) { + groupService.activateGroup(groupId); + return Result.success(); + } + +- @ApiOperation("删除公式组") ++ @ApiOperation(value = "删除公式组", ++ notes = "删除公式组及其下所有步骤。\n" ++ + "**限制**:已激活的公式组不能删除,需先激活其他公式组。") + @DeleteMapping("/group/{groupId}") + public Result deleteGroup(@PathVariable Long groupId) { + groupService.deleteGroup(groupId); +@@ -76,25 +100,35 @@ public class FormulaController { + + // ===== Step endpoints ===== + +- @ApiOperation("公式步骤列表") ++ @ApiOperation(value = "公式步骤列表", ++ notes = "获取公式组下所有步骤,按执行顺序(executionOrder)升序排列。\n" ++ + "步骤按顺序依次执行,前一步的输出变量可作为后续步骤的输入。") + @GetMapping("/group/{groupId}/steps") + public Result> listSteps(@PathVariable Long groupId) { + return Result.success(stepService.listSteps(groupId)); + } + +- @ApiOperation("公式步骤详情") ++ @ApiOperation(value = "公式步骤详情", ++ notes = "获取单个公式步骤的完整信息,包含表达式、输入/输出变量、执行顺序等。") + @GetMapping("/step/{formulaId}") + public Result getStep(@PathVariable Long formulaId) { + return Result.success(stepService.getStep(formulaId)); + } + +- @ApiOperation("创建公式步骤") ++ @ApiOperation(value = "创建公式步骤", ++ notes = "在公式组中创建一个计算步骤。\n\n" ++ + "**表达式语法**:使用 Aviator 表达式引擎,支持数学运算、条件判断、内置函数等。\n" ++ + "示例:`baseCost = adultCount * adultUnitCost + childCount * childUnitCost`\n\n" ++ + "**输入变量**:可引用公式变量表中定义的变量,或前置步骤的输出变量。\n" ++ + "**输出变量**:每个步骤必须指定一个输出变量名,供后续步骤引用。") + @PostMapping("/step") + public Result createStep(@Valid @RequestBody FormulaStepRequest request) { + return Result.success(stepService.createStep(request)); + } + +- @ApiOperation("更新公式步骤") ++ @ApiOperation(value = "更新公式步骤", ++ notes = "更新公式步骤的表达式、输入/输出变量等。\n" ++ + "每次更新会自动保存一个版本快照,可通过版本历史接口查看和回滚。") + @PutMapping("/step/{formulaId}") + public Result updateStep(@PathVariable Long formulaId, + @Valid @RequestBody FormulaStepRequest request, +@@ -103,27 +137,36 @@ public class FormulaController { + return Result.success(stepService.updateStep(formulaId, request, adminId)); + } + +- @ApiOperation("启用/禁用公式步骤") ++ @ApiOperation(value = "启用/禁用公式步骤", ++ notes = "切换公式步骤的启用状态。\n" ++ + "禁用的步骤在公式执行时会被跳过,不影响其他步骤的执行。\n" ++ + "适用场景:临时跳过某个计算步骤进行调试或测试。") + @PutMapping("/step/{formulaId}/toggle") + public Result toggleStep(@PathVariable Long formulaId) { + stepService.toggleStep(formulaId); + return Result.success(); + } + +- @ApiOperation("删除公式步骤") ++ @ApiOperation(value = "删除公式步骤", ++ notes = "删除指定的公式步骤。删除后其他步骤的执行顺序不会自动调整。\n" ++ + "**注意**:如果后续步骤引用了被删步骤的输出变量,执行时会报错。") + @DeleteMapping("/step/{formulaId}") + public Result deleteStep(@PathVariable Long formulaId) { + stepService.deleteStep(formulaId); + return Result.success(); + } + +- @ApiOperation("公式步骤版本历史") ++ @ApiOperation(value = "公式步骤版本历史", ++ notes = "获取公式步骤的所有历史版本列表,按版本号倒序。\n" ++ + "每次更新步骤表达式会自动创建新版本,方便追溯和回滚。") + @GetMapping("/step/{formulaId}/versions") + public Result> listVersions(@PathVariable Long formulaId) { + return Result.success(stepService.listVersions(formulaId)); + } + +- @ApiOperation("回滚公式步骤到指定版本") ++ @ApiOperation(value = "回滚公式步骤到指定版本", ++ notes = "将公式步骤回滚到历史版本。\n" ++ + "回滚操作会用历史版本的表达式、变量等覆盖当前内容,并创建一个新的版本记录。") + @PutMapping("/step/{formulaId}/rollback/{versionNum}") + public Result rollbackStep(@PathVariable Long formulaId, + @PathVariable Integer versionNum, +@@ -134,7 +177,11 @@ public class FormulaController { + + // ===== Test endpoint ===== + +- @ApiOperation("测试公式执行") ++ @ApiOperation(value = "测试公式执行", ++ notes = "使用自定义变量值测试公式组的执行结果,不影响任何业务数据。\n\n" ++ + "传入公式组ID和测试变量(变量名→值的映射),返回每个步骤的执行结果。\n" ++ + "适用于公式调试:验证表达式是否正确、计算结果是否符合预期。\n" ++ + "如果某步骤执行出错,会在结果中标明错误信息。") + @PostMapping("/test") + public Result testFormulas(@Valid @RequestBody FormulaTestRequest request) { + return Result.success(testService.testFormulas(request)); +@@ -142,27 +189,41 @@ public class FormulaController { + + // ===== Var endpoints ===== + +- @ApiOperation("公式变量列表") ++ @ApiOperation(value = "公式变量列表", ++ notes = "获取公式变量列表,可按变量分类筛选。\n\n" ++ + "**变量分类**:\n" ++ + "- INPUT:输入变量,从业务数据获取(如成人人数、资源单价)\n" ++ + "- INTERMEDIATE:中间变量,由公式步骤计算得出\n" ++ + "- OUTPUT:输出变量,最终报价结果(如总成本、售价)") + @GetMapping("/var/list") + public Result> listVars( + @RequestParam(required = false) String category) { + return Result.success(varService.listVars(category)); + } + +- @ApiOperation("创建公式变量") ++ @ApiOperation(value = "创建公式变量", ++ notes = "创建公式变量定义。变量名(varName)全局唯一,建议使用驼峰命名。\n" ++ + "可指定适用的产品类型列表(productTypes),为空则适用于所有类型。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,变量适用范围):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/var") + public Result createVar(@Valid @RequestBody FormulaVarRequest request) { + return Result.success(varService.createVar(request)); + } + +- @ApiOperation("更新公式变量") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java +index 7e553dc..ab7b818 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/GroupBatchController.java +@@ -25,7 +25,16 @@ public class GroupBatchController { + + // ===== Batch CRUD ===== + +- @ApiOperation("创建主批次") ++ @ApiOperation(value = "创建主批次", ++ notes = "为 GROUP(小蒙马拼团)产品创建一个团期主批次。\n\n" ++ + "**仅适用于 GROUP 产品类型**。\n" ++ + "每个批次有独立的出发日期、报名截止日期、人数上限。\n" ++ + "创建后状态为 PENDING(待开放),需手动开启报名。\n\n" ++ + "**批次状态流转**:PENDING → ENROLLING(报名中)→ CONFIRMED(已成团)→ CLOSED(已关闭)\n" ++ + "任意报名状态均可被解散(DISBANDED)。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限GROUP):GROUP=小蒙马拼团\n" ++ + "- batch_status(批次状态):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束") + @PostMapping + public Result createBatch(@PathVariable Long productId, + @Valid @RequestBody GroupBatchCreateRequest request, +@@ -34,7 +43,11 @@ public class GroupBatchController { + return Result.success(batchService.createBatch(productId, request, adminId)); + } + +- @ApiOperation("创建子批次(溢出)") ++ @ApiOperation(value = "创建子批次(溢出)", ++ notes = "当主批次人数满员时,创建子批次接收溢出报名。\n\n" ++ + "子批次共享主批次的出发日期和行程,但有独立的人数上限和报名人数。\n" ++ + "适用场景:某团期特别火爆,需要扩容但希望分开管理。\n" ++ + "子批次在列表中显示为主批次的子级节点。") + @PostMapping("/{batchId}/sub-batch") + public Result createSubBatch(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -44,7 +57,9 @@ public class GroupBatchController { + return Result.success(batchService.createSubBatch(batchId, request, adminId)); + } + +- @ApiOperation("更新批次") ++ @ApiOperation(value = "更新批次", ++ notes = "更新批次基本信息。仅传入需要修改的字段。\n" ++ + "已有报名人员的批次修改人数上限时,不能低于已报名人数。") + @PutMapping("/{batchId}") + public Result updateBatch(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -52,20 +67,30 @@ public class GroupBatchController { + return Result.success(batchService.updateBatch(batchId, request)); + } + +- @ApiOperation("删除批次") ++ @ApiOperation(value = "删除批次", ++ notes = "删除批次(软删除)。\n" ++ + "**限制**:已有报名人员的批次不能直接删除,需先解散批次。") + @DeleteMapping("/{batchId}") + public Result deleteBatch(@PathVariable Long productId, @PathVariable Long batchId) { + batchService.deleteBatch(batchId); + return Result.success(); + } + +- @ApiOperation("批次列表(树形)") ++ @ApiOperation(value = "批次列表(树形)", ++ notes = "获取产品所有批次,以树形结构返回(主批次包含子批次列表)。\n" ++ + "按出发日期升序排列,包含每个批次的报名人数和剩余名额。\n\n" ++ + "**关联字典**:\n" ++ + "- batch_status(批次状态,返回字段):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束") + @GetMapping("/list") + public Result> listBatches(@PathVariable Long productId) { + return Result.success(batchService.listBatches(productId)); + } + +- @ApiOperation("批次详情") ++ @ApiOperation(value = "批次详情", ++ notes = "获取单个批次的完整信息,包括批次基本信息、服务人员配置、套餐组合等。\n\n" ++ + "**关联字典**:\n" ++ + "- batch_status(批次状态):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束\n" ++ + "- staff_type(人员类型,服务人员配置):GUIDE=领队, DRIVER=司机, PHOTOGRAPHER=摄影师, ASSISTANT=助理, OTHER=其他") + @GetMapping("/{batchId}") + public Result getBatchDetail(@PathVariable Long productId, + @PathVariable Long batchId) { +@@ -74,21 +99,33 @@ public class GroupBatchController { + + // ===== Status operations ===== + +- @ApiOperation("开启报名(PENDING->ENROLLING)") ++ @ApiOperation(value = "开启报名(PENDING->ENROLLING)", ++ notes = "将批次从 PENDING 状态变更为 ENROLLING(报名中)。\n" ++ + "开启后用户可在小程序端看到该团期并报名。\n" ++ + "前提条件:产品必须已上架(PUBLISHED)。") + @PutMapping("/{batchId}/open") + public Result openEnrollment(@PathVariable Long productId, @PathVariable Long batchId) { + batchService.openEnrollment(batchId); + return Result.success(); + } + +- @ApiOperation("关闭报名(ENROLLING/CONFIRMED->CLOSED)") ++ @ApiOperation(value = "关闭报名(ENROLLING/CONFIRMED->CLOSED)", ++ notes = "关闭批次报名,不再接受新的报名。\n" ++ + "已报名的订单不受影响,仅阻止新增报名。\n" ++ + "适用于报名截止日期到达或手动提前关闭的场景。") + @PutMapping("/{batchId}/close") + public Result closeEnrollment(@PathVariable Long productId, @PathVariable Long batchId) { + batchService.closeEnrollment(batchId); + return Result.success(); + } + +- @ApiOperation("解散批次") ++ @ApiOperation(value = "解散批次", ++ notes = "解散批次并处理已报名的订单。\n\n" ++ + "**重要**:解散操作会触发以下流程:\n" ++ + "1. 批次状态变更为 DISBANDED\n" ++ + "2. 通过 MQ 消息通知订单服务,自动取消该批次下的所有未完成订单\n" ++ + "3. 已支付订单会触发退款流程\n\n" ++ + "必须填写解散原因(如:报名人数不足、行程调整等)。") + @PostMapping("/{batchId}/disband") + public Result disbandBatch(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -103,7 +140,13 @@ public class GroupBatchController { + + // ===== Staff operations ===== + +- @ApiOperation("保存服务人员(全量替换)") ++ @ApiOperation(value = "保存服务人员(全量替换)", ++ notes = "保存批次的服务人员配置,采用全量替换模式(先删后增)。\n\n" ++ + "每次提交完整的人员列表,替换掉该批次原有的所有人员配置。\n" ++ + "人员来源于资源服务的人员库,通过 staffId 关联。\n" ++ + "**角色类型**:LEADER(领队)/PHOTOGRAPHER(摄影师)/DRIVER(司机)/OTHER(其他)\n\n" ++ + "**关联字典**:\n" ++ + "- staff_type(人员类型):GUIDE=领队, DRIVER=司机, PHOTOGRAPHER=摄影师, ASSISTANT=助理, OTHER=其他") + @PostMapping("/{batchId}/staff") + public Result> saveStaff(@PathVariable Long productId, + @PathVariable Long batchId, +@@ -111,14 +154,18 @@ public class GroupBatchController { + return Result.success(staffService.saveStaff(batchId, productId, requests)); + } + +- @ApiOperation("服务人员列表") ++ @ApiOperation(value = "服务人员列表", ++ notes = "**关联字典**:\n" ++ + "- staff_type(人员类型):GUIDE=领队, DRIVER=司机, PHOTOGRAPHER=摄影师, ASSISTANT=助理, OTHER=其他") + @GetMapping("/{batchId}/staff") + public Result> listStaff(@PathVariable Long productId, + @PathVariable Long batchId) { + return Result.success(staffService.listStaff(batchId)); + } + +- @ApiOperation("从其他批次复制服务人员") ++ @ApiOperation(value = "从其他批次复制服务人员", ++ notes = "将源批次的服务人员配置复制到当前批次(全量替换当前批次已有人员)。\n" ++ + "适用场景:多个团期使用相同的服务人员班底。") + @PostMapping("/{batchId}/staff/copy-from/{sourceId}") + public Result> copyStaff(@PathVariable Long productId, + @PathVariable Long batchId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java +index 61d9a75..7a6ea65 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalMpProductController.java +@@ -36,7 +36,7 @@ import java.util.Map; + * C端产品内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】小程序产品(Feign调用)") ++@Api(tags = "【内部接口】小程序产品(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/product") + @RequiredArgsConstructor +@@ -50,39 +50,56 @@ public class InternalMpProductController { + private final ProductPriceCalendarMapper priceCalendarMapper; + private final GroupTourBatchMapper groupTourBatchMapper; + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", ++ notes = "内部Feign接口,返回已上架产品列表。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选+返回字段):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/list") + public Result> listProducts(@Valid MpProductQueryRequest query) { + return Result.success(productService.listPublishedProducts(query)); + } + +- @ApiOperation("产品详情") ++ @ApiOperation(value = "产品详情", ++ notes = "内部Feign接口,返回已上架产品详情。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态):PUBLISHED=已上架\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}") + public Result getProduct(@PathVariable Long productId) { + return Result.success(productService.getPublishedProduct(productId)); + } + +- @ApiOperation("报价计算") ++ @ApiOperation(value = "报价计算", ++ notes = "内部服务间调用,供 hl-mp-service BFF 层 Feign 调用的报价计算接口。\n" ++ + "计算逻辑与管理后台报价一致,根据日期和人数计算总价。") + @PostMapping("/{productId}/quote") + public Result calculateQuote(@PathVariable Long productId, + @Valid @RequestBody QuoteRequest request) { + return Result.success(quoteCalculatorService.calculateQuote(productId, request)); + } + +- @ApiOperation("产品线列表(活跃)") ++ @ApiOperation(value = "产品线列表(活跃)", ++ notes = "内部服务间调用,供 hl-mp-service 获取所有启用的产品线列表,用于小程序端筛选。") + @GetMapping("/lines") + public Result> listActiveLines() { + return Result.success(productLineService.listAllActive()); + } + +- @ApiOperation("推荐产品列表") ++ @ApiOperation(value = "推荐产品列表", ++ notes = "返回推荐的已上架产品。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,返回字段):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/recommend") + public Result> listRecommendProducts( + @RequestParam(defaultValue = "6") int limit) { + return Result.success(productService.listRecommendProducts(limit)); + } + +- @ApiOperation("C端价格日历") ++ @ApiOperation(value = "C端价格日历", ++ notes = "内部服务间调用,供 hl-mp-service 获取产品的价格日历数据。\n\n" ++ + "可通过 startDate/endDate 限定查询范围,不传则返回今天及之后的所有可用日期。\n" ++ + "返回每天的售价和库存信息,供小程序端日历选择器使用。") + @GetMapping("/{productId}/price-calendar") + public Result>> getPriceCalendar( + @PathVariable Long productId, +@@ -91,7 +108,10 @@ public class InternalMpProductController { + return Result.success(priceCalendarService.getMpPriceCalendar(productId, startDate, endDate)); + } + +- @ApiOperation("产品最早可订日期") ++ @ApiOperation(value = "产品最早可订日期", ++ notes = "根据产品类型查询最早可预订日期。GROUP类型查批次出发日期,CORE/CUSTOM类型查价格日历。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响查询逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/earliest-booking-date") + public Result getEarliestBookingDate(@RequestParam Long productId) { + Product product = productMapper.selectById(productId); +@@ -137,7 +157,10 @@ public class InternalMpProductController { + } + } + +- @ApiOperation("定制师产品统计(C端用)") ++ @ApiOperation(value = "定制师产品统计(C端用)", ++ notes = "统计指定定制师已发布的产品数量。\n\n" ++ + "**关联字典**:\n" ++ + "- product_status(产品状态,统计条件):PUBLISHED=已上架") + @GetMapping("/designer-stats") + public Result> getDesignerStats(@RequestParam Long customizerId) { + long routeCount = productMapper.selectCount( +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java +index 978f513..7c0b2e7 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/InternalProductController.java +@@ -49,7 +49,7 @@ import java.util.stream.Collectors; + @RestController + @RequestMapping("/internal/product") + @RequiredArgsConstructor +-@Api(tags = "【内部接口】产品(Feign调用)") ++@Api(tags = "【内部接口】产品(Feign调用)", hidden = true) + public class InternalProductController { + + private final ProductStatusService productStatusService; +@@ -66,8 +66,12 @@ public class InternalProductController { + private final GroupTourBatchMapper groupBatchMapper; + private final ObjectMapper objectMapper; + ++ @ApiOperation(value = "处理产品审批结果", ++ notes = "接收企微审批回调结果,更新产品状态。\n\n" ++ + "**关联字典**:\n" ++ + "- product_status(产品状态):PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@Valid @RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@Valid @RequestBody ApprovalResultDTO dto) { + try { + productStatusService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +@@ -78,10 +82,12 @@ public class InternalProductController { + } + } + +- /** +- * 获取产品详情(不过滤状态,供 order-service 创建订单时获取快照) +- * 可选传入 date 参数,传入后会从资源价格日历查询各节点的成本价并填入快照 +- */ ++ @ApiOperation(value = "获取产品详情(内部)", ++ notes = "不过滤状态,供 order-service 创建订单时获取快照。可选传入 date 参数查询各节点成本价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}/detail") + public Result getProductDetail(@PathVariable Long productId, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) { +@@ -91,19 +97,20 @@ public class InternalProductController { + return Result.success(productService.getProduct(productId)); + } + +- /** +- * 报价计算(供 order-service 创建订单时自动报价) +- */ ++ @ApiOperation(value = "报价计算(内部)", ++ notes = "供 order-service 创建订单时自动报价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响计算逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/{productId}/quote") + public Result calculateQuote(@PathVariable Long productId, + @Valid @RequestBody QuoteRequest request) { + return Result.success(quoteCalculatorService.calculateQuote(productId, request)); + } + +- /** +- * 简单报价:直接从价格日历取售价 × 人数,不走资源价格计算。 +- * 小童 = 儿童售价 × 折扣比例,幼童 = 固定价格。 +- */ ++ @ApiOperation(value = "简单报价(内部)", ++ notes = "直接从价格日历取售价乘以人数,不走资源价格计算。CUSTOM/ROUTE按整单,CORE/GROUP按人头。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响计算逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/{productId}/simple-quote") + public Result> simpleQuote( + @PathVariable Long productId, +@@ -253,6 +260,10 @@ public class InternalProductController { + /** + * Deduct stock (optimistic lock: only succeeds if stock >= count) + */ ++ @ApiOperation(value = "扣减库存(内部)", ++ notes = "内部服务间调用,供 order-service 创建订单时扣减价格日历库存。\n\n" ++ + "使用乐观锁机制:只有当库存 >= count 时才扣减成功。\n" ++ + "扣减失败返回错误(库存不足),调用方需处理失败情况。") + @PostMapping("/{productId}/deduct-stock") + public Result deductStock(@PathVariable Long productId, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") String date, +@@ -268,6 +279,9 @@ public class InternalProductController { + /** + * Restore stock (compensation for cancelled/expired orders) + */ ++ @ApiOperation(value = "恢复库存(内部)", ++ notes = "内部服务间调用,供 order-service 订单取消/过期时恢复价格日历库存。\n" ++ + "用于补偿已扣减的库存,恢复数量不校验上限。") + @PostMapping("/{productId}/restore-stock") + public Result restoreStock(@PathVariable Long productId, + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") String date, +@@ -281,6 +295,9 @@ public class InternalProductController { + * Get itinerary resources (SCENIC/ACTIVITY/HOTEL) for review service. + * Returns deduplicated list of { resourceType, resourceId, resourceName }. + */ ++ @ApiOperation(value = "获取行程关联资源(内部)", ++ notes = "内部服务间调用,供 review-service 获取产品行程中关联的资源列表。\n\n" ++ + "返回去重后的景区(SCENIC)、活动(ACTIVITY)、酒店(HOTEL)资源,用于评价时选择关联的资源对象。") + @GetMapping("/{productId}/itinerary-resources") + public Result>> getItineraryResources(@PathVariable Long productId) { + // Allowed resource types for review +@@ -310,9 +327,11 @@ public class InternalProductController { + return Result.success(result); + } + +- /** +- * 变更定制产品状态(供 order-service 调用:下单→ORDERED / 取消→COMPLETED) +- */ ++ @ApiOperation(value = "变更定制产品状态(内部)", ++ notes = "供 order-service 调用:下单时 COMPLETED→ORDERED,取消时 ORDERED→COMPLETED。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限CUSTOM):CUSTOM=定制产品\n" ++ + "- product_status(产品状态):COMPLETED=已完成, ORDERED=已下单") + @PutMapping("/{productId}/custom-status") + public Result changeCustomProductStatus(@PathVariable Long productId, + @RequestParam String targetStatus) { +@@ -339,6 +358,10 @@ public class InternalProductController { + /** + * Enroll participants (optimistic lock on batch). + */ ++ @ApiOperation(value = "报名入团(内部)", ++ notes = "内部服务间调用,供 order-service 下单时增加批次已报名人数。\n\n" ++ + "使用乐观锁机制:只有当剩余名额 >= peopleCount 时才报名成功。\n" ++ + "报名成功后自动检查是否满员(FULL)或达到成团条件(CONFIRMED)。") + @PostMapping("/batch/{batchId}/enroll") + public Result enrollBatch(@PathVariable Long batchId, + @RequestParam @Min(1) int peopleCount) { +@@ -349,6 +372,9 @@ public class InternalProductController { + /** + * Unenroll participants (compensation for cancellation). + */ ++ @ApiOperation(value = "退出报名(内部)", ++ notes = "内部服务间调用,供 order-service 订单取消/退款时减少批次已报名人数。\n" ++ + "用于补偿已报名的人数,恢复剩余名额。") + @PostMapping("/batch/{batchId}/unenroll") + public Result unenrollBatch(@PathVariable Long batchId, + @RequestParam @Min(1) int peopleCount) { +@@ -356,9 +382,10 @@ public class InternalProductController { + return Result.success(); + } + +- /** +- * Get batch info (for order snapshot). +- */ ++ @ApiOperation(value = "批次信息(内部)", ++ notes = "供 order-service 创建订单时获取批次快照。\n\n" ++ + "**关联字典**:\n" ++ + "- batch_status(批次状态,返回字段):PENDING=待开放, ENROLLING=报名中, CONFIRMED=已成团, FULL=已满员, CLOSED=已关闭, DISBANDED=已解散, IN_PROGRESS=进行中, FINISHED=已结束") + @GetMapping("/batch/{batchId}/info") + public Result> getBatchInfo(@PathVariable Long batchId) { + GroupTourBatch batch = groupTourBatchService.getBatchById(batchId); +@@ -385,6 +412,10 @@ public class InternalProductController { + /** + * GROUP quote: returns adult/child dynamic pricing for a batch. + */ ++ @ApiOperation(value = "GROUP产品报价(内部)", ++ notes = "内部服务间调用,供 order-service 和 mp-service 获取 GROUP 产品按套餐组合的报价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限GROUP):GROUP=小蒙马拼团") + @GetMapping("/{productId}/group-quote") + public Result getGroupQuote(@PathVariable Long productId, + @RequestParam Long batchId, +@@ -395,6 +426,9 @@ public class InternalProductController { + /** + * C-end calendar data for GROUP products. + */ ++ @ApiOperation(value = "团期日历数据(内部)", ++ notes = "内部服务间调用,供小程序端展示 GROUP 产品的团期日历。\n\n" ++ + "返回可报名批次的出发日期、状态、剩余名额等信息,用于日历选择器展示。") + @GetMapping("/{productId}/batches/calendar") + public Result> getBatchesCalendar(@PathVariable Long productId) { + return Result.success(groupTourBatchService.listCalendar(productId)); +@@ -403,6 +437,9 @@ public class InternalProductController { + /** + * C-end combo list for a batch (套餐列表). + */ ++ @ApiOperation(value = "批次套餐列表(内部)", ++ notes = "内部服务间调用,供小程序端展示 GROUP 产品批次下的套餐组合列表。\n\n" ++ + "每个套餐包含成人/儿童人数搭配、售价、原价、库存和已售数量。") + @GetMapping("/batch/{batchId}/combos") + public Result>> listBatchCombos(@PathVariable Long batchId) { + List combos = comboMapper.selectList( +@@ -431,7 +468,9 @@ public class InternalProductController { + + // ===== 定制师内部接口 ===== + +- @ApiOperation("获取定制师已发布产品ID列表") ++ @ApiOperation(value = "获取定制师已发布产品ID列表", ++ notes = "**关联字典**:\n" ++ + "- product_status(产品状态,筛选条件):PUBLISHED=已上架") + @GetMapping("/designer-published-ids") + public Result> getDesignerPublishedProductIds(@RequestParam Long createBy) { + List ids = productService.getDesignerPublishedProductIds(createBy); +@@ -439,19 +478,28 @@ public class InternalProductController { + return Result.success(strIds); + } + +- @ApiOperation("获取全局产品统计") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java +index f813a83..7ea5e3b 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ItineraryController.java +@@ -28,7 +28,10 @@ public class ItineraryController { + + // ========================= Day ========================= + +- @ApiOperation("更新行程天") ++ @ApiOperation(value = "更新行程天", ++ notes = "更新指定天的行程信息,如当天主题、概述等。\n" ++ + "行程天在创建产品时根据 tripDays 自动生成,不支持单独增删,只能更新。\n" ++ + "dayNumber 从 1 开始,对应第几天的行程。") + @PutMapping("/item/{productId}/day/{dayNumber}") + public Result updateDay( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -37,7 +40,9 @@ public class ItineraryController { + return Result.success(dayService.updateDay(productId, dayNumber, request)); + } + +- @ApiOperation("获取行程天列表") ++ @ApiOperation(value = "获取行程天列表", ++ notes = "获取产品所有行程天的信息,按 dayNumber 升序排列。\n" ++ + "每一天包含当天主题、概述等信息,不包含节点详情(节点通过单独接口获取)。") + @GetMapping("/item/{productId}/days") + public Result> listDays(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(dayService.listDays(productId)); +@@ -45,7 +50,14 @@ public class ItineraryController { + + // ========================= Node ========================= + +- @ApiOperation("添加行程节点") ++ @ApiOperation(value = "添加行程节点", ++ notes = "在指定天添加一个行程节点。节点是行程的最小单元,可关联资源服务中的景区、酒店、活动等。\n\n" ++ + "**节点类型**:TRANSPORT(交通)/SCENIC(景区)/DINING(餐饮)/ACTIVITY(活动)/" ++ + "PHOTOGRAPHY(摄影)/HOTEL(酒店)/FREE(自由活动)/CUSTOM(自定义)\n\n" ++ + "**CUSTOM 定制产品特有**:可通过 familyIds 指定节点所属的家庭分组,实现按家庭分配行程。\n" ++ + "新建节点自动追加到当天最后位置,可通过排序接口调整顺序。\n\n" ++ + "**关联字典**:\n" ++ + "- city(城市,资源面板筛选用):用于在添加节点时按城市筛选可选资源") + @PostMapping("/item/{productId}/day/{dayNumber}/node") + public Result createNode( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -54,7 +66,12 @@ public class ItineraryController { + return Result.success(nodeService.createNode(productId, dayNumber, request)); + } + +- @ApiOperation("更新行程节点") ++ @ApiOperation(value = "更新行程节点", ++ notes = "更新行程节点信息,仅传入需要修改的字段。\n" ++ + "可修改节点名称、时间、关联资源、图片、描述等。\n\n" ++ + "**关联字典**:\n" ++ + "- city(城市):资源面板城市筛选\n" ++ + "- cities(城市ID映射):城市名称预览") + @PutMapping("/node/{nodeId}") + public Result updateNode( + @ApiParam("行程节点ID") @PathVariable Long nodeId, +@@ -62,14 +79,17 @@ public class ItineraryController { + return Result.success(nodeService.updateNode(nodeId, request)); + } + +- @ApiOperation("删除行程节点") ++ @ApiOperation(value = "删除行程节点", ++ notes = "删除指定行程节点,同天其他节点的排序自动调整。") + @DeleteMapping("/node/{nodeId}") + public Result deleteNode(@ApiParam("行程节点ID") @PathVariable Long nodeId) { + nodeService.deleteNode(nodeId); + return Result.success(); + } + +- @ApiOperation("行程节点拖拽排序") ++ @ApiOperation(value = "行程节点拖拽排序", ++ notes = "重新排列指定天的所有行程节点顺序。前端拖拽排序后,将新的节点ID顺序全量提交。\n" ++ + "nodeIds 列表中的顺序即为新的排序顺序(从上到下)。") + @PutMapping("/item/{productId}/day/{dayNumber}/nodes/sort") + public Result sortNodes( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -79,13 +99,17 @@ public class ItineraryController { + return Result.success(); + } + +- @ApiOperation("复制行程节点") ++ @ApiOperation(value = "复制行程节点", ++ notes = "复制指定节点到同一天的末尾位置,包括节点的所有属性(名称、资源关联、图片等)。\n" ++ + "适用场景:同一天有相似的行程安排时快速复制。") + @PostMapping("/node/{nodeId}/copy") + public Result copyNode(@ApiParam("行程节点ID") @PathVariable Long nodeId) { + return Result.success(nodeService.copyNode(nodeId)); + } + +- @ApiOperation("移动行程节点到其他天") ++ @ApiOperation(value = "移动行程节点到其他天", ++ notes = "将节点从当前天移动到目标天的末尾位置。\n" ++ + "移动后原天和目标天的节点排序自动调整。") + @PutMapping("/node/{nodeId}/move") + public Result moveNode( + @ApiParam("行程节点ID") @PathVariable Long nodeId, +@@ -93,7 +117,12 @@ public class ItineraryController { + return Result.success(nodeService.moveNode(nodeId, request.getTargetDayNumber())); + } + +- @ApiOperation("获取某天的节点列表") ++ @ApiOperation(value = "获取某天的节点列表", ++ notes = "获取指定天的所有行程节点,按排序顺序返回。\n" ++ + "每个节点包含类型、名称、时间、关联资源信息、图片等完整数据。\n\n" ++ + "**关联字典**:\n" ++ + "- city(城市):资源面板城市筛选\n" ++ + "- cities(城市ID映射):城市名称预览") + @GetMapping("/item/{productId}/day/{dayNumber}/nodes") + public Result> listNodes( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -103,7 +132,10 @@ public class ItineraryController { + + // ========================= Hotel ========================= + +- @ApiOperation("添加每日住宿") ++ @ApiOperation(value = "添加每日住宿", ++ notes = "为指定天添加住宿安排,关联资源服务中的酒店和房型。\n" ++ + "每天可以有多个住宿选项(如不同档次),参与成本自动计算。\n" ++ + "住宿费用会体现在价格日历的成本计算中。") + @PostMapping("/item/{productId}/day/{dayNumber}/hotel") + public Result addHotel( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -112,7 +144,8 @@ public class ItineraryController { + return Result.success(hotelService.addHotel(productId, dayNumber, request)); + } + +- @ApiOperation("更新每日住宿") ++ @ApiOperation(value = "更新每日住宿", ++ notes = "更新住宿记录的酒店、房型、数量等信息。") + @PutMapping("/hotel/{id}") + public Result updateHotel( + @ApiParam("住宿记录ID") @PathVariable Long id, +@@ -120,14 +153,16 @@ public class ItineraryController { + return Result.success(hotelService.updateHotel(id, request)); + } + +- @ApiOperation("删除每日住宿") ++ @ApiOperation(value = "删除每日住宿", ++ notes = "删除指定住宿记录。删除后该天的住宿成本会从报价中移除。") + @DeleteMapping("/hotel/{id}") + public Result deleteHotel(@ApiParam("住宿记录ID") @PathVariable Long id) { + hotelService.deleteHotel(id); + return Result.success(); + } + +- @ApiOperation("获取某天的住宿列表") ++ @ApiOperation(value = "获取某天的住宿列表", ++ notes = "获取指定天的所有住宿安排,包含酒店名称、房型、数量等信息。") + @GetMapping("/item/{productId}/day/{dayNumber}/hotels") + public Result> listHotels( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -137,7 +172,9 @@ public class ItineraryController { + + // ========================= Dining ========================= + +- @ApiOperation("添加每日餐厅推荐") ++ @ApiOperation(value = "添加每日餐厅推荐", ++ notes = "为指定天添加餐饮推荐,关联资源服务中的餐厅。\n" ++ + "用于展示当天的用餐安排,可按早/午/晚分类。") + @PostMapping("/item/{productId}/day/{dayNumber}/dining") + public Result addDiningOption( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -146,7 +183,8 @@ public class ItineraryController { + return Result.success(diningOptionService.addDiningOption(productId, dayNumber, request)); + } + +- @ApiOperation("更新餐饮推荐") ++ @ApiOperation(value = "更新餐饮推荐", ++ notes = "更新餐饮推荐的餐厅、用餐类型(早/午/晚)、描述等信息。") + @PutMapping("/dining/{id}") + public Result updateDiningOption( + @ApiParam("餐饮推荐ID") @PathVariable Long id, +@@ -154,7 +192,8 @@ public class ItineraryController { + return Result.success(diningOptionService.updateDiningOption(id, request)); + } + +- @ApiOperation("获取某天的餐厅推荐列表") ++ @ApiOperation(value = "获取某天的餐厅推荐列表", ++ notes = "获取指定天的所有餐饮推荐,包含餐厅名称、用餐类型、描述等信息。") + @GetMapping("/item/{productId}/day/{dayNumber}/dining") + public Result> listDining( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -162,7 +201,8 @@ public class ItineraryController { + return Result.success(diningOptionService.listDiningOptions(productId, dayNumber)); + } + +- @ApiOperation("删除餐饮推荐") ++ @ApiOperation(value = "删除餐饮推荐", ++ notes = "删除指定的餐饮推荐记录。") + @DeleteMapping("/dining/{id}") + public Result deleteDiningOption(@ApiParam("餐饮推荐ID") @PathVariable Long id) { + diningOptionService.deleteDiningOption(id); +@@ -171,7 +211,9 @@ public class ItineraryController { + + // ========================= Supplies ========================= + +- @ApiOperation("添加物资配品") ++ @ApiOperation(value = "添加物资配品", ++ notes = "为产品添加物资配品(如帐篷、睡袋、登山杖等),关联资源服务中的物资。\n" +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java +index 526bc16..94a6723 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/MpProductController.java +@@ -31,19 +31,33 @@ public class MpProductController { + private final ProductService productService; + private final QuoteCalculatorService quoteCalculatorService; + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表(C端)", ++ notes = "小程序端产品列表接口,仅返回已上架(PUBLISHED)的产品。\n\n" ++ + "支持按产品类型、季节、行程天数、目的地、产品线、支付模式、定制师等筛选。\n" ++ + "默认按 sortOrder 排序,也可按价格或行程天数排序。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选条件):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @GetMapping("/list") + public Result> listProducts(@ApiParam("产品查询请求") @Valid MpProductQueryRequest query) { + return Result.success(productService.listPublishedProducts(query)); + } + +- @ApiOperation("产品详情") ++ @ApiOperation(value = "产品详情(C端)", ++ notes = "小程序端产品详情接口,仅返回已上架(PUBLISHED)的产品。\n" ++ + "包含完整的行程信息、定价配置、费用说明、创作者寄语等。\n" ++ + "未上架的产品会返回 404 错误。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}") + public Result getProduct(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(productService.getPublishedProduct(productId)); + } + +- @ApiOperation("报价计算") ++ @ApiOperation(value = "报价计算(C端)", ++ notes = "小程序端报价计算接口,根据用户选择的日期和人数计算总价。\n" ++ + "内部会校验产品是否存在且已上架。\n" ++ + "详细计算逻辑参见管理后台的报价计算接口说明。") + @PostMapping("/{productId}/quote") + public Result calculateQuote( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java +index cdd0cb8..1599755 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/PricingController.java +@@ -28,7 +28,18 @@ public class PricingController { + + // ========== 定价规则 ========== + +- @ApiOperation("保存定价规则") ++ @ApiOperation(value = "保存定价规则", ++ notes = "保存或更新产品的定价配置(一个产品仅一条定价记录,重复调用为覆盖更新)。\n\n" ++ + "**定价模式**:\n" ++ + "- AUTO:自动计算,通过公式引擎根据行程资源价格自动测算成本和售价\n" ++ + "- MANUAL:手动定价,直接在价格日历中手动设置每日价格\n" ++ + "- CUSTOM:定制定价,设置整单总价(customTotalPrice),不按人头\n\n" ++ + "**利润模式**(AUTO 模式下生效):\n" ++ + "- FIXED:固定金额加价,售价 = 成本 + profitAmount\n" ++ + "- PERCENT:百分比加价,售价 = 成本 × (1 + markupPercent/100)\n\n" ++ + "**支付方式**:FULL=全款支付,DEPOSIT=定金+尾款(需设置 depositRatio 或 depositAmount)\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):费用配置中车辆相关成本计算") + @PostMapping("/pricing") + public Result savePricing( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -36,7 +47,11 @@ public class PricingController { + return Result.success(pricingService.savePricing(productId, request)); + } + +- @ApiOperation("获取定价规则") ++ @ApiOperation(value = "获取定价规则", ++ notes = "获取产品的定价配置,包括定价模式、利润设置、儿童/婴儿价格、支付方式等。\n" ++ + "如果产品尚未设置定价规则,返回 null。\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):费用配置中车辆相关成本显示") + @GetMapping("/pricing") + public Result getPricing(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(pricingService.getPricing(productId)); +@@ -44,7 +59,11 @@ public class PricingController { + + // ========== 价格日历 ========== + +- @ApiOperation("获取月度价格日历") ++ @ApiOperation(value = "获取月度价格日历", ++ notes = "获取指定月份的价格日历数据列表。\n\n" ++ + "每条数据包含:日期、成人售价/成本价、儿童售价/成本价、库存、状态(OPEN/CLOSED)等。\n" ++ + "**CORE/GROUP 产品**:价格为单人价格,按人头 × 价格计算总价。\n" ++ + "**CUSTOM/ROUTE 产品**:价格为整单总价,不乘以人头数。") + @GetMapping("/price-calendar") + public Result> getMonthCalendar( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -53,7 +72,10 @@ public class PricingController { + return Result.success(calendarService.getMonthCalendar(productId, year, month)); + } + +- @ApiOperation("设置单日价格") ++ @ApiOperation(value = "设置单日价格", ++ notes = "设置或更新指定日期的价格和库存。如果该日期已有记录则更新,否则新建。\n\n" ++ + "可设置成人售价/成本价、儿童售价/成本价、库存数量、状态(OPEN/CLOSED)。\n" ++ + "状态为 CLOSED 的日期不会出现在小程序端的可选日期中。") + @PostMapping("/price-calendar") + public Result setDayPrice( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -61,7 +83,11 @@ public class PricingController { + return Result.success(calendarService.setDayPrice(productId, request)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", ++ notes = "批量设置日期范围内的价格和库存,支持按星期筛选。\n\n" ++ + "指定 startDate 和 endDate 日期范围,可选 selectedWeekdays 过滤星期几。\n" ++ + "示例:设置5月1日-5月31日的工作日(周一到周五=[1,2,3,4,5])价格。\n" ++ + "selectedWeekdays 为空时,范围内所有日期都会被设置。") + @PostMapping("/price-calendar/batch") + public Result> batchSetPrices( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -69,7 +95,13 @@ public class PricingController { + return Result.success(calendarService.batchSetPrices(productId, request)); + } + +- @ApiOperation("测算预览(不写入数据库)") ++ @ApiOperation(value = "测算预览(不写入数据库)", ++ notes = "根据行程中的资源价格日历,自动计算指定日期的成本价和售价,仅预览不保存。\n\n" ++ + "用于在设置价格日历前预览自动计算的结果。\n" ++ + "计算逻辑:汇总当天所有行程节点关联资源的价格 → 应用公式引擎 → 加上利润。\n" ++ + "GROUP 产品需要传 adultCount 参数(影响均摊计算)。\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):车辆费用成本测算") + @PostMapping("/price-calendar/calc-preview") + public Result calcPreview( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -77,13 +109,21 @@ public class PricingController { + return Result.success(calendarService.calcPreview(productId, request)); + } + +- @ApiOperation("重新测算所有自动测算日期的价格") ++ @ApiOperation(value = "重新测算所有自动测算日期的价格", ++ notes = "重新计算价格日历中所有 costAutoCalc=true 的日期的成本价和售价。\n\n" ++ + "适用场景:资源价格调整后,批量刷新所有自动计算的价格日历。\n" ++ + "返回更新的日期数量和详情。手动设置的价格(costAutoCalc=false)不受影响。") + @PostMapping("/price-calendar/recalculate") + public Result> recalculate(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(calendarService.recalculateAll(productId)); + } + +- @ApiOperation("自动计算成本并同步到价格日历") ++ @ApiOperation(value = "自动计算成本并同步到价格日历", ++ notes = "根据出发日期和人数,自动计算成本并将结果写入价格日历。\n\n" ++ + "与测算预览不同,此接口会实际更新价格日历数据。\n" ++ + "计算逻辑:查询各资源的价格日历 → 汇总成本 → 应用公式和利润规则 → 写入结果。\n\n" ++ + "**关联字典**:\n" ++ + "- vehicle_type(车型):车辆费用成本计算") + @PostMapping("/price-calendar/auto-calc") + public Result autoCalcCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -100,7 +140,10 @@ public class PricingController { + + // ========== 费用包含/不包含 ========== + +- @ApiOperation("添加费用项") ++ @ApiOperation(value = "添加费用项", ++ notes = "添加产品的费用包含/不包含说明项。\n\n" ++ + "用于在产品详情页展示\"费用包含\"和\"费用不包含\"信息。\n" ++ + "仅用于前端展示,不参与报价计算。") + @PostMapping("/cost-item") + public Result addCostItem( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -108,7 +151,8 @@ public class PricingController { + return Result.success(costItemService.addCostItem(productId, request)); + } + +- @ApiOperation("更新费用项") ++ @ApiOperation(value = "更新费用项", ++ notes = "更新费用包含/不包含说明项的内容。仅用于前端展示,不参与报价计算。") + @PutMapping("/cost-item/{itemId}") + public Result updateCostItem( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -117,7 +161,8 @@ public class PricingController { + return Result.success(costItemService.updateCostItem(itemId, request)); + } + +- @ApiOperation("删除费用项") ++ @ApiOperation(value = "删除费用项", ++ notes = "删除费用包含/不包含说明项。") + @DeleteMapping("/cost-item/{itemId}") + public Result deleteCostItem( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -126,7 +171,8 @@ public class PricingController { + return Result.success(); + } + +- @ApiOperation("获取费用项列表") ++ @ApiOperation(value = "获取费用项列表", ++ notes = "获取产品的所有费用包含/不包含说明项列表。") + @GetMapping("/cost-items") + public Result> listCostItems(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(costItemService.listCostItems(productId)); +@@ -134,7 +180,10 @@ public class PricingController { + + // ========== 额外成本关联 ========== + +- @ApiOperation("添加额外成本关联") ++ @ApiOperation(value = "添加额外成本关联", ++ notes = "关联资源服务中的费用项(cost_item)到产品,参与成本自动计算。\n\n" ++ + "额外成本是指不包含在行程节点中、但需要计入总成本的费用。\n" ++ + "例如:导游服务费、保险费、通讯费等固定运营开支。") + @PostMapping("/extra-cost") + public Result addExtraCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -142,7 +191,8 @@ public class PricingController { + return Result.success(extraCostService.addExtraCost(productId, request)); + } + +- @ApiOperation("更新额外成本关联") ++ @ApiOperation(value = "更新额外成本关联", ++ notes = "更新额外成本关联的费用项、数量等信息。修改后会影响成本自动计算结果。") + @PutMapping("/extra-cost/{ecId}") + public Result updateExtraCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -151,7 +201,8 @@ public class PricingController { + return Result.success(extraCostService.updateExtraCost(ecId, request)); + } + +- @ApiOperation("删除额外成本关联") ++ @ApiOperation(value = "删除额外成本关联", ++ notes = "删除额外成本关联记录。删除后该费用项不再计入成本自动计算。") + @DeleteMapping("/extra-cost/{ecId}") + public Result removeExtraCost( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -160,7 +211,8 @@ public class PricingController { + return Result.success(); + } + +- @ApiOperation("获取额外成本关联列表") ++ @ApiOperation(value = "获取额外成本关联列表", ++ notes = "获取产品关联的所有额外成本项列表,包含费用项名称、金额等信息。") + @GetMapping("/extra-costs") + public Result> listExtraCosts(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(extraCostService.listExtraCosts(productId)); +@@ -168,7 +220,10 @@ public class PricingController { + +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java +index bc250d7..5f48dff 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductController.java +@@ -28,7 +28,20 @@ public class ProductController { + private final ProductStatusService productStatusService; + private final RouteMapService routeMapService; + +- @ApiOperation("创建产品(草稿)") ++ @ApiOperation(value = "创建产品(草稿)", ++ notes = "创建一个新产品,初始状态为 DRAFT(草稿)。\n\n" ++ + "**产品类型说明**:\n" ++ + "- CORE:核心产品,标准旅游产品,支持上架/下架审批流程\n" ++ + "- GROUP:小蒙马拼团,需配合团期批次管理,按人头计价\n" ++ + "- CUSTOM:定制产品,由定制师为客户量身定制,按单计价\n" ++ + "- ROUTE:线路产品,预设线路模板,按单计价\n\n" ++ + "**注意事项**:\n" ++ + "- 创建后需依次完善行程、定价、价格日历等信息\n" ++ + "- CUSTOM/ROUTE 产品的价格日历存储的是整单总价,不按人头乘算\n" ++ + "- GROUP 产品需额外创建团期批次才能报名\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @PostMapping + public Result createProduct( + @ApiParam("创建产品请求") @Valid @RequestBody ProductCreateRequest request, +@@ -37,13 +50,28 @@ public class ProductController { + return Result.success(productService.createProduct(request, adminId)); + } + +- @ApiOperation("获取产品详情") ++ @ApiOperation(value = "获取产品详情", ++ notes = "获取产品完整信息,包括基本信息、行程天列表、定价配置、费用项等。\n" ++ + "返回数据包含关联的行程节点资源详情,适用于产品编辑页面。\n" ++ + "不过滤产品状态,所有状态的产品都可查看。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @GetMapping("/{productId}") + public Result getProduct(@ApiParam("产品ID") @PathVariable Long productId) { + return Result.success(productService.getProduct(productId)); + } + +- @ApiOperation("更新产品") ++ @ApiOperation(value = "更新产品", ++ notes = "更新产品基本信息,仅传入需要修改的字段,未传字段不会被覆盖。\n\n" ++ + "**权限说明**:\n" ++ + "- 普通管理员只能编辑自己创建的产品\n" ++ + "- SUPER_ADMIN 可编辑所有产品\n\n" ++ + "**注意**:行程、定价、价格日历等通过各自独立的接口管理,不在此接口中处理。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_category(产品分类):family=亲子游, honeymoon=蜜月游, photography=旅拍, experience=体验, driving=自驾") + @PutMapping("/{productId}") + public Result updateProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -54,7 +82,10 @@ public class ProductController { + return Result.success(productService.updateProduct(productId, request, adminId, role)); + } + +- @ApiOperation("删除产品") ++ @ApiOperation(value = "删除产品", ++ notes = "软删除产品(设置 deleted_at 字段)。\n\n" ++ + "**权限说明**:普通管理员只能删除自己创建的产品,SUPER_ADMIN 可删除所有产品。\n" ++ + "**限制**:已上架(PUBLISHED)的产品不能直接删除,需先下架。") + @DeleteMapping("/{productId}") + public Result deleteProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -65,17 +96,33 @@ public class ProductController { + return Result.success(); + } + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", ++ notes = "分页查询产品列表,支持多维度筛选和排序。\n\n" ++ + "**权限说明**:\n" ++ + "- 普通管理员只能看到自己创建的产品\n" ++ + "- SUPER_ADMIN 可看到所有产品\n\n" ++ + "**筛选条件**:关键词(名称/副标题模糊匹配)、产品类型、状态、文件夹、产品线、季节、行程天数。\n" ++ + "支持多状态筛选(statuses 字段,逗号分隔)。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,筛选条件):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态,筛选条件+返回字段):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单") + @GetMapping("/list") + public Result> listProducts( + @ApiParam("产品查询请求") @Valid ProductQueryRequest query, + HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +- boolean isSuperAdmin = "SUPER_ADMIN".equals(httpRequest.getAttribute("role")); +- return Result.success(productService.listProducts(query, adminId, isSuperAdmin)); ++ String role = (String) httpRequest.getAttribute("role"); ++ boolean canViewAll = "SUPER_ADMIN".equals(role) || "CUSTOMER_SERVICE".equals(role); ++ return Result.success(productService.listProducts(query, adminId, canViewAll)); + } + +- @ApiOperation("复制产品") ++ @ApiOperation(value = "复制产品", ++ notes = "深度复制产品,包括行程天、行程节点、定价配置、住宿、餐饮、物资、人员配置等所有关联数据。\n\n" ++ + "复制后的产品状态为 DRAFT,名称自动添加\"(副本)\"后缀。\n" ++ + "适用场景:基于已有产品快速创建新产品。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,返回字段):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态,复制后固定为 DRAFT)") + @PostMapping("/{productId}/copy") + public Result copyProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -84,7 +131,9 @@ public class ProductController { + return Result.success(productService.copyProduct(productId, adminId)); + } + +- @ApiOperation("移动产品到文件夹") ++ @ApiOperation(value = "移动产品到文件夹", ++ notes = "将产品移动到指定文件夹,或移出文件夹(folderId 传空字符串或 null)。\n" ++ + "文件夹用于组织管理产品,不影响产品的业务逻辑。") + @PutMapping("/{productId}/move") + public Result moveProduct( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -95,7 +144,10 @@ public class ProductController { + return Result.success(); + } + +- @ApiOperation("生成定制产品分享链接") ++ @ApiOperation(value = "生成定制产品分享链接", ++ notes = "为 CUSTOM(定制)产品生成小程序分享链接,用于定制师发送给客户查看方案。\n\n" ++ + "**限制**:仅 CUSTOM 类型且状态为 COMPLETED 的产品可生成。\n" ++ + "**权限**:普通管理员只能为自己创建的产品生成链接,SUPER_ADMIN 不受限制。") + @PostMapping("/{productId}/share-link") + public Result generateShareLink( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -105,7 +157,10 @@ public class ProductController { + return Result.success(productService.generateShareLink(productId, adminId, role)); + } + +- @ApiOperation("手动生成路径图") ++ @ApiOperation(value = "手动生成路径图", ++ notes = "根据产品行程节点的经纬度信息,调用地图API生成行程路径图。\n\n" ++ + "通常在行程编辑完成后手动触发,生成结果为 OSS 图片 URL。\n" ++ + "如果行程节点没有经纬度信息,则无法生成路径图。") + @PostMapping("/{productId}/generate-route-map") + public Result generateRouteMap(@ApiParam("产品ID") @PathVariable Long productId) { + try { +@@ -116,7 +171,20 @@ public class ProductController { + } + } + +- @ApiOperation("产品状态变更(上架/下架等)") ++ @ApiOperation(value = "产品状态变更(上架/下架/完成)", ++ notes = "根据产品类型,状态流转规则不同:\n\n" ++ + "**核心产品(CORE) / 小蒙马(GROUP)**:支持上架/下架,需企微审批\n" ++ + "- DRAFT → PENDING_REVIEW → REVIEWED → PUBLISHED(上架)\n" ++ + "- PUBLISHED → UNPUBLISHED(下架)\n" ++ + "- UNPUBLISHED → PUBLISHED(重新上架)\n" ++ + "- REJECTED → DRAFT(驳回后重新编辑)\n\n" ++ + "**定制产品(CUSTOM)**:仅支持完成,无上架/下架概念\n" ++ + "- DRAFT → COMPLETED(定制师完成设计)\n" ++ + "- COMPLETED → ORDERED(客户下单,系统自动变更)\n" ++ + "- ORDERED → COMPLETED(订单取消/退款后回退)\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响状态流转规则):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品\n" ++ + "- product_status(产品状态,请求+返回字段):DRAFT=草稿, PENDING_REVIEW=待审核, REVIEWED=已审核, REJECTED=已驳回, PUBLISHED=已上架, UNPUBLISHED=已下架, COMPLETED=已完成, ORDERED=已下单") + @PutMapping("/{productId}/status") + public Result changeStatus( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java +index 2562b23..2b69413 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductFolderController.java +@@ -23,7 +23,9 @@ public class ProductFolderController { + + private final ProductFolderService folderService; + +- @ApiOperation("创建文件夹") ++ @ApiOperation(value = "创建文件夹", ++ notes = "创建产品文件夹,用于组织管理产品。支持多级目录结构。\n" ++ + "文件夹归属于创建人,普通管理员只能看到自己的文件夹。") + @PostMapping + public Result createFolder( + @ApiParam("创建文件夹请求") @Valid @RequestBody FolderCreateRequest request, +@@ -33,7 +35,9 @@ public class ProductFolderController { + return Result.success(folderService.createFolder(request, adminId, ownerName)); + } + +- @ApiOperation("更新文件夹") ++ @ApiOperation(value = "更新文件夹", ++ notes = "更新文件夹名称等信息。\n" ++ + "**权限说明**:普通管理员只能更新自己创建的文件夹,SUPER_ADMIN 可更新任何文件夹。") + @PutMapping("/{folderId}") + public Result updateFolder( + @ApiParam("文件夹ID") @PathVariable Long folderId, +@@ -44,7 +48,9 @@ public class ProductFolderController { + return Result.success(folderService.updateFolder(folderId, request, adminId, isSuperAdmin)); + } + +- @ApiOperation("删除文件夹") ++ @ApiOperation(value = "删除文件夹", ++ notes = "删除文件夹。如果文件夹下有产品,产品会自动移到根目录(folderId 置空)。\n" ++ + "普通管理员只能删除自己的文件夹,SUPER_ADMIN 可删除任何文件夹。") + @DeleteMapping("/{folderId}") + public Result deleteFolder(@ApiParam("文件夹ID") @PathVariable Long folderId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -53,7 +59,10 @@ public class ProductFolderController { + return Result.success(); + } + +- @ApiOperation("获取文件夹树") ++ @ApiOperation(value = "获取文件夹树", ++ notes = "获取当前用户可见的文件夹树形结构。\n" ++ + "普通管理员只能看到自己创建的文件夹,SUPER_ADMIN 可看到所有文件夹。\n" ++ + "返回结构为嵌套的树形列表,包含每个文件夹的子文件夹。") + @GetMapping("/tree") + public Result> getFolderTree(HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java +index 28d7d17..13683ab 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/ProductLineController.java +@@ -25,7 +25,9 @@ public class ProductLineController { + + private final ProductLineService lineService; + +- @ApiOperation("创建产品线") ++ @ApiOperation(value = "创建产品线", ++ notes = "创建产品线,用于对产品进行业务分类(如:亲子游、蜜月游、探险游等)。\n" ++ + "产品线在小程序端可作为筛选条件,帮助用户快速找到感兴趣的产品类别。") + @PostMapping + public Result createLine( + @ApiParam("创建产品线请求") @Valid @RequestBody LineCreateRequest request, +@@ -34,7 +36,8 @@ public class ProductLineController { + return Result.success(lineService.createLine(request, adminId)); + } + +- @ApiOperation("更新产品线") ++ @ApiOperation(value = "更新产品线", ++ notes = "更新产品线名称、描述、状态等信息。") + @PutMapping("/{lineId}") + public Result updateLine( + @ApiParam("产品线ID") @PathVariable Long lineId, +@@ -42,26 +45,31 @@ public class ProductLineController { + return Result.success(lineService.updateLine(lineId, request)); + } + +- @ApiOperation("删除产品线") ++ @ApiOperation(value = "删除产品线", ++ notes = "删除产品线(软删除)。已关联产品的产品线仍可删除,但关联产品的产品线字段不会被清空。") + @DeleteMapping("/{lineId}") + public Result deleteLine(@ApiParam("产品线ID") @PathVariable Long lineId) { + lineService.deleteLine(lineId); + return Result.success(); + } + +- @ApiOperation("产品线详情") ++ @ApiOperation(value = "产品线详情", ++ notes = "获取指定产品线的完整信息。") + @GetMapping("/{lineId}") + public Result getLine(@ApiParam("产品线ID") @PathVariable Long lineId) { + return Result.success(lineService.getLine(lineId)); + } + +- @ApiOperation("产品线列表(分页)") ++ @ApiOperation(value = "产品线列表(分页)", ++ notes = "分页查询产品线列表,支持按名称关键词筛选。") + @GetMapping("/list") + public Result> listLines(@ApiParam("产品线查询请求") @Valid LineQueryRequest query) { + return Result.success(lineService.listLines(query)); + } + +- @ApiOperation("所有启用的产品线") ++ @ApiOperation(value = "所有启用的产品线", ++ notes = "获取所有启用状态的产品线,不分页。\n" ++ + "适用于产品编辑时的产品线下拉选择,以及小程序端的筛选项。") + @GetMapping("/active") + public Result> listAllActive() { + return Result.success(lineService.listAllActive()); +``` + +### `hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java b/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java +index b6676e4..81f33f0 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/controller/QuoteController.java +@@ -23,7 +23,18 @@ public class QuoteController { + private final QuoteCalculatorService quoteCalculatorService; + private final CostCalculationService costCalculationService; + +- @ApiOperation("计算报价") ++ @ApiOperation(value = "计算报价", ++ notes = "根据出发日期和人数组合,计算产品的完整报价。\n\n" ++ + "**计算流程**:\n" ++ + "1. 从价格日历获取指定日期的单价\n" ++ + "2. 按人数类型分别计算:成人 × 成人价、儿童 × 儿童价\n" ++ + "3. 小童按儿童价 × 折扣比例(childDiscountPercent)计算\n" ++ + "4. 婴儿使用固定价格(babyPrice)\n" ++ + "5. 儿童加床(childNeedBed=true)额外加收 childWithBed 费用\n\n" ++ + "**CUSTOM/ROUTE 产品**:价格日历存的是整单总价,不按人头乘算。\n" ++ + "**GROUP 产品**:建议使用 group-quote 接口,支持套餐组合报价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,影响计算逻辑):CORE=核心产品, GROUP=小蒙马拼团, CUSTOM=定制产品, ROUTE=线路产品") + @PostMapping("/quote") + public Result calculateQuote( + @ApiParam("产品ID") @PathVariable Long productId, +@@ -31,7 +42,13 @@ public class QuoteController { + return Result.success(quoteCalculatorService.calculateQuote(productId, request)); + } + +- @ApiOperation("GROUP产品报价(按组合)") ++ @ApiOperation(value = "GROUP产品报价(按套餐组合)", ++ notes = "为 GROUP(小蒙马拼团)产品按团期批次和套餐组合计算报价。\n\n" ++ + "GROUP 产品的价格由批次下的套餐组合(combo)决定,不同组合有不同的成人/儿童人数搭配和价格。\n" ++ + "传入 batchId 指定团期批次,adultCount 用于匹配合适的套餐组合。\n\n" ++ + "**与普通报价的区别**:普通报价从价格日历取单价,GROUP 报价从套餐组合取打包价。\n\n" ++ + "**关联字典**:\n" ++ + "- product_type(产品类型,仅限GROUP):GROUP=小蒙马拼团") + @GetMapping("/group-quote") + public Result calculateGroupQuote( + @ApiParam("产品ID") @PathVariable Long productId, +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java +index 223810b..84591cf 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/FamilySaveRequest.java +@@ -9,7 +9,7 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.Size; + + @Data +-@ApiModel("家庭分组保存请求") ++@ApiModel(value = "家庭分组保存请求", description = "仅适用于CUSTOM定制产品,用于将行程按家庭单位分配") + public class FamilySaveRequest { + + @ApiModelProperty(value = "家庭名称", required = true, example = "家庭1") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java +index 4acb045..89b3240 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/FormulaStepRequest.java +@@ -29,7 +29,8 @@ public class FormulaStepRequest { + @ApiModelProperty(value = "执行顺序", example = "1") + private Integer executionOrder; + +- @ApiModelProperty(value = "表达式", required = true, example = "baseCost = adultCount * adultUnitCost + childCount * childUnitCost") ++ @ApiModelProperty(value = "Aviator表达式(支持数学运算、条件判断、内置函数;可引用前置步骤的输出变量和公式变量表中的变量)", ++ required = true, example = "baseCost = adultCount * adultUnitCost + childCount * childUnitCost") + @NotBlank(message = "表达式不能为空") + @Size(max = 2000, message = "表达式不能超过2000个字符") + private String expression; +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java +index 70e06ec..2cf6432 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchCreateRequest.java +@@ -8,34 +8,34 @@ import javax.validation.constraints.*; + import java.time.LocalDate; + + @Data +-@ApiModel("create group batch request") ++@ApiModel("创建拼团批次请求") + public class GroupBatchCreateRequest { + +- @ApiModelProperty(value = "batch name", required = true, example = "Jul 20 Batch 1") +- @NotBlank(message = "batch name required") ++ @ApiModelProperty(value = "批次名称", required = true, example = "7月20日第1批") ++ @NotBlank(message = "批次名称不能为空") + @Size(max = 128) + private String batchName; + +- @ApiModelProperty(value = "departure date", required = true, example = "2026-07-20") +- @NotNull(message = "departure date required") ++ @ApiModelProperty(value = "出发日期", required = true, example = "2026-07-20") ++ @NotNull(message = "出发日期不能为空") + private LocalDate departureDate; + +- @ApiModelProperty(value = "enrollment deadline", required = true, example = "2026-07-15") +- @NotNull(message = "enrollment deadline required") ++ @ApiModelProperty(value = "报名截止日期,必须早于出发日期", required = true, example = "2026-07-15") ++ @NotNull(message = "报名截止日期不能为空") + private LocalDate enrollmentDeadline; + +- @ApiModelProperty(value = "min participants for group confirmation (0=no limit)", example = "10") ++ @ApiModelProperty(value = "最低成团人数(0=不限制,达到此人数自动变为CONFIRMED状态)", example = "10") + @Min(0) + private int minParticipants = 0; + +- @ApiModelProperty(value = "max participants", required = true, example = "30") +- @Min(value = 1, message = "max participants must be >= 1") ++ @ApiModelProperty(value = "最大参团人数(报名人数达到上限后自动关闭报名)", required = true, example = "30") ++ @Min(value = 1, message = "最大参团人数至少为1") + private int maxParticipants; + +- @ApiModelProperty(value = "remark", example = "summer special batch") ++ @ApiModelProperty(value = "备注说明", example = "暑期特别批次") + @Size(max = 512) + private String remark; + +- @ApiModelProperty(value = "sort order", example = "0") ++ @ApiModelProperty(value = "排序序号(越小越靠前)", example = "0") + private int sortOrder = 0; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java +index 369a7ca..ca769e4 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchDisbandRequest.java +@@ -8,11 +8,11 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.Size; + + @Data +-@ApiModel("disband batch request") ++@ApiModel("解散批次请求") + public class GroupBatchDisbandRequest { + +- @ApiModelProperty(value = "disband reason", required = true, example = "insufficient enrollment") +- @NotBlank(message = "disband reason required") ++ @ApiModelProperty(value = "解散原因(如:报名人数不足、行程调整等)", required = true, example = "报名人数不足") ++ @NotBlank(message = "解散原因不能为空") + @Size(max = 512) + private String reason; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java +index 8c2f4bb..712181e 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchStaffRequest.java +@@ -9,22 +9,22 @@ import javax.validation.constraints.NotNull; + import javax.validation.constraints.Size; + + @Data +-@ApiModel("batch staff assignment request") ++@ApiModel("批次服务人员分配请求") + public class GroupBatchStaffRequest { + +- @ApiModelProperty(value = "staff ID (from resource-service)", required = true, example = "1760000000000001") +- @NotNull(message = "staff ID required") ++ @ApiModelProperty(value = "人员ID(来自资源服务的人员库)", required = true, example = "1760000000000001") ++ @NotNull(message = "人员ID不能为空") + private Long staffId; + +- @ApiModelProperty(value = "role in this batch: LEADER/PHOTOGRAPHER/DRIVER/OTHER", required = true, example = "LEADER") +- @NotBlank(message = "staff role required") ++ @ApiModelProperty(value = "在该批次中的角色:LEADER(领队)/PHOTOGRAPHER(摄影师)/DRIVER(司机)/OTHER(其他)", required = true, example = "LEADER") ++ @NotBlank(message = "人员角色不能为空") + @Size(max = 32) + private String staffRole; + +- @ApiModelProperty(value = "remark", example = "main guide") ++ @ApiModelProperty(value = "备注(如:主导游、备用摄影师等)", example = "主导游") + @Size(max = 256) + private String remark; + +- @ApiModelProperty(value = "sort order", example = "0") ++ @ApiModelProperty(value = "排序序号(越小越靠前)", example = "0") + private int sortOrder = 0; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java +index a8e2de6..4532f60 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/GroupBatchUpdateRequest.java +@@ -9,31 +9,31 @@ import javax.validation.constraints.Size; + import java.time.LocalDate; + + @Data +-@ApiModel("update group batch request") ++@ApiModel("更新拼团批次请求") + public class GroupBatchUpdateRequest { + +- @ApiModelProperty(value = "batch name", example = "Jul 20 Batch 1") ++ @ApiModelProperty(value = "批次名称", example = "7月20日第1批") + @Size(max = 128) + private String batchName; + +- @ApiModelProperty(value = "departure date", example = "2026-07-20") ++ @ApiModelProperty(value = "出发日期", example = "2026-07-20") + private LocalDate departureDate; + +- @ApiModelProperty(value = "enrollment deadline", example = "2026-07-15") ++ @ApiModelProperty(value = "报名截止日期", example = "2026-07-15") + private LocalDate enrollmentDeadline; + +- @ApiModelProperty(value = "min participants", example = "10") ++ @ApiModelProperty(value = "最低成团人数(0=不限制)", example = "10") + @Min(0) + private Integer minParticipants; + +- @ApiModelProperty(value = "max participants", example = "30") ++ @ApiModelProperty(value = "最大参团人数(不能低于已报名人数)", example = "30") + @Min(1) + private Integer maxParticipants; + +- @ApiModelProperty(value = "remark") ++ @ApiModelProperty(value = "备注说明") + @Size(max = 512) + private String remark; + +- @ApiModelProperty(value = "sort order") ++ @ApiModelProperty(value = "排序序号") + private Integer sortOrder; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java +index a19ae8a..eae3469 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/NodeCreateRequest.java +@@ -37,10 +37,10 @@ public class NodeCreateRequest { + @ApiModelProperty(value = "纬度", example = "26.872108") + private BigDecimal latitude; + +- @ApiModelProperty(value = "关联资源类型:SCENIC_SPOT/HOTEL/RESTAURANT/ACTIVITY/VEHICLE/SERVICE", example = "SCENIC_SPOT") ++ @ApiModelProperty(value = "关联资源类型(关联后可从资源服务获取价格参与成本计算):SCENIC/HOTEL/RESTAURANT/ACTIVITY/VEHICLE/SERVICE", example = "SCENIC") + private String resourceType; + +- @ApiModelProperty(value = "关联资源ID", example = "1893012345678901234") ++ @ApiModelProperty(value = "关联资源ID(来自资源服务,关联后节点名称和图片可自动同步)", example = "1893012345678901234") + private String resourceId; + + @ApiModelProperty(value = "节点描述", example = "漫步古城,感受纳西文化") +@@ -58,6 +58,6 @@ public class NodeCreateRequest { + @ApiModelProperty(value = "数量", example = "1") + private Integer quantity; + +- @ApiModelProperty(value = "所属家庭ID列表(定制产品按家庭分配)") ++ @ApiModelProperty(value = "所属家庭ID列表(仅CUSTOM定制产品使用,实现按家庭分配行程节点)") + private List familyIds; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java +index a5188da..dacb69c 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/PriceCalendarRequest.java +@@ -28,13 +28,13 @@ public class PriceCalendarRequest { + @ApiModelProperty(value = "儿童成本价", example = "1800.00") + private BigDecimal childCostPrice; + +- @ApiModelProperty(value = "是否自动计算成本", example = "true") ++ @ApiModelProperty(value = "是否自动计算成本(true时重新测算会自动更新此日期的价格)", example = "true") + private Boolean costAutoCalc; + +- @ApiModelProperty(value = "库存数量", example = "30") ++ @ApiModelProperty(value = "库存数量(CORE/GROUP按人头扣减,CUSTOM/ROUTE按单扣减)", example = "30") + private Integer stock; + +- @ApiModelProperty(value = "状态:OPEN=开放 CLOSED=关闭", example = "OPEN") ++ @ApiModelProperty(value = "状态:OPEN=开放预订 CLOSED=关闭(不可预订)", example = "OPEN") + private String status; + + @ApiModelProperty(value = "备注", example = "五一黄金周特价") +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java +index 28b7e49..a937367 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/PricingRequest.java +@@ -11,10 +11,10 @@ import java.util.List; + @ApiModel("定价配置请求") + public class PricingRequest { + +- @ApiModelProperty(value = "定价模式:AUTO=自动计算 MANUAL=手动定价 CUSTOM=定制定价", example = "AUTO") ++ @ApiModelProperty(value = "定价模式:AUTO=根据行程资源价格自动计算 MANUAL=手动在价格日历设置每日价格 CUSTOM=定制产品整单定价", example = "AUTO") + private String pricingMode; + +- @ApiModelProperty(value = "利润模式:FIXED=固定金额 PERCENT=百分比", example = "FIXED") ++ @ApiModelProperty(value = "利润模式(AUTO模式下生效):FIXED=在成本基础上加固定金额 PERCENT=在成本基础上按百分比加价", example = "FIXED") + private String profitMode; + + @ApiModelProperty(value = "利润金额(FIXED模式下使用)", example = "500.00") +@@ -32,16 +32,16 @@ public class PricingRequest { + @ApiModelProperty(value = "餐费预算", example = "100.00") + private BigDecimal mealBudget; + +- @ApiModelProperty(value = "儿童占床价", example = "1800.00") ++ @ApiModelProperty(value = "儿童加床费(childNeedBed=true时额外加收的费用)", example = "1800.00") + private BigDecimal childWithBed; + +- @ApiModelProperty(value = "儿童不占床价", example = "1200.00") ++ @ApiModelProperty(value = "儿童不占床价(暂未使用,预留字段)", example = "1200.00") + private BigDecimal childNoBed; + +- @ApiModelProperty(value = "婴儿价", example = "300.00") ++ @ApiModelProperty(value = "婴儿固定价格(不随日期变化)", example = "300.00") + private BigDecimal babyPrice; + +- @ApiModelProperty(value = "儿童折扣百分比", example = "70.00") ++ @ApiModelProperty(value = "小童折扣百分比(小童价=儿童价×此百分比/100,如70表示打7折)", example = "70.00") + private BigDecimal childDiscountPercent; + + @ApiModelProperty(value = "车型ID列表") +@@ -56,24 +56,24 @@ public class PricingRequest { + @ApiModelProperty(value = "陪同人员价格", example = "0.00") + private BigDecimal companionPrice; + +- @ApiModelProperty(value = "定制产品总价(CUSTOM模式下使用)", example = "28800.00") ++ @ApiModelProperty(value = "定制产品总价(CUSTOM定价模式下使用,代表整单总价)", example = "28800.00") + private BigDecimal customTotalPrice; + +- @ApiModelProperty(value = "最小成团人数", example = "2") ++ @ApiModelProperty(value = "最小成团人数(CORE/GROUP产品用,影响均摊成本计算)", example = "2") + private Integer minGroupSize; + +- @ApiModelProperty(value = "最大成团人数", example = "16") ++ @ApiModelProperty(value = "最大成团人数(CORE/GROUP产品用)", example = "16") + private Integer maxGroupSize; + +- @ApiModelProperty(value = "支付方式:FULL=全款 DEPOSIT=定金+尾款", example = "FULL") ++ @ApiModelProperty(value = "支付方式:FULL=全款支付 DEPOSIT=定金+尾款分期支付", example = "FULL") + private String paymentType; + +- @ApiModelProperty(value = "定金比例(百分比)", example = "30") ++ @ApiModelProperty(value = "定金比例(百分比,如30代表30%。与depositAmount二选一,优先使用比例)", example = "30") + private Integer depositRatio; + +- @ApiModelProperty(value = "定金金额", example = "1000.00") ++ @ApiModelProperty(value = "定金金额(固定金额,与depositRatio二选一)", example = "1000.00") + private BigDecimal depositAmount; + +- @ApiModelProperty(value = "尾款支付截止天数(出发前N天)", example = "7") ++ @ApiModelProperty(value = "尾款支付截止天数(出发前N天必须支付尾款,超时可能取消订单)", example = "7") + private Integer balanceDueDays; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java +index 23e1203..99033be 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/ProductStatusRequest.java +@@ -10,10 +10,11 @@ import javax.validation.constraints.NotBlank; + @ApiModel("产品状态变更请求") + public class ProductStatusRequest { + +- @ApiModelProperty(value = "目标状态:DRAFT/PENDING_REVIEW/REVIEWED/REJECTED/PUBLISHED/UNPUBLISHED/COMPLETED", required = true, example = "PUBLISHED") ++ @ApiModelProperty(value = "目标状态。核心/小蒙马:DRAFT/PENDING_REVIEW/REVIEWED/REJECTED/PUBLISHED/UNPUBLISHED;定制产品:COMPLETED", ++ required = true, example = "PUBLISHED") + @NotBlank(message = "目标状态不能为空") + private String status; + +- @ApiModelProperty(value = "状态变更原因(驳回时必填)", example = "行程信息不完整,请补充") ++ @ApiModelProperty(value = "状态变更原因(驳回时必填;上架/下架审批时可填)", example = "行程信息不完整,请补充") + private String reason; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java b/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java +index fd39d97..92c28aa 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/dto/QuoteRequest.java +@@ -21,18 +21,18 @@ public class QuoteRequest { + @Min(value = 1, message = "成人人数最少1人") + private Integer adultCount; + +- @ApiModelProperty(value = "儿童人数(占床)", example = "1") ++ @ApiModelProperty(value = "儿童人数(占床,按儿童价计算)", example = "1") + @Min(value = 0, message = "儿童人数不能为负数") + private Integer childCount = 0; + +- @ApiModelProperty(value = "小童人数(不占床)", example = "0") ++ @ApiModelProperty(value = "小童人数(不占床,按儿童价 × childDiscountPercent 折扣比例计算)", example = "0") + @Min(value = 0, message = "小童人数不能为负数") + private Integer youngChildCount = 0; + +- @ApiModelProperty(value = "婴儿人数", example = "0") ++ @ApiModelProperty(value = "婴儿人数(按固定 babyPrice 计算)", example = "0") + @Min(value = 0, message = "幼童人数不能为负数") + private Integer babyCount = 0; + +- @ApiModelProperty(value = "儿童是否加床", example = "false") ++ @ApiModelProperty(value = "儿童是否加床(true 时额外加收 childWithBed 费用)", example = "false") + private Boolean childNeedBed = false; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java +index 46060ff..63b4dc9 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/BatchMaterialIdsRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("批量素材ID请求") + public class BatchMaterialIdsRequest { + ++ @ApiModelProperty("素材ID列表") + private List materialIds; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java +index e859cea..53c0c3d 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchBindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("批量引用绑定请求") + public class RefBatchBindRequest { + ++ @ApiModelProperty("引用绑定列表") + private List refs; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java +index 965c0e9..b532ee1 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBatchUnbindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -9,7 +11,9 @@ import java.util.List; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("批量引用解绑请求") + public class RefBatchUnbindRequest { + ++ @ApiModelProperty("引用解绑列表") + private List refs; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java +index 8d95b02..16fdb65 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefBindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,11 +9,21 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("引用绑定请求") + public class RefBindRequest { + ++ @ApiModelProperty("素材ID") + private Long materialId; ++ ++ @ApiModelProperty("业务类型") + private String bizType; ++ ++ @ApiModelProperty("业务ID") + private Long bizId; ++ ++ @ApiModelProperty("业务名称") + private String bizName; ++ ++ @ApiModelProperty("用途类型") + private String usageType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java +index 04252db..cdd7901 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/RefUnbindRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,10 +9,18 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("引用解绑请求") + public class RefUnbindRequest { + ++ @ApiModelProperty("素材ID") + private Long materialId; ++ ++ @ApiModelProperty("业务类型") + private String bizType; ++ ++ @ApiModelProperty("业务ID") + private Long bizId; ++ ++ @ApiModelProperty("用途类型") + private String usageType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java +index da0d81d..9188dfb 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourceCoverQuery.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Data; + import lombok.NoArgsConstructor; +@@ -7,7 +9,12 @@ import lombok.NoArgsConstructor; + @Data + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源封面查询") + public class ResourceCoverQuery { ++ ++ @ApiModelProperty("资源类型") + private String resourceType; ++ ++ @ApiModelProperty("资源ID") + private String resourceId; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java +index 90b98cf..685d2e0 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/dto/ResourcePriceQuery.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Builder; + import lombok.Data; +@@ -12,16 +14,21 @@ import java.util.List; + @Builder + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源价格查询") + public class ResourcePriceQuery { + ++ @ApiModelProperty("资源ID列表") + private List resourceIds; + ++ @ApiModelProperty("人员类型列表") + private List staffTypes; + ++ @ApiModelProperty("开始日期") + private LocalDate startDate; + ++ @ApiModelProperty("结束日期") + private LocalDate endDate; + +- /** resource sub-type (e.g. room_type_id for hotel, vehicle category for vehicle) */ ++ @ApiModelProperty("资源子类型(如酒店房型ID、车辆类别)") + private String subType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java +index d072f29..ec5b204 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/MaterialVO.java +@@ -1,13 +1,25 @@ + package com.hulalv.product.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + @Data ++@ApiModel("素材信息VO") + public class MaterialVO { + ++ @ApiModelProperty("素材ID") + private String materialId; ++ ++ @ApiModelProperty("OSS访问URL") + private String ossUrl; ++ ++ @ApiModelProperty("缩略图URL") + private String thumbnailUrl; ++ ++ @ApiModelProperty("素材名称") + private String materialName; ++ ++ @ApiModelProperty("文件类型") + private String fileType; + } +``` + +### `hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java` (M) + +```diff +diff --git a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java +index 4cf6dae..232915a 100644 +--- a/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java ++++ b/hl-product-service/src/main/java/com/hulalv/product/feign/vo/ResourcePriceVO.java +@@ -1,5 +1,7 @@ + package com.hulalv.product.feign.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.AllArgsConstructor; + import lombok.Builder; + import lombok.Data; +@@ -12,15 +14,21 @@ import java.time.LocalDate; + @Builder + @NoArgsConstructor + @AllArgsConstructor ++@ApiModel("资源价格VO") + public class ResourcePriceVO { + ++ @ApiModelProperty("资源ID") + private Long resourceId; + ++ @ApiModelProperty("人员类型") + private String staffType; + ++ @ApiModelProperty("日期") + private LocalDate date; + ++ @ApiModelProperty("价格") + private BigDecimal price; + ++ @ApiModelProperty("资源名称") + private String resourceName; + } +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java +index ab64e9e..4015f1e 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityController.java +@@ -26,7 +26,7 @@ public class ActivityController { + + private final ActivityService activityService; + +- @ApiOperation("创建游玩项目") ++ @ApiOperation(value = "创建游玩项目", notes = "新建游玩项目资源(如漂流、骑行、篝火晚会等),初始状态为草稿(status=0)。需通过「提交启用/禁用审批」走企微审批后上架。支持按项收费(PER_ITEM)和按人收费(PER_PERSON)两种计费方式。\n\n**关联字典**:\n- activity_category:活动分类(表单选择)\n- activity_billing_type:计费方式(表单选择)") + @PostMapping("/item") + public Result createActivity( + @ApiParam("游玩项目创建请求") @Valid @RequestBody ActivityCreateRequest request, +@@ -35,19 +35,19 @@ public class ActivityController { + return Result.success(activityService.createActivity(request, adminId)); + } + +- @ApiOperation("游玩项目列表") ++ @ApiOperation(value = "游玩项目列表", notes = "分页查询游玩项目列表,支持按名称、状态、分类等条件筛选。返回摘要信息,按sortOrder倒序+创建时间倒序排列。\n\n**关联字典**:\n- activity_category:活动分类(筛选+列表显示)\n- activity_billing_type:计费方式(列表显示)") + @GetMapping("/items") + public Result> listActivities(@ApiParam("游玩项目查询请求") @Valid ActivityQueryRequest query) { + return Result.success(activityService.listActivities(query)); + } + +- @ApiOperation("游玩项目详情") ++ @ApiOperation(value = "游玩项目详情", notes = "获取游玩项目完整信息,包含富文本内容、素材URL、标签、价格日历等。\n\n**关联字典**:\n- activity_category:活动分类(详情显示)\n- activity_billing_type:计费方式(详情显示)") + @GetMapping("/item/{activityId}") + public Result getActivity(@ApiParam("游玩项目ID") @PathVariable Long activityId) { + return Result.success(activityService.getActivity(activityId)); + } + +- @ApiOperation("更新游玩项目") ++ @ApiOperation(value = "更新游玩项目", notes = "更新游玩项目基本信息,不改变当前状态。已上架的项目修改后仍保持上架。\n\n**关联字典**:\n- activity_category:活动分类(表单选择)\n- activity_billing_type:计费方式(表单选择)") + @PutMapping("/item/{activityId}") + public Result updateActivity( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -57,7 +57,7 @@ public class ActivityController { + return Result.success(activityService.updateActivity(activityId, request, adminId)); + } + +- @ApiOperation("删除游玩项目") ++ @ApiOperation(value = "删除游玩项目", notes = "软删除游玩项目。仅SUPER_ADMIN或创建者可操作。删除后关联的素材引用会被清理。") + @DeleteMapping("/item/{activityId}") + public Result deleteActivity( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -68,7 +68,7 @@ public class ActivityController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。审批通过后自动更新状态,返回审批单号spNo。") + @PostMapping("/item/{activityId}/submit-approval") + public Result> submitApproval( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -80,7 +80,7 @@ public class ActivityController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("启用/禁用切换") ++ @ApiOperation(value = "启用/禁用切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{activityId}/status") + public Result updateStatus( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -91,7 +91,7 @@ public class ActivityController { + return Result.success(); + } + +- @ApiOperation("批量启用/禁用") ++ @ApiOperation(value = "批量启用/禁用", notes = "批量修改多个游玩项目的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("游玩项目状态请求") @Valid @RequestBody ActivityStatusRequest request, +@@ -103,7 +103,7 @@ public class ActivityController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个游玩项目。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java +index 9fec542..3fff48f 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityPriceCalendarController.java +@@ -25,7 +25,7 @@ public class ActivityPriceCalendarController { + + private final ActivityPriceCalendarService priceService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询游玩项目的每日价格和可接待状态。") + @GetMapping("/item/{activityId}/prices") + public Result getPriceCalendar( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -34,7 +34,7 @@ public class ActivityPriceCalendarController { + return Result.success(priceService.getPriceCalendar(activityId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置成本价和可接待状态。支持按星期过滤和排除特定日期。") + @PutMapping("/item/{activityId}/prices") + public Result batchSetPrices( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -43,7 +43,7 @@ public class ActivityPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改可接待状态") ++ @ApiOperation(value = "批量修改可接待状态", notes = "批量修改指定日期范围内的可接待状态,不影响价格。") + @PutMapping("/item/{activityId}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -52,7 +52,7 @@ public class ActivityPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量清除价格") ++ @ApiOperation(value = "批量清除价格", notes = "删除指定日期范围内的所有价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/item/{activityId}/prices") + public Result deletePrices( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java +index 2a01cd2..80b72a0 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/ActivityTagController.java +@@ -27,7 +27,7 @@ public class ActivityTagController { + + private final ActivityTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询游玩项目标签库,支持按关键词搜索。包含预设标签和自定义标签。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class ActivityTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于项目编辑时的标签选择下拉。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。可指定颜色(tagColor),默认#409EFF。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class ActivityTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。用于项目编辑时快速输入新标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class ActivityTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色,所有关联项目自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class ActivityTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并自动解除所有项目与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新项目标签") ++ @ApiOperation(value = "更新项目标签", notes = "全量替换指定项目的标签列表。传入tagIds为最终关联的标签ID列表,为空则清除所有标签。") + @PutMapping("/item/{activityId}/tags") + public Result updateActivityTags( + @ApiParam("游玩项目ID") @PathVariable Long activityId, +@@ -87,7 +87,7 @@ public class ActivityTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个项目批量添加/移除标签。增量操作,不影响未指定的标签。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java +index e24ce98..1b5dd8f 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalActivityController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】游玩项目(Feign调用)") ++@Api(tags = "【内部接口】游玩项目(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/activity") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalActivityController { + + private final ActivityService activityService; + +- @ApiOperation("获取项目简要信息") ++ @ApiOperation(value = "获取项目简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个游玩项目的简要信息,返回ID、名称、分类编码、计费类型、状态。不存在时返回错误。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{activityId}") + public Result> getActivityBrief(@PathVariable Long activityId) { + Activity item = activityService.getActivityEntity(activityId); +@@ -41,7 +41,7 @@ public class InternalActivityController { + return Result.success(brief); + } + +- @ApiOperation("批量获取项目简要信息") ++ @ApiOperation(value = "批量获取项目简要信息", notes = "【仅限内部Feign调用】批量获取游玩项目简要信息,最多500个ID。不存在的ID自动过滤,返回实际找到的项目列表。供产品服务批量查询行程节点绑定的活动资源。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getActivityBatch(@RequestParam @Size(max = 500) List activityIds) { + List> results = activityIds.stream() +@@ -61,9 +61,9 @@ public class InternalActivityController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo(审批单号)匹配游玩项目并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + activityService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java +index 63164c0..03e9f1d 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/activity/controller/InternalMpActivityController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; + /** + * C端活动内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序活动(Feign调用)") ++@Api(tags = "【内部接口】小程序活动(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/activity") + @RequiredArgsConstructor +@@ -22,14 +22,14 @@ public class InternalMpActivityController { + + private final ActivityService activityService; + +- @ApiOperation("C端活动列表") ++ @ApiOperation(value = "C端活动列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架活动,支持分页和筛选。C端用户通过小程序间接访问。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- environment_type(环境类型,返回字段environmentType):INDOOR=室内, OUTDOOR=户外, MIXED=混合") + @GetMapping("/list") + public Result> listActivities(ActivityQueryRequest query) { + query.setStatus(1); + return Result.success(activityService.listActivities(query)); + } + +- @ApiOperation("C端活动详情") ++ @ApiOperation(value = "C端活动详情", notes = "【仅限内部Feign调用】供mp-service获取活动完整详情,包含封面、轮播图、标签、富文本介绍等。注意:不限制status,由BFF层校验是否展示。\n\n**关联字典**:\n- activity_category(活动分类,返回字段categoryCode):OUTDOOR=户外, INDOOR=室内, CULTURAL=文化, ADVENTURE=探险\n- environment_type(环境类型,返回字段environmentType):INDOOR=室内, OUTDOOR=户外, MIXED=混合") + @GetMapping("/{activityId}") + public Result getActivityDetail(@PathVariable Long activityId) { + ActivityVO vo = activityService.getActivity(activityId); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/config/Knife4jConfig.java b/hl-resource-service/src/main/java/com/hulalv/resource/config/Knife4jConfig.java +index 88feb5b..21cce9b 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/config/Knife4jConfig.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/config/Knife4jConfig.java +@@ -1,5 +1,6 @@ + package com.hulalv.resource.config; + ++import com.google.common.base.Predicate; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + import springfox.documentation.builders.ApiInfoBuilder; +@@ -11,12 +12,18 @@ import springfox.documentation.spring.web.plugins.Docket; + /** + * Knife4j API文档配置(9个资源领域分组) + *

+- * 为每个资源领域创建独立的API文档分组,便于分类查阅接口 ++ * 为每个资源领域创建独立的API文档分组,便于分类查阅接口。 ++ * 内部Feign接口(/internal/路径)不在文档中展示。 + *

+ */ + @Configuration + public class Knife4jConfig { + ++ /** 排除内部接口路径 */ ++ private Predicate adminPaths() { ++ return input -> input != null && !input.contains("/internal/") && !input.contains("/callback/"); ++ } ++ + /** 景区管理API分组 */ + @Bean + public Docket scenicApi() { +@@ -29,7 +36,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.scenic.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -45,7 +52,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.restaurant.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -61,7 +68,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.supplies.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -77,7 +84,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.activity.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -93,7 +100,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.hotel.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -109,7 +116,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.service.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -125,7 +132,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.vehicle.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -141,7 +148,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.cost.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + +@@ -157,7 +164,7 @@ public class Knife4jConfig { + .build()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.hulalv.resource.staff.controller")) +- .paths(PathSelectors.any()) ++ .paths(adminPaths()) + .build(); + } + } +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java +index 3fcaf95..a7c45f5 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalMpResourceBriefController.java +@@ -40,7 +40,7 @@ import java.util.stream.Collectors; + */ + @Slf4j + @Validated +-@Api(tags = "【内部接口】资源摘要(Feign调用)") ++@Api(tags = "【内部接口】资源摘要(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/resource") + @RequiredArgsConstructor +@@ -60,7 +60,7 @@ public class InternalMpResourceBriefController { + + private final MaterialRefFeignClient materialRefClient; + +- @ApiOperation("批量查询景区摘要") ++ @ApiOperation(value = "批量查询景区摘要", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用(收藏列表/足迹列表),返回最小化信息:id、name、coverUrl、tags。最多500个ID。") + @GetMapping("/scenic/brief") + public Result>> getScenicBrief(@RequestParam @Size(max = 500) List ids) { + if (ids == null || ids.isEmpty()) { +@@ -94,7 +94,7 @@ public class InternalMpResourceBriefController { + return Result.success(result); + } + +- @ApiOperation("批量查询餐厅摘要") ++ @ApiOperation(value = "批量查询餐厅摘要", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用,返回最小化信息。最多500个ID。") + @GetMapping("/restaurant/brief") + public Result>> getRestaurantBrief(@RequestParam @Size(max = 500) List ids) { + if (ids == null || ids.isEmpty()) { +@@ -126,7 +126,7 @@ public class InternalMpResourceBriefController { + return Result.success(result); + } + +- @ApiOperation("批量查询活动摘要") ++ @ApiOperation(value = "批量查询活动摘要", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用,返回最小化信息。最多500个ID。") + @GetMapping("/activity/brief") + public Result>> getActivityBrief(@RequestParam @Size(max = 500) List ids) { + if (ids == null || ids.isEmpty()) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java +index d4158a8..44cd22e 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceController.java +@@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.*; + *

+ */ + @Slf4j +-@Api(tags = "【内部接口】资源审批(Feign调用)") ++@Api(tags = "【内部接口】资源审批(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/resource") + @RequiredArgsConstructor +@@ -42,9 +42,9 @@ public class InternalResourceController { + private final StaffService staffService; + + /** 处理审批回调 - 分发到9个资源领域服务 */ +- @ApiOperation("处理审批回调 - 分发到9个资源领域服务") ++ @ApiOperation(value = "处理审批回调 - 分发到9个资源领域服务", notes = "【仅限内部Feign调用】接收企微审批回调结果,按thirdNo(审批单号)在9个资源领域中匹配并更新状态。每个领域服务内部通过approval_no匹配,未找到则忽略(幂等处理)。由hl-callback-service通过MQ消费后调用。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + + // 分发到9个领域服务 - 每个服务内部检查approval_no +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java +index a6adb66..e726a14 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceDetailController.java +@@ -41,7 +41,7 @@ import java.util.stream.Collectors; + * 供产品服务的行程节点获取绑定资源的详细信息(含图片、地址等) + */ + @Slf4j +-@Api(tags = "【内部接口】资源详情(Feign调用)") ++@Api(tags = "【内部接口】资源详情(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/resource") + @RequiredArgsConstructor +@@ -69,7 +69,7 @@ public class InternalResourceDetailController { + * @param activityIds 活动ID列表 + * @return resourceType:resourceId → ResourceDetailDTO + */ +- @ApiOperation("批量查询资源详情(行程节点用)") ++ @ApiOperation(value = "批量查询资源详情(行程节点用)", notes = "【仅限内部Feign调用】供产品服务获取行程节点绑定资源的详细信息。按类型分组查询,返回Map。包含封面、轮播图URL、地址、坐标、标签、富文本介绍等完整信息。\n\n**关联字典**:\n- city(城市,返回字段city)") + @GetMapping("/batch-details") + public Result> batchDetails( + @RequestParam(required = false) List scenicIds, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java +index 366168b..e1ddd03 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourcePriceController.java +@@ -53,7 +53,7 @@ import java.util.stream.Collectors; + @RestController + @RequestMapping("/internal/resource/prices") + @RequiredArgsConstructor +-@Api(tags = "【内部接口】资源价格(Feign调用)") ++@Api(tags = "【内部接口】资源价格(Feign调用)", hidden = true) + public class InternalResourcePriceController { + + private final ScenicPriceCalendarMapper scenicPriceMapper; +@@ -71,7 +71,7 @@ public class InternalResourcePriceController { + private final SuppliesItemMapper suppliesItemMapper; + private final SuppliesService suppliesService; + +- /** 查询景区价格 */ ++ /** 查询景区价格 - 按景区ID和日期范围查询价格日历的成本价 */ + @PostMapping("/scenic") + public Result> getScenicPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -108,7 +108,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询酒店价格(按hotelId查最低房型价格) */ ++ /** 查询酒店价格 - 按hotelId查询日期范围内最低房型的成本价(取所有房型中最低价) */ + @PostMapping("/hotel") + public Result> getHotelPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -143,7 +143,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询房型价格(按roomTypeId精确查询) */ ++ /** 查询房型价格 - 按roomTypeId精确查询日期范围内的成本价(取最低价) */ + @PostMapping("/room-type") + public Result> getRoomTypePrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -178,7 +178,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询活动价格 */ ++ /** 查询活动价格 - 按活动ID和日期范围查询价格日历的成本价 */ + @PostMapping("/activity") + public Result> getActivityPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -214,7 +214,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询车辆价格 */ ++ /** 查询车辆价格 - 按车型ID和日期范围查询价格日历的成本价 */ + @PostMapping("/vehicle") + public Result> getVehiclePrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -250,7 +250,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询服务项价格 */ ++ /** 查询服务项价格 - 按服务项ID和日期范围查询价格日历的成本价 */ + @PostMapping("/service") + public Result> getServicePrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -283,13 +283,13 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询餐厅价格(餐厅无价格日历,返回空) */ ++ /** 查询餐厅价格 - 餐厅无独立价格日历,始终返回空列表(餐费通过费用项管理) */ + @PostMapping("/restaurant") + public Result> getRestaurantPrices(@RequestBody PriceQuery query) { + return Result.success(new ArrayList<>()); + } + +- /** 查询服务人员价格(按人员类型) */ ++ /** 查询服务人员价格 - 按staffType(人员类型)和日期范围查询价格日历的成本价(人员价格按类型而非个人) */ + @PostMapping("/staff") + public Result> getStaffPrices(@RequestBody PriceQuery query) { + List results = new ArrayList<>(); +@@ -321,7 +321,7 @@ public class InternalResourcePriceController { + return Result.success(results); + } + +- /** 查询酒店下所有房型(简要信息) */ ++ /** 查询酒店下所有已启用房型 - 返回roomTypeId、name、maxOccupancy、basePrice,按sortOrder排序 */ + @GetMapping("/room-types-by-hotel/{hotelId}") + public Result> getRoomTypesByHotel(@PathVariable Long hotelId) { + List roomTypes = roomTypeMapper.selectList( +@@ -336,7 +336,7 @@ public class InternalResourcePriceController { + return Result.success(vos); + } + +- /** 查询所有可用车型(简要信息) */ ++ /** 查询所有已启用车型 - 返回vehicleId、name、seatCount、basePrice,按sortOrder排序,供产品服务车辆下拉选择使用 */ + @GetMapping("/vehicle-models") + public Result> getVehicleModels() { + List vehicles = vehicleModelMapper.selectList( +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java +index 019a26f..3ef23db 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/controller/InternalResourceStatsController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RestController; + import java.util.HashMap; + import java.util.Map; + +-@Api(tags = "【内部接口】资源统计(Feign调用)") ++@Api(tags = "【内部接口】资源统计(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/resource") + @RequiredArgsConstructor +@@ -24,7 +24,7 @@ public class InternalResourceStatsController { + private final RoomTypeMapper roomTypeMapper; + private final VehicleModelMapper vehicleModelMapper; + +- @ApiOperation("获取酒店统计") ++ @ApiOperation(value = "获取酒店统计", notes = "【仅限内部Feign调用】返回酒店总数和房型总数,供管理后台仪表盘展示。") + @GetMapping("/hotel/stats") + public Result> getHotelStats() { + long totalHotels = hotelMapper.selectCount(null); +@@ -36,7 +36,7 @@ public class InternalResourceStatsController { + return Result.success(stats); + } + +- @ApiOperation("获取车辆统计") ++ @ApiOperation(value = "获取车辆统计", notes = "【仅限内部Feign调用】返回车型总数,供管理后台仪表盘展示。") + @GetMapping("/vehicle/stats") + public Result> getVehicleStats() { + long totalVehicles = vehicleModelMapper.selectCount(null); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java +index ce21f8c..b138078 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostItemController.java +@@ -28,7 +28,7 @@ public class CostItemController { + + private final CostItemService costItemService; + +- @ApiOperation("创建费用项") ++ @ApiOperation(value = "创建费用项", notes = "新建费用项(如门票成本、餐费、保险费等),用于产品报价计算。费用项有独立的价格日历,价格变更会记录变更日志。创建后需走企微审批上架。\n\n**关联字典**:\n- cost_category:费用分类(表单选择)\n- cost_apply_role:适用角色(表单选择)\n- cost_unit:计量单位(表单选择)") + @PostMapping("/item") + public Result createCostItem(@ApiParam("费用项创建请求") @Valid @RequestBody CostItemCreateRequest request, + HttpServletRequest httpRequest) { +@@ -36,19 +36,19 @@ public class CostItemController { + return Result.success(costItemService.createCostItem(request, adminId)); + } + +- @ApiOperation("费用项列表") ++ @ApiOperation(value = "费用项列表", notes = "分页查询费用项列表,支持按名称、状态等条件筛选。\n\n**关联字典**:\n- cost_category:费用分类(筛选+列表显示)\n- cost_apply_role:适用角色(筛选+列表显示)\n- cost_unit:计量单位(列表显示)") + @GetMapping("/items") + public Result> listCostItems(@ApiParam("费用项查询请求") @Valid CostItemQueryRequest query) { + return Result.success(costItemService.listCostItems(query)); + } + +- @ApiOperation("费用项详情") ++ @ApiOperation(value = "费用项详情", notes = "获取费用项完整信息,包含当前价格、引用计数等。\n\n**关联字典**:\n- cost_category:费用分类(详情显示)\n- cost_apply_role:适用角色(详情显示)\n- cost_unit:计量单位(详情显示)") + @GetMapping("/item/{costId}") + public Result getCostItem(@ApiParam("费用项ID") @PathVariable Long costId) { + return Result.success(costItemService.getCostItem(costId)); + } + +- @ApiOperation("更新费用项") ++ @ApiOperation(value = "更新费用项", notes = "更新费用项信息。如果修改了价格,会自动记录价格变更日志。\n\n**关联字典**:\n- cost_category:费用分类(表单选择)\n- cost_apply_role:适用角色(表单选择)\n- cost_unit:计量单位(表单选择)") + @PutMapping("/item/{costId}") + public Result updateCostItem(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("费用项更新请求") @Valid @RequestBody CostItemUpdateRequest request, +@@ -57,7 +57,7 @@ public class CostItemController { + return Result.success(costItemService.updateCostItem(costId, request, adminId)); + } + +- @ApiOperation("删除费用项") ++ @ApiOperation(value = "删除费用项", notes = "软删除费用项。仅SUPER_ADMIN或创建者可操作。被产品引用(refCount>0)的费用项不建议删除。") + @DeleteMapping("/item/{costId}") + public Result deleteCostItem(@ApiParam("费用项ID") @PathVariable Long costId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -66,7 +66,7 @@ public class CostItemController { + return Result.success(); + } + +- @ApiOperation("提交审批") ++ @ApiOperation(value = "提交审批", notes = "向企微OA提交费用项启用/禁用审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{costId}/submit-approval") + public Result> submitApproval(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("审批提交请求体") @Valid @RequestBody ApprovalSubmitRequest request, +@@ -76,13 +76,13 @@ public class CostItemController { + return Result.success(java.util.Map.of("spNo", spNo)); + } + +- @ApiOperation("启用的费用项列表") ++ @ApiOperation(value = "启用的费用项列表", notes = "查询所有已启用(status=1)的费用项,不分页。用于产品编排时选择费用项的下拉列表。\n\n**关联字典**:\n- cost_category:费用分类(列表显示)\n- cost_apply_role:适用角色(列表显示)\n- cost_unit:计量单位(列表显示)") + @GetMapping("/items/enabled") + public Result> listEnabledCostItems() { + return Result.success(costItemService.listEnabledCostItems()); + } + +- @ApiOperation("费用项价格变更记录") ++ @ApiOperation(value = "费用项价格变更记录", notes = "查询费用项的历史价格变更记录,按时间倒序排列。用于追溯价格调整历史。") + @GetMapping("/item/{costId}/price-logs") + public Result> getPriceLogs(@ApiParam("费用项ID") @PathVariable Long costId) { + return Result.success(costItemService.getPriceLogs(costId)); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java +index 862c1b2..95007f0 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/CostPriceCalendarController.java +@@ -26,7 +26,7 @@ public class CostPriceCalendarController { + + private final CostPriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询费用项的每日价格。费用项价格日历用于产品报价计算时按日期获取成本价。") + @GetMapping("/item/{costId}/prices") + public Result getPriceCalendar(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("年份") @RequestParam @Min(2020) @Max(2100) Integer year, +@@ -34,7 +34,7 @@ public class CostPriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(costId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置费用项的成本价。") + @PutMapping("/item/{costId}/prices") + public Result batchSetPrices(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("价格日历设置请求") @Valid @RequestBody PriceCalendarSetRequest request) { +@@ -42,7 +42,7 @@ public class CostPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("清除价格日历") ++ @ApiOperation(value = "清除价格日历", notes = "删除指定日期范围内费用项的价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/item/{costId}/prices") + public Result deletePrices(@ApiParam("费用项ID") @PathVariable Long costId, + @ApiParam("开始日期") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java +index 5e27f64..361c8de 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/cost/controller/InternalCostController.java +@@ -20,7 +20,7 @@ import java.util.Map; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】费用项(Feign调用)") ++@Api(tags = "【内部接口】费用项(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/cost") + @RequiredArgsConstructor +@@ -28,21 +28,21 @@ public class InternalCostController { + + private final CostItemService costItemService; + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配费用项并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + costItemService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); + } + +- @ApiOperation("批量获取费用项") ++ @ApiOperation(value = "批量获取费用项", notes = "【仅限内部Feign调用】批量获取费用项完整信息(含名称、分类、计费类型、基础价格等),最多500个ID。供产品服务批量查询产品关联的费用项。\n\n**关联字典**:\n- cost_unit(计费单位,返回字段unit):PER_PERSON=元/人, PER_VEHICLE=元/台, PER_DAY=元/天, PER_TIME=元/次, PER_ROOM=元/间, PER_TABLE=元/桌, FIXED=固定金额\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result> batchGetCostItems(@RequestParam @Size(max = 500) List costIds) { + return Result.success(costItemService.batchGetCostItems(costIds)); + } + +- @ApiOperation("按日期获取费用项价格") ++ @ApiOperation(value = "按日期获取费用项价格", notes = "【仅限内部Feign调用】按指定日期批量查询费用项的成本价格。返回Map。优先取价格日历,无日历则取basePrice。供产品服务报价计算器使用。") + @GetMapping("/items/prices-by-date") + public Result> getByDatePrices( + @RequestParam @Size(max = 500) List costIds, +@@ -50,7 +50,7 @@ public class InternalCostController { + return Result.success(costItemService.getByDatePrices(costIds, date)); + } + +- @ApiOperation("更新引用计数") ++ @ApiOperation(value = "更新引用计数", notes = "【仅限内部Feign调用】更新费用项的引用计数。delta>0表示新增引用,delta<0表示减少引用。供产品服务在关联/取消关联费用项时调用,用于统计资源被使用次数。") + @PostMapping("/item/{costId}/ref-count") + public Result updateRefCount(@PathVariable Long costId, @RequestParam int delta) { + costItemService.updateRefCount(costId, delta); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java +index 4a0c2c5..7faaef1 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelController.java +@@ -26,7 +26,7 @@ public class HotelController { + + private final HotelService hotelService; + +- @ApiOperation("创建住宿") ++ @ApiOperation(value = "创建住宿", notes = "新建住宿资源(酒店/民宿/营地等),初始状态为草稿(status=0)。创建后需通过「提交启用/禁用审批」走企微OA审批流程才能上架。住宿下可继续创建房型(RoomType),房型有独立的价格日历。\n\n**关联字典**:\n- hotel_type:住宿类型(表单选择)\n- hotel_star_level:酒店星级(表单选择)\n- hotel_facility:酒店设施(表单多选)") + @PostMapping("/item") + public Result createHotel( + @ApiParam("住宿创建请求") @Valid @RequestBody HotelCreateRequest request, +@@ -35,25 +35,25 @@ public class HotelController { + return Result.success(hotelService.createHotel(request, adminId)); + } + +- @ApiOperation("住宿列表") ++ @ApiOperation(value = "住宿列表", notes = "分页查询住宿列表,支持按名称关键词、状态、住宿类型等条件筛选。返回列表摘要信息,按sortOrder倒序+创建时间倒序排列。\n\n**关联字典**:\n- hotel_type:住宿类型(筛选+列表显示)\n- hotel_star_level:酒店星级(筛选+列表显示)\n- hotel_facility:酒店设施(列表显示)") + @GetMapping("/items") + public Result> listHotels(@ApiParam("住宿查询请求") @Valid HotelQueryRequest query) { + return Result.success(hotelService.listHotels(query)); + } + +- @ApiOperation("所有启用的住宿(不分页,仅ID和名称)") ++ @ApiOperation(value = "所有启用的住宿(不分页,仅ID和名称)", notes = "返回所有已上架(status=1)的住宿简要信息,用于下拉选择框。每项只含hotelId和name字段。适用于房型管理时选择所属住宿、产品编排时绑定住宿资源等场景。") + @GetMapping("/items/all-simple") + public Result>> listAllSimple() { + return Result.success(hotelService.listAllSimple()); + } + +- @ApiOperation("住宿详情") ++ @ApiOperation(value = "住宿详情", notes = "获取住宿完整信息,包含素材URL、标签列表、房型列表等。素材ID会自动解析为OSS访问地址。\n\n**关联字典**:\n- hotel_type:住宿类型(详情显示)\n- hotel_star_level:酒店星级(详情显示)\n- hotel_facility:酒店设施(详情显示)") + @GetMapping("/item/{hotelId}") + public Result getHotel(@ApiParam("住宿ID") @PathVariable Long hotelId) { + return Result.success(hotelService.getHotel(hotelId)); + } + +- @ApiOperation("更新住宿") ++ @ApiOperation(value = "更新住宿", notes = "更新住宿基本信息。更新不会改变当前状态,已上架的住宿修改后仍保持上架状态。\n\n**关联字典**:\n- hotel_type:住宿类型(表单选择)\n- hotel_star_level:酒店星级(表单选择)\n- hotel_facility:酒店设施(表单多选)") + @PutMapping("/item/{hotelId}") + public Result updateHotel( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -63,7 +63,7 @@ public class HotelController { + return Result.success(hotelService.updateHotel(hotelId, request, adminId)); + } + +- @ApiOperation("删除住宿") ++ @ApiOperation(value = "删除住宿", notes = "软删除住宿。仅SUPER_ADMIN或创建者可操作。删除住宿会同时删除其下所有房型和价格日历数据。") + @DeleteMapping("/item/{hotelId}") + public Result deleteHotel( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -74,7 +74,7 @@ public class HotelController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交住宿启用/禁用审批。targetStatus=1申请上架,targetStatus=2申请下架。审批通过后自动更新状态。返回企微审批单号spNo。") + @PostMapping("/item/{hotelId}/submit-approval") + public Result> submitApproval( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -86,7 +86,7 @@ public class HotelController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("启用/禁用切换") ++ @ApiOperation(value = "启用/禁用切换", notes = "直接修改住宿状态(跳过审批),仅限SUPER_ADMIN使用。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{hotelId}/status") + public Result updateStatus( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -97,7 +97,7 @@ public class HotelController { + return Result.success(); + } + +- @ApiOperation("批量启用/禁用") ++ @ApiOperation(value = "批量启用/禁用", notes = "批量修改多个住宿的状态,跳过审批流程。hotelIds为住宿ID列表(字符串格式)。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("住宿状态请求") @Valid @RequestBody HotelStatusRequest request, +@@ -109,7 +109,7 @@ public class HotelController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个住宿及其关联的房型和价格日历。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java +index 3b229f8..02e8708 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/HotelTagController.java +@@ -27,7 +27,7 @@ public class HotelTagController { + + private final HotelTagService tagService; + +- @ApiOperation("预设标签列表(分页)") ++ @ApiOperation(value = "预设标签列表(分页)", notes = "分页查询住宿标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class HotelTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("所有标签列表") ++ @ApiOperation(value = "所有标签列表", notes = "不分页返回所有标签,用于住宿编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class HotelTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("查找或创建自定义标签") ++ @ApiOperation(value = "查找或创建自定义标签", notes = "按名称查找标签,不存在则自动创建。用于住宿编辑时快速输入新标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class HotelTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", notes = "修改标签名称或颜色,所有关联住宿自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class HotelTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有住宿与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("设置住宿标签") ++ @ApiOperation(value = "设置住宿标签", notes = "全量替换指定住宿的标签列表。") + @PutMapping("/item/{hotelId}/tags") + public Result updateHotelTags( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -87,7 +87,7 @@ public class HotelTagController { + return Result.success(); + } + +- @ApiOperation("批量添加/移除标签") ++ @ApiOperation(value = "批量添加/移除标签", notes = "对多个住宿批量添加/移除标签。增量操作,不影响未指定的标签。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags(@ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { + List hotelIds = request.getHotelIds().stream() +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java +index c758f6e..4b81939 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalHotelController.java +@@ -18,7 +18,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】住宿(Feign调用)") ++@Api(tags = "【内部接口】住宿(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/hotel") + @RequiredArgsConstructor +@@ -27,7 +27,7 @@ public class InternalHotelController { + private final HotelService hotelService; + private final RoomTypeService roomTypeService; + +- @ApiOperation("获取住宿简要信息") ++ @ApiOperation(value = "获取住宿简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个住宿的简要信息,返回ID、名称、住宿类型、状态。不存在时返回错误。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{hotelId}") + public Result> getHotelBrief(@PathVariable Long hotelId) { + Hotel item = hotelService.getHotelEntity(hotelId); +@@ -42,7 +42,7 @@ public class InternalHotelController { + return Result.success(brief); + } + +- @ApiOperation("批量获取住宿简要信息") ++ @ApiOperation(value = "批量获取住宿简要信息", notes = "【仅限内部Feign调用】批量获取住宿简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询行程节点绑定的住宿资源。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getHotelBatch(@RequestParam @Size(max = 500) List hotelIds) { + List> results = hotelIds.stream() +@@ -61,9 +61,9 @@ public class InternalHotelController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配住宿和房型并更新启用/禁用状态。住宿和房型共享同一审批模板,此接口同时尝试匹配两者。由hl-callback-service通过MQ消费后调用。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + hotelService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + // Also try room type (same template, same callback) +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java +index ce4fd47..2a820f5 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/InternalMpHotelController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; + /** + * C端住宿内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序酒店(Feign调用)") ++@Api(tags = "【内部接口】小程序酒店(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/hotel") + @RequiredArgsConstructor +@@ -22,7 +22,7 @@ public class InternalMpHotelController { + + private final HotelService hotelService; + +- @ApiOperation("C端住宿列表") ++ @ApiOperation(value = "C端住宿列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架住宿,支持分页和筛选。C端用户通过小程序间接访问。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- hotel_star(星级,返回字段starLevel):FIVE=五星, FOUR=四星, THREE=三星, UNRATED=未评级") + @GetMapping("/list") + public Result> listHotels(HotelQueryRequest query) { + // Force status=1 for C-side (only show published hotels) +@@ -30,7 +30,7 @@ public class InternalMpHotelController { + return Result.success(hotelService.listHotels(query)); + } + +- @ApiOperation("C端住宿详情") ++ @ApiOperation(value = "C端住宿详情", notes = "【仅限内部Feign调用】供mp-service获取住宿完整详情,包含房型列表、封面、轮播图、地址等。注意:不限制status,由BFF层校验是否展示。\n\n**关联字典**:\n- hotel_type(住宿类型,返回字段hotelType):HOTEL=酒店, GUESTHOUSE=民宿, RESORT=度假村, CAMP=营地, HOMESTAY=农家院\n- hotel_star(星级,返回字段starLevel):FIVE=五星, FOUR=四星, THREE=三星, UNRATED=未评级") + @GetMapping("/{hotelId}") + public Result getHotelDetail(@PathVariable Long hotelId) { + HotelVO vo = hotelService.getHotel(hotelId); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java +index cf6df6c..d883d85 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomPriceCalendarController.java +@@ -25,7 +25,7 @@ public class RoomPriceCalendarController { + + private final RoomPriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询房型的每日价格和可售状态。每个房型有独立的价格日历。") + @GetMapping("/room-type/{roomTypeId}/prices") + public Result getPriceCalendar( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -34,7 +34,7 @@ public class RoomPriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(roomTypeId, year, month)); + } + +- @ApiOperation("批量设置价格日历") ++ @ApiOperation(value = "批量设置价格日历", notes = "在指定日期范围内批量设置房型的成本价和可售状态。支持按星期过滤和排除特定日期。") + @PutMapping("/room-type/{roomTypeId}/prices") + public Result batchSetPrices( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -43,7 +43,7 @@ public class RoomPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改日期可售状态") ++ @ApiOperation(value = "批量修改日期可售状态", notes = "批量修改指定日期范围内房型的可售状态,不影响价格。") + @PutMapping("/room-type/{roomTypeId}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -52,7 +52,7 @@ public class RoomPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("删除价格日历") ++ @ApiOperation(value = "删除价格日历", notes = "删除指定日期范围内房型的所有价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/room-type/{roomTypeId}/prices") + public Result deletePrices( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java +index 2048f4c..0d9cf42 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/hotel/controller/RoomTypeController.java +@@ -26,7 +26,7 @@ public class RoomTypeController { + + private final RoomTypeService roomTypeService; + +- @ApiOperation("创建房型") ++ @ApiOperation(value = "创建房型", notes = "在指定住宿下创建房型(如标准间、大床房、套房等)。每个房型有独立的价格日历、最大入住人数(maxOccupancy)和基础价格(basePrice)。房型初始状态为草稿(status=0),需独立审批后才能启用。创建后可通过「提交房型启用审批」接口提交企微OA审批。\n\n**关联字典**:\n- room_category:房型分类(表单选择)\n- bed_type:床型(表单选择)\n- window_type:窗户类型(表单选择)\n- bathroom_type:卫浴类型(表单选择)\n- room_facility:房间设施(表单多选)") + @PostMapping("/{hotelId}/room-type") + public Result createRoomType( + @ApiParam("住宿ID") @PathVariable Long hotelId, +@@ -36,19 +36,19 @@ public class RoomTypeController { + return Result.success(roomTypeService.createRoomType(hotelId, request, adminId)); + } + +- @ApiOperation("房型列表") ++ @ApiOperation(value = "房型列表", notes = "获取指定住宿下的所有房型列表(不分页),按sortOrder排序。\n\n**关联字典**:\n- room_category:房型分类(列表/详情显示)\n- bed_type:床型(列表/详情显示)\n- window_type:窗户类型(列表/详情显示)\n- bathroom_type:卫浴类型(列表/详情显示)\n- room_facility:房间设施(列表/详情显示)") + @GetMapping("/{hotelId}/room-types") + public Result> listRoomTypes(@ApiParam("住宿ID") @PathVariable Long hotelId) { + return Result.success(roomTypeService.listRoomTypes(hotelId)); + } + +- @ApiOperation("房型详情") ++ @ApiOperation(value = "房型详情", notes = "获取房型完整信息,包含价格、入住人数、素材等。\n\n**关联字典**:\n- room_category:房型分类(列表/详情显示)\n- bed_type:床型(列表/详情显示)\n- window_type:窗户类型(列表/详情显示)\n- bathroom_type:卫浴类型(列表/详情显示)\n- room_facility:房间设施(列表/详情显示)") + @GetMapping("/room-type/{roomTypeId}") + public Result getRoomType(@ApiParam("房型ID") @PathVariable Long roomTypeId) { + return Result.success(roomTypeService.getRoomType(roomTypeId)); + } + +- @ApiOperation("更新房型") ++ @ApiOperation(value = "更新房型", notes = "更新房型基本信息,不改变当前状态。\n\n**关联字典**:\n- room_category:房型分类(表单选择)\n- bed_type:床型(表单选择)\n- window_type:窗户类型(表单选择)\n- bathroom_type:卫浴类型(表单选择)\n- room_facility:房间设施(表单多选)") + @PutMapping("/room-type/{roomTypeId}") + public Result updateRoomType( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -58,14 +58,14 @@ public class RoomTypeController { + return Result.success(roomTypeService.updateRoomType(roomTypeId, request, adminId)); + } + +- @ApiOperation("删除房型") ++ @ApiOperation(value = "删除房型", notes = "软删除房型及其价格日历数据。") + @DeleteMapping("/room-type/{roomTypeId}") + public Result deleteRoomType(@ApiParam("房型ID") @PathVariable Long roomTypeId) { + roomTypeService.deleteRoomType(roomTypeId); + return Result.success(); + } + +- @ApiOperation("启用/禁用房型") ++ @ApiOperation(value = "启用/禁用房型", notes = "直接修改房型状态(跳过审批)。status=0禁用,status=1启用。禁用后该房型不会出现在C端展示中。") + @PutMapping("/room-type/{roomTypeId}/status") + public Result updateRoomTypeStatus( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +@@ -74,7 +74,7 @@ public class RoomTypeController { + return Result.success(); + } + +- @ApiOperation("提交房型启用/禁用审批") ++ @ApiOperation(value = "提交房型启用/禁用审批", notes = "向企微OA提交房型启用/禁用审批。审批流程与住宿共享同一模板。返回审批单号spNo。") + @PostMapping("/room-type/{roomTypeId}/submit-approval") + public Result> submitRoomTypeApproval( + @ApiParam("房型ID") @PathVariable Long roomTypeId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java +index 41d485f..df17f5c 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalMpRestaurantController.java +@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*; + /** + * C端餐厅内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序餐厅(Feign调用)") ++@Api(tags = "【内部接口】小程序餐厅(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/restaurant") + @RequiredArgsConstructor +@@ -22,7 +22,7 @@ public class InternalMpRestaurantController { + + private final RestaurantService restaurantService; + +- @ApiOperation("C端餐厅列表") ++ @ApiOperation(value = "C端餐厅列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架餐厅,支持分页和筛选。C端用户通过小程序间接访问。\n\n**关联字典**:\n- restaurant_category(餐厅分类,返回字段categoryCode):CHINESE=中餐, WESTERN=西餐, BBQ=烧烤, HOTPOT=火锅, LOCAL=当地特色") + @GetMapping("/list") + public Result> listRestaurants(RestaurantQueryRequest query) { + // Force status=1 for C-side (only show published restaurants) +@@ -30,7 +30,7 @@ public class InternalMpRestaurantController { + return Result.success(restaurantService.listRestaurants(query)); + } + +- @ApiOperation("C端餐厅详情") ++ @ApiOperation(value = "C端餐厅详情", notes = "【仅限内部Feign调用】供mp-service获取餐厅完整详情,包含封面、轮播图、标签、地址、富文本介绍等。注意:不限制status,由BFF层校验是否展示。\n\n**关联字典**:\n- restaurant_category(餐厅分类,返回字段categoryCode):CHINESE=中餐, WESTERN=西餐, BBQ=烧烤, HOTPOT=火锅, LOCAL=当地特色") + @GetMapping("/{restaurantId}") + public Result getRestaurantDetail(@PathVariable Long restaurantId) { + RestaurantVO vo = restaurantService.getRestaurant(restaurantId); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java +index ac8e4db..a87aaea 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/InternalRestaurantController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】餐厅(Feign调用)") ++@Api(tags = "【内部接口】餐厅(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/restaurant") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalRestaurantController { + + private final RestaurantService restaurantService; + +- @ApiOperation("\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f") ++ @ApiOperation(value = "\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f", notes = "\u3010\u4ec5\u9650\u5185\u90e8Feign\u8c03\u7528\u3011\u4f9b\u4ea7\u54c1\u670d\u52a1\u83b7\u53d6\u5355\u4e2a\u9910\u5385\u7684\u7b80\u8981\u4fe1\u606f\uff0c\u8fd4\u56deID\u3001\u540d\u79f0\u3001\u5206\u7c7b\u7f16\u7801\u3001\u57ce\u5e02\u3001\u72b6\u6001\u3002\u4e0d\u5b58\u5728\u65f6\u8fd4\u56de\u9519\u8bef\u3002\n\n**\u5173\u8054\u5b57\u5178**\uff1a\n- restaurant_category\uff08\u9910\u5385\u5206\u7c7b\uff0c\u8fd4\u56de\u5b57\u6bb5categoryCode\uff09\uff1aCHINESE=\u4e2d\u9910, WESTERN=\u897f\u9910, BBQ=\u70e7\u70e4, HOTPOT=\u706b\u9505, LOCAL=\u5f53\u5730\u7279\u8272\n- common_status\uff08\u72b6\u6001\uff0c\u8fd4\u56de\u5b57\u6bb5status\uff09\uff1aACTIVE=\u542f\u7528, INACTIVE=\u505c\u7528") + @GetMapping("/item/{restaurantId}") + public Result> getRestaurantBrief(@PathVariable Long restaurantId) { + Restaurant restaurant = restaurantService.getRestaurantEntity(restaurantId); +@@ -41,7 +41,7 @@ public class InternalRestaurantController { + return Result.success(brief); + } + +- @ApiOperation("\u6279\u91cf\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f") ++ @ApiOperation(value = "\u6279\u91cf\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f", notes = "\u3010\u4ec5\u9650\u5185\u90e8Feign\u8c03\u7528\u3011\u6279\u91cf\u83b7\u53d6\u9910\u5385\u7b80\u8981\u4fe1\u606f\uff0c\u6700\u591a500\u4e2aID\u3002\u4e0d\u5b58\u5728\u7684ID\u81ea\u52a8\u8fc7\u6ee4\u3002\u4f9b\u4ea7\u54c1\u670d\u52a1\u6279\u91cf\u67e5\u8be2\u884c\u7a0b\u8282\u70b9\u7ed1\u5b9a\u7684\u9910\u5385\u8d44\u6e90\u3002\n\n**\u5173\u8054\u5b57\u5178**\uff1a\n- restaurant_category\uff08\u9910\u5385\u5206\u7c7b\uff0c\u8fd4\u56de\u5b57\u6bb5categoryCode\uff09\uff1aCHINESE=\u4e2d\u9910, WESTERN=\u897f\u9910, BBQ=\u70e7\u70e4, HOTPOT=\u706b\u9505, LOCAL=\u5f53\u5730\u7279\u8272\n- common_status\uff08\u72b6\u6001\uff0c\u8fd4\u56de\u5b57\u6bb5status\uff09\uff1aACTIVE=\u542f\u7528, INACTIVE=\u505c\u7528") + @GetMapping("/items/batch") + public Result>> getRestaurantsBatch(@RequestParam @Size(max = 500) List restaurantIds) { + List> results = restaurantIds.stream() +@@ -61,9 +61,9 @@ public class InternalRestaurantController { + return Result.success(results); + } + +- @ApiOperation("\u5904\u7406\u5ba1\u6279\u56de\u8c03\u7ed3\u679c") ++ @ApiOperation(value = "\u5904\u7406\u5ba1\u6279\u56de\u8c03\u7ed3\u679c", notes = "\u3010\u4ec5\u9650\u5185\u90e8Feign\u8c03\u7528\u3011\u63a5\u6536\u4f01\u5faeOA\u5ba1\u6279\u56de\u8c03\uff0c\u6309thirdNo\u5339\u914d\u9910\u5385\u5e76\u66f4\u65b0\u542f\u7528/\u7981\u7528\u72b6\u6001\u3002\u7531hl-callback-service\u901a\u8fc7MQ\u6d88\u8d39\u540e\u8c03\u7528\uff0c\u5e42\u7b49\u5904\u7406\u3002\n\n**\u5173\u8054\u5b57\u5178**\uff1a\n- approval_sp_status\uff08\u5ba1\u6279\u72b6\u6001\uff0c\u8bf7\u6c42\u5b57\u6bb5spStatus\uff09") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + restaurantService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java +index eb8164c..7c8961f 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantController.java +@@ -26,7 +26,7 @@ public class RestaurantController { + + private final RestaurantService restaurantService; + +- @ApiOperation("创建餐厅") ++ @ApiOperation(value = "创建餐厅", notes = "新建餐厅资源,初始状态为草稿(status=0)。餐厅没有价格日历,费用通过产品报价中的费用项管理。需走企微审批流程上架。\n\n**关联字典**:\n- restaurant_category:餐厅分类(表单选择)\n- cuisine_type:菜系类型(表单多选)\n- environment_type:环境类型(表单多选)\n- restaurant_facility:餐厅设施(表单多选)\n\n**纯文本字段**:\n- cityName:城市名称(手动输入,如「拉萨」「海拉尔」)") + @PostMapping("/item") + public Result createRestaurant( + @ApiParam("餐厅创建请求") @Valid @RequestBody RestaurantCreateRequest request, +@@ -35,19 +35,19 @@ public class RestaurantController { + return Result.success(restaurantService.createRestaurant(request, adminId)); + } + +- @ApiOperation("餐厅列表") ++ @ApiOperation(value = "餐厅列表", notes = "分页查询餐厅列表,支持按名称、状态、分类、城市等条件筛选。\n\n**关联字典**:\n- restaurant_category:餐厅分类(筛选+列表显示)\n- cuisine_type:菜系类型(列表显示)\n- environment_type:环境类型(列表显示)\n- restaurant_facility:餐厅设施(列表显示)") + @GetMapping("/items") + public Result> listRestaurants(@ApiParam("餐厅查询请求") @Valid RestaurantQueryRequest query) { + return Result.success(restaurantService.listRestaurants(query)); + } + +- @ApiOperation("餐厅详情") ++ @ApiOperation(value = "餐厅详情", notes = "获取餐厅完整信息,包含素材URL、标签、富文本介绍等。\n\n**关联字典**:\n- restaurant_category:餐厅分类(详情显示)\n- cuisine_type:菜系类型(详情显示)\n- environment_type:环境类型(详情显示)\n- restaurant_facility:餐厅设施(详情显示)") + @GetMapping("/item/{restaurantId}") + public Result getRestaurant(@ApiParam("餐厅ID") @PathVariable Long restaurantId) { + return Result.success(restaurantService.getRestaurant(restaurantId)); + } + +- @ApiOperation("更新餐厅") ++ @ApiOperation(value = "更新餐厅", notes = "更新餐厅基本信息,不改变当前状态。\n\n**关联字典**:\n- restaurant_category:餐厅分类(表单选择)\n- cuisine_type:菜系类型(表单多选)\n- environment_type:环境类型(表单多选)\n- restaurant_facility:餐厅设施(表单多选)\n\n**纯文本字段**:\n- cityName:城市名称(手动输入)") + @PutMapping("/item/{restaurantId}") + public Result updateRestaurant( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -57,7 +57,7 @@ public class RestaurantController { + return Result.success(restaurantService.updateRestaurant(restaurantId, request, adminId)); + } + +- @ApiOperation("删除餐厅") ++ @ApiOperation(value = "删除餐厅", notes = "软删除餐厅。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/item/{restaurantId}") + public Result deleteRestaurant( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -68,7 +68,7 @@ public class RestaurantController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{restaurantId}/submit-approval") + public Result> submitApproval( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -80,7 +80,7 @@ public class RestaurantController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("上下架切换") ++ @ApiOperation(value = "上下架切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{restaurantId}/status") + public Result updateStatus( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -91,7 +91,7 @@ public class RestaurantController { + return Result.success(); + } + +- @ApiOperation("批量上下架") ++ @ApiOperation(value = "批量上下架", notes = "批量修改多个餐厅的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("餐厅状态请求") @Valid @RequestBody RestaurantStatusRequest request, +@@ -103,7 +103,7 @@ public class RestaurantController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个餐厅。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java +index 05b1056..7f96d5a 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/controller/RestaurantTagController.java +@@ -27,7 +27,7 @@ public class RestaurantTagController { + + private final RestaurantTagService tagService; + +- @ApiOperation("\u83b7\u53d6\u7ba1\u7406\u6807\u7b7e\u5217\u8868\uff08\u5206\u9875\uff09") ++ @ApiOperation(value = "\u83b7\u53d6\u7ba1\u7406\u6807\u7b7e\u5217\u8868\uff08\u5206\u9875\uff09", notes = "\u5206\u9875\u67e5\u8be2\u9910\u5385\u6807\u7b7e\u5e93\uff0c\u652f\u6301\u6309\u5173\u952e\u8bcd\u641c\u7d22\u3002\u5305\u542b\u9884\u8bbe\u6807\u7b7e\u548c\u81ea\u5b9a\u4e49\u6807\u7b7e\u3002") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("\u9875\u7801") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class RestaurantTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("\u83b7\u53d6\u5168\u90e8\u6807\u7b7e") ++ @ApiOperation(value = "\u83b7\u53d6\u5168\u90e8\u6807\u7b7e", notes = "\u4e0d\u5206\u9875\u8fd4\u56de\u6240\u6709\u6807\u7b7e\uff0c\u7528\u4e8e\u9910\u5385\u7f16\u8f91\u65f6\u7684\u6807\u7b7e\u9009\u62e9\u4e0b\u62c9\u3002") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("\u521b\u5efa\u7ba1\u7406\u6807\u7b7e") ++ @ApiOperation(value = "\u521b\u5efa\u7ba1\u7406\u6807\u7b7e", notes = "\u521b\u5efa\u9884\u8bbe\u6807\u7b7e\uff0c\u6807\u7b7e\u540d\u4e0d\u53ef\u91cd\u590d\u3002\u53ef\u6307\u5b9a\u989c\u8272(tagColor)\uff0c\u9ed8\u8ba4#409EFF\u3002") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class RestaurantTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("\u89e3\u6790\u81ea\u5b9a\u4e49\u6807\u7b7e") ++ @ApiOperation(value = "\u89e3\u6790\u81ea\u5b9a\u4e49\u6807\u7b7e", notes = "\u6309\u540d\u79f0\u67e5\u627e\u6216\u81ea\u52a8\u521b\u5efa\u6807\u7b7e\u3002\u7528\u4e8e\u9910\u5385\u7f16\u8f91\u65f6\u5feb\u901f\u8f93\u5165\u65b0\u6807\u7b7e\u3002") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class RestaurantTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("\u7f16\u8f91\u6807\u7b7e") ++ @ApiOperation(value = "\u7f16\u8f91\u6807\u7b7e", notes = "\u4fee\u6539\u6807\u7b7e\u540d\u79f0\u6216\u989c\u8272\uff0c\u6240\u6709\u5173\u8054\u9910\u5385\u81ea\u52a8\u751f\u6548\u3002") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class RestaurantTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("\u5220\u9664\u6807\u7b7e") ++ @ApiOperation(value = "\u5220\u9664\u6807\u7b7e", notes = "\u5220\u9664\u6807\u7b7e\u5e76\u89e3\u9664\u6240\u6709\u9910\u5385\u4e0e\u8be5\u6807\u7b7e\u7684\u5173\u8054\u3002") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("\u66f4\u65b0\u9910\u5385\u6807\u7b7e") ++ @ApiOperation(value = "\u66f4\u65b0\u9910\u5385\u6807\u7b7e", notes = "\u5168\u91cf\u66ff\u6362\u6307\u5b9a\u9910\u5385\u7684\u6807\u7b7e\u5217\u8868\u3002\u4f20\u5165tagIds\u4e3a\u6700\u7ec8\u5173\u8054\u7684\u6807\u7b7eID\u5217\u8868\uff0c\u4e3a\u7a7a\u5219\u6e05\u9664\u6240\u6709\u6807\u7b7e\u3002") + @PutMapping("/item/{restaurantId}/tags") + public Result updateRestaurantTags( + @ApiParam("餐厅ID") @PathVariable Long restaurantId, +@@ -87,7 +87,7 @@ public class RestaurantTagController { + return Result.success(); + } + +- @ApiOperation("\u6279\u91cf\u6253\u6807\u7b7e") ++ @ApiOperation(value = "\u6279\u91cf\u6253\u6807\u7b7e", notes = "\u5bf9\u591a\u4e2a\u9910\u5385\u6279\u91cf\u6dfb\u52a0/\u79fb\u9664\u6807\u7b7e\u3002\u589e\u91cf\u64cd\u4f5c\uff0c\u4e0d\u5f71\u54cd\u672a\u6307\u5b9a\u7684\u6807\u7b7e\u3002") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java +index 629213d..23de858 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantCreateRequest.java +@@ -61,8 +61,8 @@ public class RestaurantCreateRequest { + @Size(max = 30) + private String district; + +- @ApiModelProperty(value = "城市标签", required = true, example = "拉萨") +- @NotBlank(message = "城市标签不能为空") ++ @ApiModelProperty(value = "城市名称(纯文本输入)", required = true, example = "拉萨") ++ @NotBlank(message = "城市名称不能为空") + @Size(max = 30) + private String cityName; + +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java +index 34e331b..ba2f6e9 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantQueryRequest.java +@@ -25,7 +25,7 @@ public class RestaurantQueryRequest { + @ApiModelProperty(value = "省份", example = "西藏自治区") + private String province; + +- @ApiModelProperty(value = "城市标签", example = "拉萨") ++ @ApiModelProperty(value = "城市名称筛选(纯文本)", example = "拉萨") + private String cityName; + + @ApiModelProperty(value = "城市", example = "拉萨市") +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java +index 8b62d81..51eb13c 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/dto/RestaurantUpdateRequest.java +@@ -57,7 +57,7 @@ public class RestaurantUpdateRequest { + @Size(max = 30) + private String district; + +- @ApiModelProperty(value = "城市标签", example = "拉萨") ++ @ApiModelProperty(value = "城市名称(纯文本输入)", example = "拉萨") + @Size(max = 30) + private String cityName; + +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java +index df37c80..f0d4d24 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantListVO.java +@@ -36,7 +36,7 @@ public class RestaurantListVO { + @ApiModelProperty("人均消费(元)") + private BigDecimal pricePerPerson; + +- @ApiModelProperty("城市标签") ++ @ApiModelProperty("城市名称(纯文本)") + private String cityName; + + @ApiModelProperty("亮点摘要") +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java +index acfd3d8..4396d6e 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/restaurant/vo/RestaurantVO.java +@@ -54,7 +54,7 @@ public class RestaurantVO { + @ApiModelProperty("区县") + private String district; + +- @ApiModelProperty("城市标签") ++ @ApiModelProperty("城市名称(纯文本)") + private String cityName; + + @ApiModelProperty("详细地址") +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java +index dbe9f19..a28ef38 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalMpScenicController.java +@@ -17,7 +17,7 @@ import java.util.List; + /** + * C端景区内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + */ +-@Api(tags = "【内部接口】小程序景区(Feign调用)") ++@Api(tags = "【内部接口】小程序景区(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/scenic") + @RequiredArgsConstructor +@@ -25,21 +25,21 @@ public class InternalMpScenicController { + + private final ScenicSpotService scenicSpotService; + +- @ApiOperation("C端景区列表") ++ @ApiOperation(value = "C端景区列表", notes = "【仅限内部Feign调用】供mp-service BFF聚合使用。强制status=1只返回已上架景区,支持分页、城市筛选和关键词搜索。C端用户通过小程序间接访问。\n\ncityName为纯文本筛选字段,非字典。") + @GetMapping("/list") + public Result> listScenic(ScenicSpotQueryRequest query) { + query.setStatus(1); + return Result.success(scenicSpotService.listSpots(query)); + } + +- @ApiOperation("C端景区详情") ++ @ApiOperation(value = "C端景区详情", notes = "【仅限内部Feign调用】供mp-service获取景区完整详情,包含封面、轮播图、标签、季节内容、富文本介绍、坐标等。注意:不限制status,由BFF层校验是否展示。") + @GetMapping("/{scenicId}") + public Result getScenicDetail(@PathVariable Long scenicId) { + ScenicSpotVO vo = scenicSpotService.getSpot(scenicId); + return Result.success(vo); + } + +- @ApiOperation("C端附近景区") ++ @ApiOperation(value = "C端附近景区", notes = "【仅限内部Feign调用】根据指定景区的坐标查询附近的景区列表。radius为搜索半径(km,默认50),limit为最大返回数(默认10)。按距离排序,返回名称、封面、距离等信息。") + @GetMapping("/{scenicId}/nearby") + public Result> getNearbyScenic( + @PathVariable Long scenicId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java +index a902ee1..9f47695 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/InternalScenicController.java +@@ -22,7 +22,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】景区(Feign调用)") ++@Api(tags = "【内部接口】景区(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/scenic") + @RequiredArgsConstructor +@@ -31,7 +31,7 @@ public class InternalScenicController { + private final ScenicSpotService spotService; + private final ScenicPriceCalendarService priceService; + +- @ApiOperation("获取景区简要信息") ++ @ApiOperation(value = "获取景区简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个景区的简要信息,返回ID、名称、荣誉称号、城市、状态。不存在时返回错误。\n\n**关联字典**:\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/spot/{scenicId}") + public Result> getSpotBrief(@PathVariable Long scenicId) { + ScenicSpot spot = spotService.getSpotEntity(scenicId); +@@ -47,7 +47,7 @@ public class InternalScenicController { + return Result.success(brief); + } + +- @ApiOperation("批量获取景区简要信息") ++ @ApiOperation(value = "批量获取景区简要信息", notes = "【仅限内部Feign调用】批量获取景区简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询行程节点绑定的景区资源。\n\n**关联字典**:\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/spots/batch") + public Result>> getSpotsBatch(@RequestParam @Size(max = 500) List scenicIds) { + List> results = scenicIds.stream() +@@ -67,7 +67,7 @@ public class InternalScenicController { + return Result.success(results); + } + +- @ApiOperation("查询某日价格") ++ @ApiOperation(value = "查询某日价格", notes = "【仅限内部Feign调用】查询景区指定日期的价格日历信息,包含成本价、售价、库存、状态。date格式为yyyy-MM-dd。供产品服务报价计算和库存校验使用。") + @GetMapping("/spot/{scenicId}/price/{date}") + public Result getPriceForDate( + @PathVariable Long scenicId, +@@ -76,7 +76,7 @@ public class InternalScenicController { + return Result.success(price); + } + +- @ApiOperation("判断某日是否可售") ++ @ApiOperation(value = "判断某日是否可售", notes = "【仅限内部Feign调用】判断景区指定日期是否可售(价格日历存在且状态为启用且库存>0)。供订单服务下单前校验使用。") + @GetMapping("/spot/{scenicId}/available/{date}") + public Result isAvailable( + @PathVariable Long scenicId, +@@ -84,7 +84,7 @@ public class InternalScenicController { + return Result.success(priceService.isAvailable(scenicId, LocalDate.parse(date))); + } + +- @ApiOperation("扣减库存") ++ @ApiOperation(value = "扣减库存", notes = "【仅限内部Feign调用】扣减景区指定日期的库存数量。下单成功时由订单服务调用。库存不足时返回false。使用乐观锁防止超卖。") + @PutMapping("/spot/{scenicId}/stock/deduct") + public Result deductStock( + @PathVariable Long scenicId, +@@ -94,7 +94,7 @@ public class InternalScenicController { + return Result.success(success); + } + +- @ApiOperation("恢复库存") ++ @ApiOperation(value = "恢复库存", notes = "【仅限内部Feign调用】恢复景区指定日期的库存数量。订单取消或退款时由订单服务调用,将之前扣减的库存加回。") + @PutMapping("/spot/{scenicId}/stock/restore") + public Result restoreStock( + @PathVariable Long scenicId, +@@ -104,9 +104,9 @@ public class InternalScenicController { + return Result.success(); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配景区并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + spotService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java +index 8e2b1cb..62d7de0 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicPriceCalendarController.java +@@ -25,7 +25,7 @@ public class ScenicPriceCalendarController { + + private final ScenicPriceCalendarService priceService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询景区的每日价格和可售状态。返回指定年月中所有已设置价格的日期,未设置的日期不返回。用于前端日历组件渲染。") + @GetMapping("/spot/{scenicId}/prices") + public Result getPriceCalendar( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -34,7 +34,7 @@ public class ScenicPriceCalendarController { + return Result.success(priceService.getPriceCalendar(scenicId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置成本价、库存和可售状态。支持weekdayOnly/weekendOnly/selectedWeekdays过滤特定星期,支持excludeDates排除特定日期。已有价格的日期会被覆盖更新。") + @PutMapping("/spot/{scenicId}/prices") + public Result batchSetPrices( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -43,7 +43,7 @@ public class ScenicPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改可售状态") ++ @ApiOperation(value = "批量修改可售状态", notes = "批量修改指定日期范围内的可售状态,不影响价格和库存。status=0不可售,status=1可售。用于临时关闭/开放某些日期的售卖。") + @PutMapping("/spot/{scenicId}/prices/status") + public Result batchUpdateStatus( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -52,7 +52,7 @@ public class ScenicPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量清除价格") ++ @ApiOperation(value = "批量清除价格", notes = "删除指定日期范围内的所有价格记录。删除后该日期范围将显示为未设置状态。日期格式:yyyy-MM-dd。") + @DeleteMapping("/spot/{scenicId}/prices") + public Result deletePrices( + @ApiParam("景区ID") @PathVariable Long scenicId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java +index 8933ec2..ab7ad78 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSeasonController.java +@@ -22,13 +22,13 @@ public class ScenicSeasonController { + + private final ScenicSeasonService seasonService; + +- @ApiOperation("获取景区全部季节内容") ++ @ApiOperation(value = "获取景区全部季节内容", notes = "返回景区的所有季节内容列表(春/夏/秋/冬)。季节内容是景区独有功能,其他资源类型没有此概念。每个季节可设置独立的封面、轮播图、亮点描述和游玩攻略。") + @GetMapping("/spot/{scenicId}/seasons") + public Result> getSeasons(@ApiParam("景区ID") @PathVariable Long scenicId) { + return Result.success(seasonService.getSeasons(scenicId)); + } + +- @ApiOperation("保存/更新季节内容") ++ @ApiOperation(value = "保存/更新季节内容", notes = "创建或更新指定景区的季节内容。seasonType为季节标识(如spring/summer/autumn/winter)。如果该季节已存在则更新,不存在则创建。支持设置季节别名(如「樱花季」)、月份范围、独立封面和轮播图。") + @PutMapping("/spot/{scenicId}/season/{seasonType}") + public Result saveSeason( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -39,7 +39,7 @@ public class ScenicSeasonController { + return Result.success(seasonService.saveSeason(scenicId, seasonType, request, adminId)); + } + +- @ApiOperation("删除季节内容") ++ @ApiOperation(value = "删除季节内容", notes = "删除指定景区的某个季节内容,同时清理关联的素材引用。") + @DeleteMapping("/spot/{scenicId}/season/{seasonType}") + public Result deleteSeason( + @ApiParam("景区ID") @PathVariable Long scenicId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java +index b8aff01..c2da355 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicSpotController.java +@@ -26,7 +26,7 @@ public class ScenicSpotController { + + private final ScenicSpotService spotService; + +- @ApiOperation("创建景区") ++ @ApiOperation(value = "创建景区", notes = "新建一个景区资源,初始状态为草稿(status=0)。创建后需通过「提交启用审批」接口走企微OA审批流程才能上架。支持富文本字段(featureIntro/detailContent等),素材ID从素材库获取。\n\n**关联字典**:\n- scenic_facility:景区设施(表单多选)\n- scenic_honor:景区荣誉(表单多选)") + @PostMapping("/spot") + public Result createSpot( + @ApiParam("景区创建请求") @Valid @RequestBody ScenicSpotCreateRequest request, +@@ -35,19 +35,19 @@ public class ScenicSpotController { + return Result.success(spotService.createSpot(request, adminId)); + } + +- @ApiOperation("景区列表") ++ @ApiOperation(value = "景区列表", notes = "分页查询景区列表,支持按名称关键词、状态(0草稿/1上架/2下架)、城市等条件筛选。返回列表摘要信息(不含富文本详情),按sortOrder倒序+创建时间倒序排列。\n\n**关联字典**:\n- scenic_facility:景区设施(列表显示)\n- scenic_honor:景区荣誉(列表显示)") + @GetMapping("/spots") + public Result> listSpots(@ApiParam("景区查询请求") @Valid ScenicSpotQueryRequest query) { + return Result.success(spotService.listSpots(query)); + } + +- @ApiOperation("景区详情") ++ @ApiOperation(value = "景区详情", notes = "获取景区完整信息,包含富文本内容、素材URL、标签列表、季节内容等。素材ID会自动解析为OSS访问地址。\n\n**关联字典**:\n- scenic_facility:景区设施(详情显示)\n- scenic_honor:景区荣誉(详情显示)") + @GetMapping("/spot/{scenicId}") + public Result getSpot(@ApiParam("景区ID") @PathVariable Long scenicId) { + return Result.success(spotService.getSpot(scenicId)); + } + +- @ApiOperation("更新景区") ++ @ApiOperation(value = "更新景区", notes = "更新景区基本信息和富文本内容。更新不会改变当前状态。如果景区已上架,修改后仍保持上架状态,无需重新审批。\n\n**关联字典**:\n- scenic_facility:景区设施(表单多选)\n- scenic_honor:景区荣誉(表单多选)") + @PutMapping("/spot/{scenicId}") + public Result updateSpot( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -57,7 +57,7 @@ public class ScenicSpotController { + return Result.success(spotService.updateSpot(scenicId, request, adminId)); + } + +- @ApiOperation("删除景区") ++ @ApiOperation(value = "删除景区", notes = "软删除景区(设置deleted_at)。仅SUPER_ADMIN角色或创建者本人可删除。已上架的景区需先下架再删除。删除后会同时清理关联的素材引用。") + @DeleteMapping("/spot/{scenicId}") + public Result deleteSpot( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -68,7 +68,7 @@ public class ScenicSpotController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批申请。targetStatus=1表示申请上架,targetStatus=2表示申请下架。提交后景区进入PENDING_APPROVAL状态,企微审批通过/拒绝后通过回调自动更新状态。返回企微审批单号spNo。同一景区不可重复提交未完成的审批。") + @PostMapping("/spot/{scenicId}/submit-approval") + public Result> submitApproval( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -80,7 +80,7 @@ public class ScenicSpotController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("上下架切换") ++ @ApiOperation(value = "上下架切换", notes = "直接修改景区状态(跳过审批流程),仅限SUPER_ADMIN使用。普通管理员应使用「提交启用/禁用审批」接口。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/spot/{scenicId}/status") + public Result updateStatus( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -91,7 +91,7 @@ public class ScenicSpotController { + return Result.success(); + } + +- @ApiOperation("批量上下架") ++ @ApiOperation(value = "批量上下架", notes = "批量修改多个景区的状态。scenicIds为景区ID列表(字符串格式),status为目标状态。跳过审批流程,适用于批量管理场景。") + @PutMapping("/spots/batch/status") + public Result batchUpdateStatus( + @ApiParam("景区状态请求") @Valid @RequestBody ScenicStatusRequest request, +@@ -103,7 +103,7 @@ public class ScenicSpotController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个景区。权限校验同单个删除:仅SUPER_ADMIN或创建者可操作。部分失败不影响其他景区的删除。") + @DeleteMapping("/spots/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java +index eda0e91..1410edc 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/scenic/controller/ScenicTagController.java +@@ -27,7 +27,7 @@ public class ScenicTagController { + + private final ScenicTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询景区标签库中的所有标签,支持按关键词搜索。标签分为预设标签(管理员创建)和自定义标签(adhoc接口创建),此接口返回全部类型。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class ScenicTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于景区编辑时的标签选择下拉列表。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。可指定颜色(tagColor),默认为#409EFF。预设标签在标签管理页面展示和维护。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class ScenicTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "输入标签名称,如果已存在则直接返回,不存在则自动创建。用于景区编辑时快速输入新标签,避免先到标签管理页面创建。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class ScenicTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色。修改后所有关联此标签的景区会自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class ScenicTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并自动解除所有景区与该标签的关联关系。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新景区标签") ++ @ApiOperation(value = "更新景区标签", notes = "全量替换指定景区的标签列表。传入tagIds为该景区最终要关联的标签ID列表,为空则清除所有标签。") + @PutMapping("/spot/{scenicId}/tags") + public Result updateScenicTags( + @ApiParam("景区ID") @PathVariable Long scenicId, +@@ -87,7 +87,7 @@ public class ScenicTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个景区批量添加或移除标签。addTagIds为要添加的标签,removeTagIds为要移除的标签,两者可同时使用。增量操作,不影响未指定的标签。") + @PutMapping("/spots/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java +index 95c02bf..4125c0d 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/InternalServiceController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】增值服务(Feign调用)") ++@Api(tags = "【内部接口】增值服务(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/service") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalServiceController { + + private final ServiceItemService serviceItemService; + +- @ApiOperation("获取服务简要信息") ++ @ApiOperation(value = "获取服务简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个增值服务的简要信息,返回ID、名称、分类编码、计费类型、是否收费、状态。不存在时返回错误。\n\n**关联字典**:\n- service_unit(计费单位,返回字段billingType):PER_PERSON=元/人, PER_TIME=元/次, PER_DAY=元/天, PER_VEHICLE=元/台, FIXED=固定金额\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{serviceId}") + public Result> getServiceBrief(@PathVariable Long serviceId) { + ServiceItem item = serviceItemService.getServiceItemEntity(serviceId); +@@ -42,7 +42,7 @@ public class InternalServiceController { + return Result.success(brief); + } + +- @ApiOperation("批量获取服务简要信息") ++ @ApiOperation(value = "批量获取服务简要信息", notes = "【仅限内部Feign调用】批量获取增值服务简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询产品关联的服务项。\n\n**关联字典**:\n- service_unit(计费单位,返回字段billingType):PER_PERSON=元/人, PER_TIME=元/次, PER_DAY=元/天, PER_VEHICLE=元/台, FIXED=固定金额\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getServiceBatch(@RequestParam @Size(max = 500) List serviceIds) { + List> results = serviceIds.stream() +@@ -63,9 +63,9 @@ public class InternalServiceController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配增值服务并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + serviceItemService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java +index 6750979..52e1bb9 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceItemController.java +@@ -26,7 +26,7 @@ public class ServiceItemController { + + private final ServiceItemService serviceItemService; + +- @ApiOperation("创建服务") ++ @ApiOperation(value = "创建增值服务", notes = "新建增值服务项目(如保险、签证代办、接送机等),初始状态为草稿(status=0)。支持免费(isPaid=false)和付费两种模式,付费服务有独立的价格日历。需走企微审批上架。\n\n**关联字典**:\n- service_category:服务分类(表单选择)\n- billing_type_service:服务计费方式(表单选择)\n- service_unit:服务计量单位(表单选择)") + @PostMapping("/item") + public Result createServiceItem( + @ApiParam("服务创建请求") @Valid @RequestBody ServiceCreateRequest request, +@@ -35,19 +35,19 @@ public class ServiceItemController { + return Result.success(serviceItemService.createServiceItem(request, adminId)); + } + +- @ApiOperation("服务列表") ++ @ApiOperation(value = "增值服务列表", notes = "分页查询增值服务列表,支持按名称、状态、分类等条件筛选。\n\n**关联字典**:\n- service_category:服务分类(筛选+列表显示)\n- billing_type_service:服务计费方式(列表显示)\n- service_unit:服务计量单位(列表显示)") + @GetMapping("/items") + public Result> listServiceItems(@ApiParam("服务查询请求") @Valid ServiceQueryRequest query) { + return Result.success(serviceItemService.listServiceItems(query)); + } + +- @ApiOperation("服务详情") ++ @ApiOperation(value = "增值服务详情", notes = "获取增值服务完整信息,包含素材URL、标签、计费方式等。\n\n**关联字典**:\n- service_category:服务分类(详情显示)\n- billing_type_service:服务计费方式(详情显示)\n- service_unit:服务计量单位(详情显示)") + @GetMapping("/item/{serviceId}") + public Result getServiceItem(@ApiParam("服务ID") @PathVariable Long serviceId) { + return Result.success(serviceItemService.getServiceItem(serviceId)); + } + +- @ApiOperation("更新服务") ++ @ApiOperation(value = "更新增值服务", notes = "更新增值服务基本信息,不改变当前状态。\n\n**关联字典**:\n- service_category:服务分类(表单选择)\n- billing_type_service:服务计费方式(表单选择)\n- service_unit:服务计量单位(表单选择)") + @PutMapping("/item/{serviceId}") + public Result updateServiceItem( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -57,7 +57,7 @@ public class ServiceItemController { + return Result.success(serviceItemService.updateServiceItem(serviceId, request, adminId)); + } + +- @ApiOperation("删除服务") ++ @ApiOperation(value = "删除增值服务", notes = "软删除增值服务。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/item/{serviceId}") + public Result deleteServiceItem( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -68,7 +68,7 @@ public class ServiceItemController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{serviceId}/submit-approval") + public Result> submitApproval( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -80,7 +80,7 @@ public class ServiceItemController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("启用/禁用切换") ++ @ApiOperation(value = "启用/禁用切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{serviceId}/status") + public Result updateStatus( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -91,7 +91,7 @@ public class ServiceItemController { + return Result.success(); + } + +- @ApiOperation("批量启用/禁用") ++ @ApiOperation(value = "批量启用/禁用", notes = "批量修改多个增值服务的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("服务状态请求") @Valid @RequestBody ServiceStatusRequest request, +@@ -103,7 +103,7 @@ public class ServiceItemController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个增值服务。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java +index e96654d..a2f52d3 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServicePriceCalendarController.java +@@ -25,7 +25,7 @@ public class ServicePriceCalendarController { + + private final ServicePriceCalendarService priceService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询增值服务的每日价格和可售状态。仅付费服务(isPaid=true)需要设置价格日历。") + @GetMapping("/item/{serviceId}/prices") + public Result getPriceCalendar( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -34,7 +34,7 @@ public class ServicePriceCalendarController { + return Result.success(priceService.getPriceCalendar(serviceId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置服务的成本价和可售状态。") + @PutMapping("/item/{serviceId}/prices") + public Result batchSetPrices( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -43,7 +43,7 @@ public class ServicePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改可售状态") ++ @ApiOperation(value = "批量修改可售状态", notes = "批量修改日期范围内的可售状态,不影响价格。") + @PutMapping("/item/{serviceId}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -52,7 +52,7 @@ public class ServicePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量清除价格") ++ @ApiOperation(value = "批量清除价格", notes = "删除指定日期范围内的价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/item/{serviceId}/prices") + public Result deletePrices( + @ApiParam("服务ID") @PathVariable Long serviceId, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java +index cf3865a..5dca328 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/service/controller/ServiceTagController.java +@@ -27,7 +27,7 @@ public class ServiceTagController { + + private final ServiceTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询增值服务标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class ServiceTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于服务编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class ServiceTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class ServiceTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色,所有关联服务自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class ServiceTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有服务与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新服务标签") ++ @ApiOperation(value = "更新服务标签", notes = "全量替换指定服务的标签列表。") + @PutMapping("/item/{serviceId}/tags") + public Result updateServiceTags( + @ApiParam("服务ID") @PathVariable Long serviceId, +@@ -87,7 +87,7 @@ public class ServiceTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个服务批量添加/移除标签。增量操作。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java +index 7c8bb51..ce700da 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/InternalStaffController.java +@@ -19,7 +19,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】服务人员(Feign调用)") ++@Api(tags = "【内部接口】服务人员(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/staff") + @RequiredArgsConstructor +@@ -28,7 +28,7 @@ public class InternalStaffController { + private final StaffService staffService; + private final StaffMapper staffMapper; + +- @ApiOperation("获取人员简要信息") ++ @ApiOperation(value = "获取人员简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个服务人员的简要信息,返回ID、姓名、人员类型、手机号、状态。不存在时返回错误。\n\n**关联字典**:\n- staff_type(人员类型,返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/{staffId}") + public Result> getStaffBrief(@PathVariable Long staffId) { + Staff staff = staffService.getStaffEntity(staffId); +@@ -44,7 +44,7 @@ public class InternalStaffController { + return Result.success(brief); + } + +- @ApiOperation("批量获取人员简要信息") ++ @ApiOperation(value = "批量获取人员简要信息", notes = "【仅限内部Feign调用】批量获取服务人员简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询团批关联的服务人员。\n\n**关联字典**:\n- staff_type(人员类型,返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/batch") + public Result>> getStaffBatch(@RequestParam @Size(max = 500) List staffIds) { + List> results = staffIds.stream() +@@ -64,7 +64,7 @@ public class InternalStaffController { + return Result.success(results); + } + +- @ApiOperation("按人员类型查询") ++ @ApiOperation(value = "按人员类型查询", notes = "【仅限内部Feign调用】按staffType查询第一个匹配的服务人员。staffType如:GUIDE(导游)、DRIVER(司机)、PHOTOGRAPHER(摄影师)等。未找到时返回null。\n\n**关联字典**:\n- staff_type(人员类型,请求参数+返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/by-type/{staffType}") + public Result> getStaffByType(@PathVariable String staffType) { + Staff staff = staffService.getStaffByType(staffType); +@@ -80,9 +80,9 @@ public class InternalStaffController { + return Result.success(brief); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配服务人员并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + staffService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +@@ -91,7 +91,7 @@ public class InternalStaffController { + /** + * Batch get staff basic info by comma-separated IDs (for product-service batch staff snapshot). + */ +- @ApiOperation("批量获取人员基本信息(逗号分隔ID)") ++ @ApiOperation(value = "批量获取人员基本信息(逗号分隔ID)", notes = "【仅限内部Feign调用】通过逗号分隔的ID字符串批量获取人员基本信息(含staffId、name、phone、staffType、coverMaterialId)。供产品服务团批人员快照使用。与/batch接口不同,此接口接收逗号分隔字符串而非数组。\n\n**关联字典**:\n- staff_type(人员类型,返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师") + @GetMapping("/batch-basic") + public Result>> batchGetStaffBasic(@RequestParam String staffIds) { + List ids = Arrays.stream(staffIds.split(",")) +@@ -122,7 +122,7 @@ public class InternalStaffController { + * List available staff (status=1), optionally filter by staffType. + * Used by admin batch staff selection dropdown. + */ +- @ApiOperation("列出可用人员(用于下拉选择)") ++ @ApiOperation(value = "列出可用人员(用于下拉选择)", notes = "【仅限内部Feign调用】列出所有status=1的可用服务人员,可按staffType筛选。按sortOrder和staffId排序。供管理后台团批分配人员的下拉选择框使用。\n\n**关联字典**:\n- staff_type(人员类型,请求参数+返回字段staffType):GUIDE=导游, DRIVER=司机, PHOTOGRAPHER=摄影师, CHEF=厨师") + @GetMapping("/list-available") + public Result>> listAvailableStaff( + @RequestParam(required = false) String staffType) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java +index f90638f..be01710 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffController.java +@@ -24,7 +24,7 @@ public class StaffController { + + private final StaffService staffService; + +- @ApiOperation("创建服务人员") ++ @ApiOperation(value = "创建服务人员", notes = "新建服务人员(导游/领队/摄影师/助理等)。人员类型(staffType)决定了其在价格日历中的归类。需走企微审批上架后才能被产品引用。\n\n**关联字典**:\n- staff_type:人员类型(表单选择)\n- guide_level:导游等级(表单选择)\n- driver_license_type:驾照类型(表单选择)\n- language:语言能力(表单多选)\n- guide_specialty:导游专长(表单多选)\n- guide_service_area:服务区域(表单多选)") + @PostMapping + public Result createStaff(@ApiParam("服务人员创建请求") @Valid @RequestBody StaffCreateRequest request, + HttpServletRequest httpRequest) { +@@ -32,19 +32,19 @@ public class StaffController { + return Result.success(staffService.createStaff(request, adminId)); + } + +- @ApiOperation("服务人员列表") ++ @ApiOperation(value = "服务人员列表", notes = "分页查询服务人员列表,支持按姓名、状态、人员类型等条件筛选。\n\n**关联字典**:\n- staff_type:人员类型(筛选+列表显示)\n- guide_level:导游等级(列表显示)\n- driver_license_type:驾照类型(列表显示)\n- language:语言能力(列表显示)\n- guide_specialty:导游专长(列表显示)\n- guide_service_area:服务区域(列表显示)") + @GetMapping("/list") + public Result> listStaff(@ApiParam("服务人员查询请求") @Valid StaffQueryRequest query) { + return Result.success(staffService.listStaff(query)); + } + +- @ApiOperation("服务人员详情") ++ @ApiOperation(value = "服务人员详情", notes = "获取服务人员完整信息,包含素材URL、标签、技能描述等。\n\n**关联字典**:\n- staff_type:人员类型(详情显示)\n- guide_level:导游等级(详情显示)\n- driver_license_type:驾照类型(详情显示)\n- language:语言能力(详情显示)\n- guide_specialty:导游专长(详情显示)\n- guide_service_area:服务区域(详情显示)") + @GetMapping("/{staffId}") + public Result getStaff(@ApiParam("人员ID") @PathVariable Long staffId) { + return Result.success(staffService.getStaff(staffId)); + } + +- @ApiOperation("更新服务人员") ++ @ApiOperation(value = "更新服务人员", notes = "更新服务人员基本信息,不改变当前状态。\n\n**关联字典**:\n- staff_type:人员类型(表单选择)\n- guide_level:导游等级(表单选择)\n- driver_license_type:驾照类型(表单选择)\n- language:语言能力(表单多选)\n- guide_specialty:导游专长(表单多选)\n- guide_service_area:服务区域(表单多选)") + @PutMapping("/{staffId}") + public Result updateStaff(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("服务人员更新请求") @Valid @RequestBody StaffUpdateRequest request, +@@ -53,7 +53,7 @@ public class StaffController { + return Result.success(staffService.updateStaff(staffId, request, adminId)); + } + +- @ApiOperation("删除服务人员") ++ @ApiOperation(value = "删除服务人员", notes = "软删除服务人员。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/{staffId}") + public Result deleteStaff(@ApiParam("人员ID") @PathVariable Long staffId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -62,7 +62,7 @@ public class StaffController { + return Result.success(); + } + +- @ApiOperation("提交审批") ++ @ApiOperation(value = "提交审批", notes = "向企微OA提交人员启用/禁用审批。targetStatus=1申请启用,targetStatus=2申请禁用。返回审批单号spNo。") + @PostMapping("/{staffId}/submit-approval") + public Result> submitApproval(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("审批提交请求体") @Valid @RequestBody ApprovalSubmitRequest request, +@@ -72,7 +72,7 @@ public class StaffController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("更新状态") ++ @ApiOperation(value = "更新状态", notes = "直接修改人员状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=启用,2=禁用。") + @PutMapping("/{staffId}/status") + public Result updateStatus(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("状态请求体") @Valid @RequestBody StaffStatusRequest request, +@@ -82,14 +82,14 @@ public class StaffController { + return Result.success(); + } + +- @ApiOperation("批量更新状态") ++ @ApiOperation(value = "批量更新状态", notes = "批量修改多个服务人员的状态,跳过审批流程。") + @PutMapping("/batch/status") + public Result batchUpdateStatus(@ApiParam("批量状态请求体") @Valid @RequestBody StaffStatusRequest request) { + staffService.batchUpdateStatus(request.getStaffIds(), request.getStatus()); + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个服务人员。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/batch") + public Result batchDelete(@ApiParam("批量删除请求体") @Valid @RequestBody StaffBatchDeleteRequest request, + HttpServletRequest httpRequest) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java +index 2993bef..a762de1 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffPriceCalendarController.java +@@ -27,7 +27,7 @@ public class StaffPriceCalendarController { + + private final StaffPriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历(按人员类型)") ++ @ApiOperation(value = "查询价格日历(按人员类型)", notes = "按月查询指定人员类型的每日服务费用和可调度状态。注意:价格日历按人员类型维度管理,非按个人维度。同一类型的所有人员共享同一套价格。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @GetMapping("/type/{staffType}/prices") + public Result getPriceCalendar( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +@@ -36,7 +36,7 @@ public class StaffPriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(staffType, year, month)); + } + +- @ApiOperation("批量设置价格(按人员类型)") ++ @ApiOperation(value = "批量设置价格(按人员类型)", notes = "在指定日期范围内批量设置该类型人员的服务成本价和可调度状态。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @PutMapping("/type/{staffType}/prices") + public Result batchSetPrices( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +@@ -45,7 +45,7 @@ public class StaffPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改调度状态(按人员类型)") ++ @ApiOperation(value = "批量修改调度状态(按人员类型)", notes = "批量修改日期范围内的可调度状态,不影响价格。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @PutMapping("/type/{staffType}/prices/batch-status") + public Result batchUpdateStatus( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +@@ -54,7 +54,7 @@ public class StaffPriceCalendarController { + return Result.success(); + } + +- @ApiOperation("清除价格日历(按人员类型)") ++ @ApiOperation(value = "清除价格日历(按人员类型)", notes = "删除指定日期范围内该类型人员的价格记录。日期格式:yyyy-MM-dd。\n\n**关联字典**:\n- staff_type(人员类型)→ staffType路径参数") + @DeleteMapping("/type/{staffType}/prices") + public Result deletePrices( + @ApiParam("人员类型: GUIDE/GUIDE_ASSISTANT/PHOTOGRAPHER/LEADER/OTHER") @PathVariable String staffType, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java +index beceb5f..ff68d2c 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/staff/controller/StaffTagController.java +@@ -26,7 +26,7 @@ public class StaffTagController { + + private final StaffTagService tagService; + +- @ApiOperation("预设标签列表(分页)") ++ @ApiOperation(value = "预设标签列表(分页)", notes = "分页查询服务人员标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,13 +35,13 @@ public class StaffTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("全部标签列表") ++ @ApiOperation(value = "全部标签列表", notes = "不分页返回所有标签,用于人员编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag(@ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -49,7 +49,7 @@ public class StaffTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag(@ApiParam("标签名称请求体") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -57,21 +57,21 @@ public class StaffTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", notes = "修改标签名称或颜色。") + @PutMapping("/tag/{tagId}") + public Result updateTag(@ApiParam("标签ID") @PathVariable Long tagId, + @ApiParam("标签更新请求") @Valid @RequestBody TagUpdateRequest request) { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有人员与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("设置人员标签") ++ @ApiOperation(value = "设置人员标签", notes = "全量替换指定人员的标签列表。") + @PutMapping("/{staffId}/tags") + public Result updateStaffTags(@ApiParam("人员ID") @PathVariable Long staffId, + @ApiParam("标签ID列表请求") @Valid @RequestBody StaffTagUpdateRequest request) { +@@ -79,7 +79,7 @@ public class StaffTagController { + return Result.success(); + } + +- @ApiOperation("批量添加/移除标签") ++ @ApiOperation(value = "批量添加/移除标签", notes = "对多个人员批量添加/移除标签。增量操作。") + @PutMapping("/batch/tags") + public Result batchUpdateTags(@ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { + tagService.batchUpdateTags(request.getStaffIds(), request.getAddTagIds(), request.getRemoveTagIds()); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java +index 5467d19..e827b51 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/InternalSuppliesController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】备品(Feign调用)") ++@Api(tags = "【内部接口】备品(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/supplies") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalSuppliesController { + + private final SuppliesService suppliesService; + +- @ApiOperation("获取备品简要信息") ++ @ApiOperation(value = "获取备品简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个备品的简要信息,返回ID、名称、分类编码、计费类型、状态。不存在时返回错误。\n\n**关联字典**:\n- supplies_category(备品分类,返回字段categoryCode):CAMPING=露营, CLOTHING=服装, EQUIPMENT=装备, SAFETY=安全\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/item/{suppliesId}") + public Result> getSuppliesBrief(@PathVariable Long suppliesId) { + SuppliesItem item = suppliesService.getSuppliesEntity(suppliesId); +@@ -41,7 +41,7 @@ public class InternalSuppliesController { + return Result.success(brief); + } + +- @ApiOperation("批量获取备品简要信息") ++ @ApiOperation(value = "批量获取备品简要信息", notes = "【仅限内部Feign调用】批量获取备品简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询产品关联的备品资源。\n\n**关联字典**:\n- supplies_category(备品分类,返回字段categoryCode):CAMPING=露营, CLOTHING=服装, EQUIPMENT=装备, SAFETY=安全\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/items/batch") + public Result>> getSuppliesBatch(@RequestParam @Size(max = 500) List suppliesIds) { + List> results = suppliesIds.stream() +@@ -61,9 +61,9 @@ public class InternalSuppliesController { + return Result.success(results); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配备品并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + suppliesService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java +index 435f28b..964e6fc 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesController.java +@@ -26,7 +26,7 @@ public class SuppliesController { + + private final SuppliesService suppliesService; + +- @ApiOperation("创建备品") ++ @ApiOperation(value = "创建备品", notes = "新建备品资源(帐篷、睡袋、炊具等物资),初始状态为草稿(status=0)。需走企微审批上架。支持按件(PER_ITEM)和按人(PER_PERSON)计费。\n\n**关联字典**:\n- supplies_category:备品分类(表单选择)\n- billing_type:计费方式(表单选择)") + @PostMapping("/item") + public Result createSupplies( + @ApiParam("备品创建请求") @Valid @RequestBody SuppliesCreateRequest request, +@@ -35,19 +35,19 @@ public class SuppliesController { + return Result.success(suppliesService.createSupplies(request, adminId)); + } + +- @ApiOperation("备品列表") ++ @ApiOperation(value = "备品列表", notes = "分页查询备品列表,支持按名称、状态、分类等条件筛选。\n\n**关联字典**:\n- supplies_category:备品分类(筛选+列表显示)\n- billing_type:计费方式(列表显示)") + @GetMapping("/items") + public Result> listSupplies(@ApiParam("备品查询请求") @Valid SuppliesQueryRequest query) { + return Result.success(suppliesService.listSupplies(query)); + } + +- @ApiOperation("备品详情") ++ @ApiOperation(value = "备品详情", notes = "获取备品完整信息,包含素材URL、标签等。\n\n**关联字典**:\n- supplies_category:备品分类(详情显示)\n- billing_type:计费方式(详情显示)") + @GetMapping("/item/{suppliesId}") + public Result getSupplies(@ApiParam("备品ID") @PathVariable Long suppliesId) { + return Result.success(suppliesService.getSupplies(suppliesId)); + } + +- @ApiOperation("更新备品") ++ @ApiOperation(value = "更新备品", notes = "更新备品基本信息,不改变当前状态。\n\n**关联字典**:\n- supplies_category:备品分类(表单选择)\n- billing_type:计费方式(表单选择)") + @PutMapping("/item/{suppliesId}") + public Result updateSupplies( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -57,7 +57,7 @@ public class SuppliesController { + return Result.success(suppliesService.updateSupplies(suppliesId, request, adminId)); + } + +- @ApiOperation("删除备品") ++ @ApiOperation(value = "删除备品", notes = "软删除备品。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/item/{suppliesId}") + public Result deleteSupplies( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -68,7 +68,7 @@ public class SuppliesController { + return Result.success(); + } + +- @ApiOperation("提交启用/禁用审批") ++ @ApiOperation(value = "提交启用/禁用审批", notes = "向企微OA提交审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/item/{suppliesId}/submit-approval") + public Result> submitApproval( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -80,7 +80,7 @@ public class SuppliesController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("上下架切换") ++ @ApiOperation(value = "上下架切换", notes = "直接修改状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/item/{suppliesId}/status") + public Result updateStatus( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -91,7 +91,7 @@ public class SuppliesController { + return Result.success(); + } + +- @ApiOperation("批量上下架") ++ @ApiOperation(value = "批量上下架", notes = "批量修改多个备品的状态,跳过审批流程。") + @PutMapping("/items/batch/status") + public Result batchUpdateStatus( + @ApiParam("备品状态请求") @Valid @RequestBody SuppliesStatusRequest request, +@@ -103,7 +103,7 @@ public class SuppliesController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个备品。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/items/batch") + public Result batchDelete( + @ApiParam("批量删除请求") @Valid @RequestBody BatchDeleteRequest request, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java +index 7529058..8095ade 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/supplies/controller/SuppliesTagController.java +@@ -27,7 +27,7 @@ public class SuppliesTagController { + + private final SuppliesTagService tagService; + +- @ApiOperation("获取管理标签列表(分页)") ++ @ApiOperation(value = "获取管理标签列表(分页)", notes = "分页查询备品标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -36,13 +36,13 @@ public class SuppliesTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("获取全部标签") ++ @ApiOperation(value = "获取全部标签", notes = "不分页返回所有标签,用于备品编辑时的标签选择下拉。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建管理标签") ++ @ApiOperation(value = "创建管理标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -51,7 +51,7 @@ public class SuppliesTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag( + @ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, +@@ -60,7 +60,7 @@ public class SuppliesTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("编辑标签") ++ @ApiOperation(value = "编辑标签", notes = "修改标签名称或颜色,所有关联备品自动生效。") + @PutMapping("/tag/{tagId}") + public Result updateTag( + @ApiParam("标签ID") @PathVariable Long tagId, +@@ -68,14 +68,14 @@ public class SuppliesTagController { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有备品与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("更新备品标签") ++ @ApiOperation(value = "更新备品标签", notes = "全量替换指定备品的标签列表。") + @PutMapping("/item/{suppliesId}/tags") + public Result updateSuppliesTags( + @ApiParam("备品ID") @PathVariable Long suppliesId, +@@ -87,7 +87,7 @@ public class SuppliesTagController { + return Result.success(); + } + +- @ApiOperation("批量打标签") ++ @ApiOperation(value = "批量打标签", notes = "对多个备品批量添加/移除标签。增量操作。") + @PutMapping("/items/batch/tags") + public Result batchUpdateTags( + @ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java +index 4e672d1..a0dc396 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/InternalVehicleController.java +@@ -17,7 +17,7 @@ import java.util.stream.Collectors; + + @Slf4j + @Validated +-@Api(tags = "【内部接口】车型(Feign调用)") ++@Api(tags = "【内部接口】车型(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/vehicle") + @RequiredArgsConstructor +@@ -25,7 +25,7 @@ public class InternalVehicleController { + + private final VehicleModelService vehicleModelService; + +- @ApiOperation("获取车型简要信息") ++ @ApiOperation(value = "获取车型简要信息", notes = "【仅限内部Feign调用】供产品服务获取单个车型的简要信息,返回ID、名称、车辆类型、品牌、座位数、状态。不存在时返回错误。\n\n**关联字典**:\n- vehicle_type(车辆类型,返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/model/{vehicleId}") + public Result> getVehicleBrief(@PathVariable Long vehicleId) { + VehicleModel model = vehicleModelService.getVehicleEntity(vehicleId); +@@ -42,7 +42,7 @@ public class InternalVehicleController { + return Result.success(brief); + } + +- @ApiOperation("批量获取车型简要信息") ++ @ApiOperation(value = "批量获取车型简要信息", notes = "【仅限内部Feign调用】批量获取车型简要信息,最多500个ID。不存在的ID自动过滤。供产品服务批量查询行程关联的车辆资源。\n\n**关联字典**:\n- vehicle_type(车辆类型,返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/models/batch") + public Result>> getVehicleBatch(@RequestParam @Size(max = 500) List vehicleIds) { + List> results = vehicleIds.stream() +@@ -63,7 +63,7 @@ public class InternalVehicleController { + return Result.success(results); + } + +- @ApiOperation("按车辆类型查询车辆") ++ @ApiOperation(value = "按车辆类型查询车辆", notes = "【仅限内部Feign调用】按vehicleType查询第一个匹配的车型。vehicleType如:SEDAN(轿车)、SUV、MPV、BUS(大巴)、MINIBUS(中巴)等。未找到时返回null。\n\n**关联字典**:\n- vehicle_type(车辆类型,请求参数+返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/model/by-type/{vehicleType}") + public Result> getVehicleByType(@PathVariable String vehicleType) { + VehicleModel model = vehicleModelService.getVehicleByType(vehicleType); +@@ -80,7 +80,7 @@ public class InternalVehicleController { + return Result.success(brief); + } + +- @ApiOperation("按名称查询车辆") ++ @ApiOperation(value = "按名称查询车辆", notes = "【仅限内部Feign调用】按车型名称精确查询车辆信息。未找到时返回null。供产品服务通过名称关联车型使用。\n\n**关联字典**:\n- vehicle_type(车辆类型,返回字段vehicleType):CAR=小轿车, SUV=越野车, VAN=商务车, BUS=大巴, MINIBUS=中巴\n- common_status(状态,返回字段status):ACTIVE=启用, INACTIVE=停用") + @GetMapping("/model/by-name/{name}") + public Result> getVehicleByName(@PathVariable String name) { + VehicleModel model = vehicleModelService.getVehicleByName(name); +@@ -97,9 +97,9 @@ public class InternalVehicleController { + return Result.success(brief); + } + +- @ApiOperation("处理审批回调结果") ++ @ApiOperation(value = "处理审批回调结果", notes = "【仅限内部Feign调用】接收企微OA审批回调,按thirdNo匹配车型并更新启用/禁用状态。由hl-callback-service通过MQ消费后调用,幂等处理。\n\n**关联字典**:\n- approval_sp_status(审批状态,请求字段spStatus)") + @PostMapping("/approval-result") +- public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { ++ public Result handleApprovalResult(@RequestBody ApprovalResultDTO dto) { + log.info("Received approval result: thirdNo={}, spStatus={}", dto.getThirdNo(), dto.getSpStatus()); + vehicleModelService.handleApprovalResult(dto.getThirdNo(), dto.getSpStatus()); + return Result.success(); +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java +index de59d9f..37797fd 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleModelController.java +@@ -25,7 +25,7 @@ public class VehicleModelController { + + private final VehicleModelService vehicleModelService; + +- @ApiOperation("创建车型") ++ @ApiOperation(value = "创建车型", notes = "新建车型资源(如7座商务车、14座中巴等),初始状态为草稿(status=0)。车型有独立的价格日历用于报价计算。需走企微审批上架。\n\n**关联字典**:\n- vehicle_type:车辆类型(表单选择)") + @PostMapping("/model") + public Result createVehicle(@ApiParam("车型创建请求") @Valid @RequestBody VehicleCreateRequest request, + HttpServletRequest httpRequest) { +@@ -33,26 +33,26 @@ public class VehicleModelController { + return Result.success(vehicleModelService.createVehicle(request, adminId)); + } + +- @ApiOperation("车型列表") ++ @ApiOperation(value = "车型列表", notes = "分页查询车型列表,支持按名称、状态、车辆类型等条件筛选。\n\n**关联字典**:\n- vehicle_type:车辆类型(筛选+列表显示)") + @GetMapping("/models") + public Result> listVehicles(@ApiParam("车型查询请求") @Valid VehicleQueryRequest query) { + return Result.success(vehicleModelService.listVehicles(query)); + } + +- @ApiOperation("车型全量列表(不分页,用于下拉选择)") ++ @ApiOperation(value = "车型全量列表(不分页,用于下拉选择)", notes = "返回所有车型列表,可选按状态筛选。适用于产品编排时选择车型的下拉选择框。不分页返回全部数据。\n\n**关联字典**:\n- vehicle_type:车辆类型(列表显示)") + @GetMapping("/models/all") + public Result> listAllVehicles( + @ApiParam("状态筛选:1=上架") @RequestParam(required = false) Integer status) { + return Result.success(vehicleModelService.listAllVehicles(status)); + } + +- @ApiOperation("车型详情") ++ @ApiOperation(value = "车型详情", notes = "获取车型完整信息,包含座位数、品牌、素材URL、标签等。\n\n**关联字典**:\n- vehicle_type:车辆类型(详情显示)") + @GetMapping("/model/{vehicleId}") + public Result getVehicle(@ApiParam("车型ID") @PathVariable Long vehicleId) { + return Result.success(vehicleModelService.getVehicle(vehicleId)); + } + +- @ApiOperation("更新车型") ++ @ApiOperation(value = "更新车型", notes = "更新车型基本信息,不改变当前状态。\n\n**关联字典**:\n- vehicle_type:车辆类型(表单选择)") + @PutMapping("/model/{vehicleId}") + public Result updateVehicle(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("车型更新请求") @Valid @RequestBody VehicleUpdateRequest request, +@@ -61,7 +61,7 @@ public class VehicleModelController { + return Result.success(vehicleModelService.updateVehicle(vehicleId, request, adminId)); + } + +- @ApiOperation("删除车型") ++ @ApiOperation(value = "删除车型", notes = "软删除车型。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/model/{vehicleId}") + public Result deleteVehicle(@ApiParam("车型ID") @PathVariable Long vehicleId, HttpServletRequest httpRequest) { + Long adminId = getAdminId(httpRequest); +@@ -70,7 +70,7 @@ public class VehicleModelController { + return Result.success(); + } + +- @ApiOperation("提交审批") ++ @ApiOperation(value = "提交审批", notes = "向企微OA提交车型启用/禁用审批。targetStatus=1申请上架,targetStatus=2申请下架。返回审批单号spNo。") + @PostMapping("/model/{vehicleId}/submit-approval") + public Result> submitApproval(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("审批提交请求体") @Valid @RequestBody ApprovalSubmitRequest request, +@@ -80,7 +80,7 @@ public class VehicleModelController { + return Result.success(Map.of("spNo", spNo)); + } + +- @ApiOperation("更新状态") ++ @ApiOperation(value = "更新状态", notes = "直接修改车型状态(跳过审批),仅限SUPER_ADMIN。状态值:0=草稿,1=上架,2=下架。") + @PutMapping("/model/{vehicleId}/status") + public Result updateStatus(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("状态请求体") @Valid @RequestBody VehicleStatusRequest request, +@@ -90,7 +90,7 @@ public class VehicleModelController { + return Result.success(); + } + +- @ApiOperation("批量更新状态") ++ @ApiOperation(value = "批量更新状态", notes = "批量修改多个车型的状态,跳过审批流程。") + @PutMapping("/models/batch/status") + public Result batchUpdateStatus(@ApiParam("批量状态请求体") @Valid @RequestBody VehicleStatusRequest request, + HttpServletRequest httpRequest) { +@@ -98,7 +98,7 @@ public class VehicleModelController { + return Result.success(); + } + +- @ApiOperation("批量删除") ++ @ApiOperation(value = "批量删除", notes = "批量软删除多个车型。仅SUPER_ADMIN或创建者可操作。") + @DeleteMapping("/models/batch") + public Result batchDelete(@ApiParam("批量删除请求体") @Valid @RequestBody VehicleBatchDeleteRequest request, + HttpServletRequest httpRequest) { +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java +index 52a68eb..c1bcfba 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehiclePriceCalendarController.java +@@ -27,7 +27,7 @@ public class VehiclePriceCalendarController { + + private final VehiclePriceCalendarService priceCalendarService; + +- @ApiOperation("查询价格日历") ++ @ApiOperation(value = "查询价格日历", notes = "按月查询车型的每日租赁价格和可调度状态。") + @GetMapping("/model/{vehicleId}/prices") + public Result getPriceCalendar(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("年份") @RequestParam @Min(2020) @Max(2100) Integer year, +@@ -35,7 +35,7 @@ public class VehiclePriceCalendarController { + return Result.success(priceCalendarService.getPriceCalendar(vehicleId, year, month)); + } + +- @ApiOperation("批量设置价格") ++ @ApiOperation(value = "批量设置价格", notes = "在指定日期范围内批量设置车型的租赁成本价和可调度状态。") + @PutMapping("/model/{vehicleId}/prices") + public Result batchSetPrices(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("价格日历设置请求") @Valid @RequestBody PriceCalendarSetRequest request) { +@@ -43,7 +43,7 @@ public class VehiclePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("批量修改调度状态") ++ @ApiOperation(value = "批量修改调度状态", notes = "批量修改日期范围内车型的可调度状态,不影响价格。") + @PutMapping("/model/{vehicleId}/prices/batch-status") + public Result batchUpdateStatus(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("价格日历状态请求") @Valid @RequestBody PriceCalendarStatusRequest request) { +@@ -51,7 +51,7 @@ public class VehiclePriceCalendarController { + return Result.success(); + } + +- @ApiOperation("清除价格日历") ++ @ApiOperation(value = "清除价格日历", notes = "删除指定日期范围内车型的价格记录。日期格式:yyyy-MM-dd。") + @DeleteMapping("/model/{vehicleId}/prices") + public Result deletePrices(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("开始日期") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, +``` + +### `hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java` (M) + +```diff +diff --git a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java +index a7a1b49..b2ad988 100644 +--- a/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java ++++ b/hl-resource-service/src/main/java/com/hulalv/resource/vehicle/controller/VehicleTagController.java +@@ -26,7 +26,7 @@ public class VehicleTagController { + + private final VehicleTagService tagService; + +- @ApiOperation("预设标签列表(分页)") ++ @ApiOperation(value = "预设标签列表(分页)", notes = "分页查询车型标签库,支持按关键词搜索。") + @GetMapping("/tags") + public Result> listManagedTags( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,13 +35,13 @@ public class VehicleTagController { + return Result.success(tagService.listManagedTags(page, pageSize, keyword)); + } + +- @ApiOperation("全部标签列表") ++ @ApiOperation(value = "全部标签列表", notes = "不分页返回所有标签,用于车型编辑时的标签选择。") + @GetMapping("/tags/all") + public Result> listAllTags() { + return Result.success(tagService.listAllTags()); + } + +- @ApiOperation("创建标签") ++ @ApiOperation(value = "创建标签", notes = "创建预设标签,标签名不可重复。") + @PostMapping("/tag") + public Result createTag(@ApiParam("标签创建请求") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -49,7 +49,7 @@ public class VehicleTagController { + return Result.success(tagService.createTag(request, adminId)); + } + +- @ApiOperation("解析自定义标签") ++ @ApiOperation(value = "解析自定义标签", notes = "按名称查找或自动创建标签。") + @PostMapping("/tag/adhoc") + public Result resolveAdHocTag(@ApiParam("标签名称请求体") @Valid @RequestBody TagCreateRequest request, + HttpServletRequest httpRequest) { +@@ -57,21 +57,21 @@ public class VehicleTagController { + return Result.success(tagService.resolveAdHocTag(request.getTagName(), adminId)); + } + +- @ApiOperation("更新标签") ++ @ApiOperation(value = "更新标签", notes = "修改标签名称或颜色。") + @PutMapping("/tag/{tagId}") + public Result updateTag(@ApiParam("标签ID") @PathVariable Long tagId, + @ApiParam("标签更新请求") @Valid @RequestBody TagUpdateRequest request) { + return Result.success(tagService.updateTag(tagId, request)); + } + +- @ApiOperation("删除标签") ++ @ApiOperation(value = "删除标签", notes = "删除标签并解除所有车型与该标签的关联。") + @DeleteMapping("/tag/{tagId}") + public Result deleteTag(@ApiParam("标签ID") @PathVariable Long tagId) { + tagService.deleteTag(tagId); + return Result.success(); + } + +- @ApiOperation("设置车型标签") ++ @ApiOperation(value = "设置车型标签", notes = "全量替换指定车型的标签列表。") + @PutMapping("/model/{vehicleId}/tags") + public Result updateVehicleTags(@ApiParam("车型ID") @PathVariable Long vehicleId, + @ApiParam("标签ID列表请求") @Valid @RequestBody VehicleTagUpdateRequest request) { +@@ -79,7 +79,7 @@ public class VehicleTagController { + return Result.success(); + } + +- @ApiOperation("批量添加/移除标签") ++ @ApiOperation(value = "批量添加/移除标签", notes = "对多个车型批量添加/移除标签。增量操作。") + @PutMapping("/models/batch/tags") + public Result batchUpdateTags(@ApiParam("批量标签请求") @Valid @RequestBody BatchTagRequest request) { + tagService.batchUpdateTags(request.getVehicleIds(), request.getAddTagIds(), request.getRemoveTagIds()); +``` + +### `hl-review-service/src/main/java/com/hulalv/review/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/config/Knife4jConfig.java b/hl-review-service/src/main/java/com/hulalv/review/config/Knife4jConfig.java +index fde29e7..d3131ce 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/config/Knife4jConfig.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/config/Knife4jConfig.java +@@ -26,18 +26,4 @@ public class Knife4jConfig { + .build(); + } + +- @Bean +- public Docket internalReviewApi() { +- return new Docket(DocumentationType.SWAGGER_2) +- .groupName("2. 评价内部接口") +- .apiInfo(new ApiInfoBuilder() +- .title("评价内部 API") +- .description("评价内部接口(供BFF等服务调用)") +- .version("1.0") +- .build()) +- .select() +- .apis(RequestHandlerSelectors.basePackage("com.hulalv.review.controller")) +- .paths(PathSelectors.ant("/internal/**")) +- .build(); +- } + } +``` + +### `hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java` (M) + +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java b/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java +index 1781646..ad503eb 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/controller/AdminReviewController.java +@@ -25,19 +25,19 @@ public class AdminReviewController { + + private final ReviewService reviewService; + +- @ApiOperation("评价列表(支持好中差评/有图/有视频筛选)") ++ @ApiOperation(value = "评价列表(支持好中差评/有图/有视频筛选)", notes = "分页查询全部评价(含待审核/已通过/已拒绝),支持按评价等级、是否有图/视频、目标类型筛选\n\n**关联字典**:\n- review_status:评价审核状态(列表筛选+显示)\n- rating_level:评价等级(列表筛选+显示)") + @GetMapping("/list") + public Result> listReviews(@ApiParam("评价查询条件") ReviewQueryRequest request) { + return Result.success(reviewService.listReviews(request)); + } + +- @ApiOperation("评价详情") ++ @ApiOperation(value = "评价详情", notes = "**关联字典**:\n- review_status:评价审核状态(显示)\n- rating_level:评价等级(显示)") + @GetMapping("/{reviewId}") + public Result getReviewDetail(@ApiParam("评价ID") @PathVariable Long reviewId) { + return Result.success(reviewService.getReviewDetail(reviewId)); + } + +- @ApiOperation("通过评价") ++ @ApiOperation(value = "通过评价", notes = "审核通过评价,通过后评价在小程序端公开展示。状态流转:PENDING_REVIEW → APPROVED") + @PostMapping("/{reviewId}/approve") + public Result approve(@ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -47,7 +47,7 @@ public class AdminReviewController { + return Result.success(); + } + +- @ApiOperation("拒绝评价") ++ @ApiOperation(value = "拒绝评价", notes = "审核拒绝评价,需填写拒绝原因。拒绝后评价不公开展示。状态流转:PENDING_REVIEW → REJECTED") + @PostMapping("/{reviewId}/reject") + public Result reject(@ApiParam("评价ID") @PathVariable Long reviewId, + @ApiParam("拒绝请求") @Valid @RequestBody RejectRequest body, +@@ -59,7 +59,7 @@ public class AdminReviewController { + return Result.success(); + } + +- @ApiOperation("覆盖通过(机器拒绝的)") ++ @ApiOperation(value = "覆盖通过(机器拒绝的)", notes = "对阿里云内容审核自动拒绝的评价进行人工覆盖通过。状态流转:AUTO_REJECTED → APPROVED") + @PostMapping("/{reviewId}/override-approve") + public Result overrideApprove(@ApiParam("评价ID") @PathVariable Long reviewId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -69,7 +69,8 @@ public class AdminReviewController { + return Result.success(); + } + +- @ApiOperation("回复评价(每条评价仅可回复一次)") ++ @ApiOperation(value = "回复评价(每条评价仅可回复一次)", ++ notes = "管理员回复用户评价,回复内容在小程序端公开展示。每条评价仅允许回复一次,不可修改。\n\n**权限**:需管理员登录。") + @PostMapping("/{reviewId}/reply") + public Result adminReply(@ApiParam("评价ID") @PathVariable Long reviewId, + @ApiParam("回复内容") @Valid @RequestBody AdminReplyRequest body, +``` + +### `hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java` (M) + +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java +index b3dd6a3..62fb7d0 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalMpReviewController.java +@@ -19,7 +19,7 @@ import javax.validation.Valid; + import java.util.List; + import java.util.Map; + +-@Api(tags = "【内部接口】小程序评价(Feign调用)") ++@Api(tags = "【内部接口】小程序评价(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/mp/review") + @RequiredArgsConstructor +@@ -27,7 +27,7 @@ public class InternalMpReviewController { + + private final ReviewService reviewService; + +- @ApiOperation("创建评价(仅针对产品,每个订单仅可评价一次)") ++ @ApiOperation(value = "创建评价(仅针对产品,每个订单仅可评价一次)", notes = "**关联字典**:\n- review_status:评价审核状态(返回字段)\n- rating_level:评价等级(返回字段)") + @PostMapping("/create") + public Result createReview(@Valid @RequestBody CreateReviewRequest body, + HttpServletRequest request) { +@@ -35,13 +35,14 @@ public class InternalMpReviewController { + return Result.success(reviewService.createReview(userId, body)); + } + +- @ApiOperation("检查订单是否已评价") ++ @ApiOperation(value = "检查订单是否已评价", ++ notes = "内部服务间调用。检查指定订单是否已有评价记录,用于小程序端订单详情页控制评价入口的显示。") + @GetMapping("/order/{orderId}/reviewed") + public Result isOrderReviewed(@PathVariable Long orderId) { + return Result.success(reviewService.isOrderReviewed(orderId)); + } + +- @ApiOperation("我的评价列表") ++ @ApiOperation(value = "我的评价列表", notes = "**关联字典**:\n- review_status:评价审核状态(显示)\n- rating_level:评价等级(显示)") + @GetMapping("/my") + public Result> getMyReviews(MpReviewQueryRequest query, + HttpServletRequest request) { +@@ -49,13 +50,13 @@ public class InternalMpReviewController { + return Result.success(reviewService.getMyReviews(userId, query)); + } + +- @ApiOperation("某目标的已通过评价(公开,支持好中差评/有图/有视频筛选)") ++ @ApiOperation(value = "某目标的已通过评价(公开,支持好中差评/有图/有视频筛选)", notes = "**关联字典**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/target") + public Result> getTargetReviews(@Valid TargetReviewQueryRequest query) { + return Result.success(reviewService.getTargetReviews(query)); + } + +- @ApiOperation("关键词搜索评价(公开)") ++ @ApiOperation(value = "关键词搜索评价(公开)", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/search") + public Result> searchReviews( + @ApiParam("搜索关键词") @RequestParam String keyword, +@@ -66,14 +67,15 @@ public class InternalMpReviewController { + return Result.success(reviewService.searchReviews(keyword, targetType, targetId, page, pageSize)); + } + +- @ApiOperation("首页精选评价") ++ @ApiOperation(value = "首页精选评价", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/featured") + public Result> getFeaturedReviews( + @ApiParam("数量限制") @RequestParam(defaultValue = "5") Integer limit) { + return Result.success(reviewService.getFeaturedReviews(limit)); + } + +- @ApiOperation("订单可评价目标列表") ++ @ApiOperation(value = "订单可评价目标列表", ++ notes = "内部服务间调用。返回订单关联的可评价目标(产品、定制师等),用于评价页面选择评价对象。已评价的目标不会重复出现。") + @GetMapping("/order/{orderId}/reviewable-targets") + public Result>> getReviewableTargets( + @PathVariable Long orderId, HttpServletRequest request) { +@@ -81,7 +83,8 @@ public class InternalMpReviewController { + return Result.success(reviewService.getReviewableTargets(orderId, userId)); + } + +- @ApiOperation("点赞/取消点赞评价") ++ @ApiOperation(value = "点赞/取消点赞评价", ++ notes = "内部服务间调用。切换当前用户对评价的点赞状态(toggle),返回最新点赞状态和点赞总数。") + @PostMapping("/{reviewId}/like") + public Result> toggleLike(@PathVariable Long reviewId, + HttpServletRequest request) { +@@ -89,7 +92,8 @@ public class InternalMpReviewController { + return Result.success(reviewService.toggleLike(reviewId, userId)); + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "内部服务间调用。检查当前用户是否已对指定评价点赞,用于小程序端渲染点赞按钮状态。") + @GetMapping("/{reviewId}/like/check") + public Result checkLiked(@PathVariable Long reviewId, + HttpServletRequest request) { +@@ -97,7 +101,8 @@ public class InternalMpReviewController { + return Result.success(reviewService.checkLiked(reviewId, userId)); + } + +- @ApiOperation("同步评价点赞数(供通用点赞服务回调)") ++ @ApiOperation(value = "同步评价点赞数(供通用点赞服务回调)", ++ notes = "内部服务间调用。通用点赞服务(user-service)发生点赞变化后回调此接口,同步更新评价表的点赞计数字段。") + @PostMapping("/{reviewId}/sync-like-count") + public Result syncLikeCount(@PathVariable Long reviewId, + @RequestParam int likeCount) { +``` + +### `hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java` (M) + +```diff +diff --git a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java +index 0567412..7e5f1cb 100644 +--- a/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java ++++ b/hl-review-service/src/main/java/com/hulalv/review/controller/InternalReviewController.java +@@ -21,7 +21,7 @@ import java.util.List; + import java.util.Map; + import java.util.stream.Collectors; + +-@Api(tags = "【内部接口】评价统计(Feign调用)") ++@Api(tags = "【内部接口】评价统计(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/review") + @RequiredArgsConstructor +@@ -29,14 +29,14 @@ public class InternalReviewController { + + private final ReviewService reviewService; + +- @ApiOperation("目标评价统计(平均分,数量)") ++ @ApiOperation(value = "目标评价统计(平均分,数量)", notes = "**关联字典**:\n- rating_level:评价等级(统计维度)") + @GetMapping("/target-stats") + public Result getTargetStats(@RequestParam String targetType, + @RequestParam Long targetId) { + return Result.success(reviewService.getTargetStats(targetType, targetId)); + } + +- @ApiOperation("目标已通过评价列表") ++ @ApiOperation(value = "目标已通过评价列表", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/target-list") + public Result> getTargetReviews( + @RequestParam String targetType, +@@ -46,7 +46,7 @@ public class InternalReviewController { + return Result.success(reviewService.getTargetReviewsInternal(targetType, targetId, page, pageSize)); + } + +- @ApiOperation("批量目标评价统计(聚合多个targetId)") ++ @ApiOperation(value = "批量目标评价统计(聚合多个targetId)", notes = "**关联字典**:\n- rating_level:评价等级(统计维度)") + @GetMapping("/stats-by-targets") + public Result getStatsByTargetIds( + @RequestParam String targetType, +@@ -55,7 +55,7 @@ public class InternalReviewController { + return Result.success(reviewService.getStatsByTargetIds(targetType, ids)); + } + +- @ApiOperation("批量目标已通过评价列表(聚合多个targetId)") ++ @ApiOperation(value = "批量目标已通过评价列表(聚合多个targetId)", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/reviews-by-targets") + public Result> getReviewsByTargetIds( + @RequestParam String targetType, +@@ -66,13 +66,13 @@ public class InternalReviewController { + return Result.success(reviewService.getReviewsByTargetIds(targetType, ids, page, pageSize)); + } + +- @ApiOperation("产品精选评价(最高评分+最高点赞+统计)") ++ @ApiOperation(value = "产品精选评价(最高评分+最高点赞+统计)", notes = "**关联字典**:\n- rating_level:评价等级(显示)") + @GetMapping("/product-highlights") + public Result> getProductHighlights(@RequestParam Long productId) { + return Result.success(reviewService.getProductHighlightReviews(productId)); + } + +- @ApiOperation("定制师已通过评价列表") ++ @ApiOperation(value = "定制师已通过评价列表", notes = "**关联字典**:\n- rating_level:评价等级(筛选+显示)") + @GetMapping("/customizer-reviews") + public Result> getCustomizerReviews( + @RequestParam Long customizerId, +@@ -82,7 +82,8 @@ public class InternalReviewController { + return Result.success(reviewService.getCustomizerReviews(customizerId, page, pageSize, ratingLevel)); + } + +- @ApiOperation("定制师评价统计(总数/平均分/好评率)") ++ @ApiOperation(value = "定制师评价统计(总数/平均分/好评率)", ++ notes = "内部服务间调用。返回指定定制师的评价汇总统计:总评价数、平均评分、好评率等。用于定制师主页展示服务评价。") + @GetMapping("/customizer-review-stats") + public Result> getCustomizerReviewStats( + @RequestParam Long customizerId) { +``` + +### `hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java` (M) + +```diff +diff --git a/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java b/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java +index 75b6a7a..0629ed1 100644 +--- a/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java ++++ b/hl-task-service/src/main/java/com/hulalv/task/controller/BoardController.java +@@ -33,7 +33,7 @@ public class BoardController { + + // ======================= Board CRUD ======================= + +- @ApiOperation("获取可见看板列表") ++ @ApiOperation(value = "获取可见看板列表", notes = "返回当前管理员可见的看板列表:超级管理员可见所有看板,普通管理员仅可见自己创建的或作为成员的看板") + @GetMapping("/boards") + public Result> getBoards(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -41,7 +41,7 @@ public class BoardController { + return Result.success(boardService.getVisibleBoards(adminId, role)); + } + +- @ApiOperation("看板详情") ++ @ApiOperation(value = "看板详情", notes = "返回看板基本信息(名称、描述、创建者),不含任务数据。查看任务请使用「获取看板任务」接口") + @GetMapping("/board/{boardId}") + public Result getBoardDetail(@ApiParam("看板ID") @PathVariable Long boardId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -49,7 +49,8 @@ public class BoardController { + return Result.success(boardService.getBoardDetail(boardId, adminId, role)); + } + +- @ApiOperation("创建自定义看板") ++ @ApiOperation(value = "创建自定义看板", ++ notes = "创建自定义看板,自动添加创建者为看板成员,并创建默认状态列(待办、进行中、已完成)。\n\n**权限**:需管理员登录。") + @OperationLog(value = "创建看板", module = "任务看板") + @PostMapping("/board") + public Result createBoard(@ApiParam("创建看板请求") @Valid @RequestBody CreateBoardRequest req, HttpServletRequest request) { +@@ -57,7 +58,8 @@ public class BoardController { + return Result.success(boardService.createBoard(req, adminId)); + } + +- @ApiOperation("更新看板") ++ @ApiOperation(value = "更新看板", ++ notes = "更新看板的名称和描述。仅看板创建者或超级管理员可操作。\n\n**权限**:需管理员登录,且为看板创建者或超级管理员。") + @OperationLog(value = "编辑看板", module = "任务看板") + @PutMapping("/board/{boardId}") + public Result updateBoard(@ApiParam("看板ID") @PathVariable Long boardId, +@@ -68,7 +70,7 @@ public class BoardController { + return Result.success(boardService.updateBoard(boardId, req, adminId, role)); + } + +- @ApiOperation("删除看板") ++ @ApiOperation(value = "删除看板", notes = "删除看板及其下所有状态列和任务(级联删除)。仅看板创建者或超级管理员可操作") + @OperationLog(value = "删除看板", module = "任务看板") + @DeleteMapping("/board/{boardId}") + public Result deleteBoard(@ApiParam("看板ID") @PathVariable Long boardId, HttpServletRequest request) { +@@ -80,13 +82,14 @@ public class BoardController { + + // ======================= Status columns ======================= + +- @ApiOperation("获取看板状态列") ++ @ApiOperation(value = "获取看板状态列", notes = "返回看板的所有状态列(如待办、进行中、已完成),按排序字段升序排列。拖拽任务到不同状态列实现状态流转") + @GetMapping("/board/{boardId}/statuses") + public Result> getStatuses(@ApiParam("看板ID") @PathVariable Long boardId) { + return Result.success(boardStatusService.getStatuses(boardId)); + } + +- @ApiOperation("创建状态列") ++ @ApiOperation(value = "创建状态列", ++ notes = "在看板中创建新的状态列(如测试中、待发布等),自动排到末尾。任务通过拖拽在不同状态列间流转。\n\n**权限**:需管理员登录且为看板成员。") + @OperationLog(value = "新增状态列", module = "任务看板") + @PostMapping("/board/{boardId}/status") + public Result createStatus(@ApiParam("看板ID") @PathVariable Long boardId, +@@ -97,7 +100,8 @@ public class BoardController { + return Result.success(boardStatusService.createStatus(boardId, req, adminId, role)); + } + +- @ApiOperation("更新状态列") ++ @ApiOperation(value = "更新状态列", ++ notes = "更新状态列的名称和颜色。\n\n**权限**:需管理员登录且为看板成员。") + @OperationLog(value = "编辑状态列", module = "任务看板") + @PutMapping("/status/{statusId}") + public Result updateStatus(@ApiParam("状态列ID") @PathVariable Long statusId, +@@ -108,7 +112,7 @@ public class BoardController { + return Result.success(boardStatusService.updateStatus(statusId, req, adminId, role)); + } + +- @ApiOperation("删除状态列") ++ @ApiOperation(value = "删除状态列", notes = "删除看板的状态列。如果状态列下有任务则不允许删除,需先移动或删除任务") + @OperationLog(value = "删除状态列", module = "任务看板") + @DeleteMapping("/status/{statusId}") + public Result deleteStatus(@ApiParam("状态列ID") @PathVariable Long statusId, +@@ -119,7 +123,7 @@ public class BoardController { + return Result.success(); + } + +- @ApiOperation("状态列排序") ++ @ApiOperation(value = "状态列排序", notes = "批量更新状态列的排序顺序。传入状态列ID数组,数组下标即为新的排序值。操作完成后通过WebSocket推送STATUS_REORDERED事件") + @PutMapping("/board/{boardId}/status/sort") + public Result sortStatuses(@ApiParam("看板ID") @PathVariable Long boardId, + @ApiParam("状态列排序请求") @Valid @RequestBody StatusSortRequest req, +@@ -133,13 +137,14 @@ public class BoardController { + + // ======================= Board Members ======================= + +- @ApiOperation("获取看板成员") ++ @ApiOperation(value = "获取看板成员", notes = "返回看板的所有成员列表,包含成员的管理员ID和姓名") + @GetMapping("/board/{boardId}/members") + public Result> getMembers(@ApiParam("看板ID") @PathVariable Long boardId) { + return Result.success(boardMemberService.getMembers(boardId)); + } + +- @ApiOperation("添加成员") ++ @ApiOperation(value = "添加成员", ++ notes = "批量添加管理员为看板成员,成为成员后可以查看看板、创建和操作任务。\n\n**权限**:需管理员登录,且为看板创建者或超级管理员。") + @OperationLog(value = "添加看板成员", module = "任务看板") + @PostMapping("/board/{boardId}/members") + public Result addMembers(@ApiParam("看板ID") @PathVariable Long boardId, +@@ -151,7 +156,7 @@ public class BoardController { + return Result.success(); + } + +- @ApiOperation("移除成员") ++ @ApiOperation(value = "移除成员", notes = "从看板中移除指定成员。仅看板创建者或超级管理员可操作,不能移除创建者自己") + @OperationLog(value = "移除看板成员", module = "任务看板") + @DeleteMapping("/board/{boardId}/member/{targetAdminId}") + public Result removeMember(@ApiParam("看板ID") @PathVariable Long boardId, +``` + +### `hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java` (M) + +```diff +diff --git a/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java b/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java +index 8593e4d..c85aeca 100644 +--- a/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java ++++ b/hl-task-service/src/main/java/com/hulalv/task/controller/TaskController.java +@@ -31,7 +31,7 @@ public class TaskController { + + // ======================= Tasks ======================= + +- @ApiOperation("获取看板任务(按状态分组)") ++ @ApiOperation(value = "获取看板任务(按状态分组)", notes = "返回看板下所有任务,按状态列分组。支持按优先级(HIGH/MEDIUM/LOW)和负责人筛选,每组内按排序值升序排列\n\n**关联字典**:\n- task_priority:任务优先级(列表筛选+显示)") + @GetMapping("/board/{boardId}/tasks") + public Result> getBoardTasks(@ApiParam("看板ID") @PathVariable Long boardId, + @ApiParam("优先级") @RequestParam(required = false) String priority, +@@ -42,7 +42,7 @@ public class TaskController { + return Result.success(taskService.getBoardTasks(boardId, adminId, role, priority, assigneeId)); + } + +- @ApiOperation("任务详情") ++ @ApiOperation(value = "任务详情", notes = "返回任务完整信息,包含子任务列表、负责人信息、附件列表等\n\n**关联字典**:\n- task_priority:任务优先级(显示)") + @GetMapping("/{taskId}") + public Result getTaskDetail(@ApiParam("任务ID") @PathVariable Long taskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -50,7 +50,7 @@ public class TaskController { + return Result.success(taskService.getTaskDetail(taskId, adminId, role)); + } + +- @ApiOperation("创建任务") ++ @ApiOperation(value = "创建任务", notes = "在指定看板和状态列下创建任务。创建成功后通过WebSocket推送TASK_CREATED事件,并通知被分配的负责人\n\n**关联字典**:\n- task_priority:任务优先级(创建时选择)") + @OperationLog(value = "创建任务", module = "任务看板") + @PostMapping + public Result createTask(@ApiParam("创建任务请求") @Valid @RequestBody CreateTaskRequest req, HttpServletRequest request) { +@@ -62,7 +62,8 @@ public class TaskController { + return Result.success(vo); + } + +- @ApiOperation("更新任务") ++ @ApiOperation(value = "更新任务", ++ notes = "更新任务的标题、描述、优先级、截止日期、负责人等信息。更新后通过WebSocket推送TASK_UPDATED事件,如果修改了负责人则额外通知新负责人。\n\n**权限**:需管理员登录且为看板成员。\n\n**关联字典**:\n- task_priority:任务优先级(编辑时选择)") + @OperationLog(value = "编辑任务", module = "任务看板") + @PutMapping("/{taskId}") + public Result updateTask(@ApiParam("任务ID") @PathVariable Long taskId, +@@ -78,7 +79,7 @@ public class TaskController { + return Result.success(vo); + } + +- @ApiOperation("变更任务状态") ++ @ApiOperation(value = "变更任务状态", notes = "将任务移动到指定状态列(拖拽操作),自动记录状态变更到时间线,并通过WebSocket推送TASK_STATUS_CHANGED事件") + @PutMapping("/{taskId}/status") + public Result changeStatus(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("变更状态请求") @Valid @RequestBody ChangeStatusRequest req, +@@ -91,7 +92,7 @@ public class TaskController { + return Result.success(); + } + +- @ApiOperation("任务排序") ++ @ApiOperation(value = "任务排序", notes = "更新任务在同一状态列内的排序位置,用于拖拽排序") + @PutMapping("/{taskId}/sort") + public Result sortTasks(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("任务排序请求") @Valid @RequestBody TaskSortRequest req, +@@ -102,7 +103,8 @@ public class TaskController { + return Result.success(); + } + +- @ApiOperation("删除任务") ++ @ApiOperation(value = "删除任务", ++ notes = "删除任务及其所有子任务、评论和时间线记录(级联删除)。删除后通过WebSocket推送TASK_DELETED事件。\n\n**权限**:需管理员登录且为看板成员。") + @OperationLog(value = "删除任务", module = "任务看板") + @DeleteMapping("/{taskId}") + public Result deleteTask(@ApiParam("任务ID") @PathVariable Long taskId, HttpServletRequest request) { +@@ -117,7 +119,8 @@ public class TaskController { + + // ======================= Subtasks ======================= + +- @ApiOperation("创建子任务") ++ @ApiOperation(value = "创建子任务", ++ notes = "在指定任务下创建子任务(待办项),用于拆分任务的执行步骤。子任务默认为未完成状态。\n\n**权限**:需管理员登录且为看板成员。") + @PostMapping("/{taskId}/subtask") + public Result createSubtask(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("创建子任务请求") @Valid @RequestBody CreateSubtaskRequest req, +@@ -128,7 +131,7 @@ public class TaskController { + return Result.success(vo); + } + +- @ApiOperation("切换子任务完成状态") ++ @ApiOperation(value = "切换子任务完成状态", notes = "切换子任务的完成/未完成状态(toggle),完成状态切换会自动记录到任务时间线") + @PutMapping("/subtask/{subtaskId}/toggle") + public Result toggleSubtask(@ApiParam("子任务ID") @PathVariable Long subtaskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -137,7 +140,8 @@ public class TaskController { + return Result.success(); + } + +- @ApiOperation("删除子任务") ++ @ApiOperation(value = "删除子任务", ++ notes = "删除指定子任务。\n\n**权限**:需管理员登录且为看板成员。") + @DeleteMapping("/subtask/{subtaskId}") + public Result deleteSubtask(@ApiParam("子任务ID") @PathVariable Long subtaskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -148,7 +152,7 @@ public class TaskController { + + // ======================= Timeline (comments + activities) ======================= + +- @ApiOperation("获取任务时间线") ++ @ApiOperation(value = "获取任务时间线", notes = "返回任务的完整操作记录,包含评论和系统自动记录的状态变更、人员分配等活动,按时间正序排列") + @GetMapping("/{taskId}/timeline") + public Result> getTimeline(@ApiParam("任务ID") @PathVariable Long taskId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -156,7 +160,7 @@ public class TaskController { + return Result.success(commentService.getTimeline(taskId, adminId, role)); + } + +- @ApiOperation("添加评论") ++ @ApiOperation(value = "添加评论", notes = "在任务时间线中添加评论,添加后自动通知任务负责人") + @PostMapping("/{taskId}/comment") + public Result addComment(@ApiParam("任务ID") @PathVariable Long taskId, + @ApiParam("创建评论请求") @Valid @RequestBody CreateCommentRequest req, +@@ -168,7 +172,7 @@ public class TaskController { + return Result.success(item); + } + +- @ApiOperation("删除评论") ++ @ApiOperation(value = "删除评论", notes = "仅评论作者本人可删除自己的评论,系统自动生成的活动记录不可删除") + @DeleteMapping("/comment/{commentId}") + public Result deleteComment(@ApiParam("评论ID") @PathVariable Long commentId, HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/config/Knife4jConfig.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/config/Knife4jConfig.java b/hl-user-service/src/main/java/com/hulalv/user/config/Knife4jConfig.java +index cf77842..eafa329 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/config/Knife4jConfig.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/config/Knife4jConfig.java +@@ -28,8 +28,7 @@ public class Knife4jConfig { + .select() + .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE)) + .paths(PathSelectors.ant("/user/**") +- .or(PathSelectors.ant("/dict/**")) +- .or(PathSelectors.ant("/internal/mp/**"))) ++ .or(PathSelectors.ant("/dict/**"))) + .build(); + } + +@@ -168,15 +167,6 @@ public class Knife4jConfig { + .build(); + } + +- @Bean +- public Docket internalApi() { +- return baseDocket("3. 内部接口(Feign)") +- .select() +- .apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE)) +- .paths(PathSelectors.ant("/internal/**")) +- .build(); +- } +- + private Predicate pathsFor(String... basePaths) { + Predicate combined = s -> false; + for (String path : basePaths) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java +index 10fe201..c012fce 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminAgreementController.java +@@ -22,7 +22,9 @@ public class AdminAgreementController { + + private final AgreementService agreementService; + +- @ApiOperation("协议列表") ++ @ApiOperation(value = "协议列表", notes = "分页查询用户协议列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listAgreements( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -32,20 +34,30 @@ public class AdminAgreementController { + return Result.success(agreementService.listAgreements(page, pageSize, keyword, status)); + } + +- @ApiOperation("协议详情") ++ @ApiOperation(value = "协议详情", ++ notes = "获取指定用户协议的详细信息,包括标题、内容(富文本)、版本号等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getAgreement(@ApiParam("协议ID") @PathVariable Long id) { + return Result.success(agreementService.getAgreement(id)); + } + +- @ApiOperation("新增协议") ++ @ApiOperation(value = "新增协议", ++ notes = "创建新的用户协议,如用户服务协议、隐私政策等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:协议类型(type)需唯一,同一类型不能重复创建。内容支持富文本。") + @OperationLog(value = "新增协议", module = "用户协议管理") + @PostMapping + public Result createAgreement(@Valid @RequestBody AgreementRequest request) { + return Result.success(agreementService.createAgreement(request)); + } + +- @ApiOperation("编辑协议") ++ @ApiOperation(value = "编辑协议", ++ notes = "更新指定用户协议的标题、内容、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:修改后小程序端会实时展示新内容。") + @OperationLog(value = "编辑协议", module = "用户协议管理") + @PutMapping("/{id}") + public Result updateAgreement(@ApiParam("协议ID") @PathVariable Long id, +@@ -53,7 +65,10 @@ public class AdminAgreementController { + return Result.success(agreementService.updateAgreement(id, request)); + } + +- @ApiOperation("删除协议") ++ @ApiOperation(value = "删除协议", ++ notes = "删除指定的用户协议记录(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序端将无法查看该协议。") + @OperationLog(value = "删除协议", module = "用户协议管理") + @DeleteMapping("/{id}") + public Result deleteAgreement(@ApiParam("协议ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java +index 5c47fa0..eec06ab 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminBannerController.java +@@ -23,7 +23,9 @@ public class AdminBannerController { + + private final BannerService bannerService; + +- @ApiOperation("Banner列表") ++ @ApiOperation(value = "Banner列表", notes = "分页查询Banner列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listBanners( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -34,13 +36,20 @@ public class AdminBannerController { + return Result.success(result); + } + +- @ApiOperation("Banner详情") ++ @ApiOperation(value = "Banner详情", ++ notes = "获取指定Banner的详细信息,包括标题、图片、跳转链接、排序等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getBanner(@ApiParam("轮播图ID") @PathVariable Long id) { + return Result.success(bannerService.getBanner(id)); + } + +- @ApiOperation("创建Banner") ++ @ApiOperation(value = "创建Banner", ++ notes = "创建新的首页轮播图,包括标题、封面图、跳转链接、排序等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:创建后默认为启用状态,小程序端将按排序展示。") + @OperationLog(value = "创建Banner", module = "Banner管理") + @PostMapping + public Result createBanner(@ApiParam("轮播图创建请求") @Valid @RequestBody BannerRequest request, +@@ -49,7 +58,9 @@ public class AdminBannerController { + return Result.success(bannerService.createBanner(request, adminId)); + } + +- @ApiOperation("更新Banner") ++ @ApiOperation(value = "更新Banner", ++ notes = "更新指定Banner的标题、封面图、跳转链接、排序、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新Banner", module = "Banner管理") + @PutMapping("/{id}") + public Result updateBanner(@ApiParam("轮播图ID") @PathVariable Long id, +@@ -57,7 +68,10 @@ public class AdminBannerController { + return Result.success(bannerService.updateBanner(id, request)); + } + +- @ApiOperation("删除Banner") ++ @ApiOperation(value = "删除Banner", ++ notes = "删除指定的Banner记录(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序首页将不再展示该Banner。") + @OperationLog(value = "删除Banner", module = "Banner管理") + @DeleteMapping("/{id}") + public Result deleteBanner(@ApiParam("轮播图ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java +index 6080439..786b6ad 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminContactController.java +@@ -22,7 +22,10 @@ public class AdminContactController { + + private final ContactService contactService; + +- @ApiOperation("联系方式列表") ++ @ApiOperation(value = "联系方式列表", notes = "分页查询联系方式列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):返回字段channelType(PHONE=电话, WECHAT=微信, EMAIL=邮箱等)\n" ++ + "- common_status(通用状态):请求参数status和返回字段status") + @GetMapping + public Result> listContacts( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -33,20 +36,27 @@ public class AdminContactController { + return Result.success(result); + } + +- @ApiOperation("联系方式详情") ++ @ApiOperation(value = "联系方式详情", notes = "获取指定联系方式的详细信息。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):返回字段channelType\n" ++ + "- common_status(通用状态):返回字段status") + @GetMapping("/{id}") + public Result getContact(@ApiParam("联系方式ID") @PathVariable Long id) { + return Result.success(contactService.getContact(id)); + } + +- @ApiOperation("创建联系方式") ++ @ApiOperation(value = "创建联系方式", notes = "新增一条联系方式记录。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):请求字段channelType") + @OperationLog(value = "创建联系方式", module = "联系我们管理") + @PostMapping + public Result createContact(@ApiParam("联系方式创建请求") @Valid @RequestBody ContactRequest request) { + return Result.success(contactService.createContact(request)); + } + +- @ApiOperation("更新联系方式") ++ @ApiOperation(value = "更新联系方式", notes = "更新指定联系方式记录。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):请求字段channelType") + @OperationLog(value = "更新联系方式", module = "联系我们管理") + @PutMapping("/{id}") + public Result updateContact(@ApiParam("联系方式ID") @PathVariable Long id, +@@ -54,7 +64,10 @@ public class AdminContactController { + return Result.success(contactService.updateContact(id, request)); + } + +- @ApiOperation("删除联系方式") ++ @ApiOperation(value = "删除联系方式", ++ notes = "删除指定的联系方式记录(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序端将不再展示该联系方式。") + @OperationLog(value = "删除联系方式", module = "联系我们管理") + @DeleteMapping("/{id}") + public Result deleteContact(@ApiParam("联系方式ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java +index 23ad20d..b5b5983 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminCustomerController.java +@@ -19,7 +19,14 @@ public class AdminCustomerController { + + private final UserService userService; + +- @ApiOperation("客户列表") ++ @ApiOperation(value = "客户列表", notes = "分页查询小程序注册的C端用户(客户)列表。" ++ + "支持按昵称/手机号/真实姓名关键词搜索,按状态筛选。" ++ + "status取值:ACTIVE=正常 BANNED=已封禁。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- user_status(用户状态):请求参数status和返回字段status(ACTIVE=正常, BANNED=已封禁)\n" ++ + "- gender(性别):返回字段gender(0=女, 1=男)\n" ++ + "- id_card_type(证件类型):返回字段idCardType") + @GetMapping + public Result> listCustomers( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -30,14 +37,21 @@ public class AdminCustomerController { + return Result.success(result); + } + +- @ApiOperation("客户详情") ++ @ApiOperation(value = "客户详情", notes = "获取指定客户的详细信息。" ++ + "\n\n**关联字典**:\n" ++ + "- user_status(用户状态):返回字段status\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType") + @GetMapping("/{userId}") + public Result getCustomer(@ApiParam("用户ID") @PathVariable Long userId) { + CustomerVO customer = userService.getCustomerDetail(userId); + return Result.success(customer); + } + +- @ApiOperation("封禁客户") ++ @ApiOperation(value = "封禁客户", notes = "封禁指定的C端用户,状态变为BANNED。" ++ + "封禁后该用户无法登录小程序,已有的Token将失效。" ++ + "封禁操作不会删除用户数据,可通过[解封客户]接口恢复。" ++ + "需要管理员认证。") + @OperationLog(value = "封禁客户", module = "客户管理") + @PostMapping("/{userId}/ban") + public Result banCustomer(@ApiParam("用户ID") @PathVariable Long userId) { +@@ -45,7 +59,9 @@ public class AdminCustomerController { + return Result.success(); + } + +- @ApiOperation("解封客户") ++ @ApiOperation(value = "解封客户", notes = "解封已封禁的C端用户,状态恢复为ACTIVE。" ++ + "解封后用户可正常登录小程序。" ++ + "需要管理员认证。") + @OperationLog(value = "解封客户", module = "客户管理") + @PostMapping("/{userId}/unban") + public Result unbanCustomer(@ApiParam("用户ID") @PathVariable Long userId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java +index 5dfa05d..c76c659 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminDesignerController.java +@@ -30,14 +30,18 @@ public class AdminDesignerController { + private final DesignerProfileService designerProfileService; + private final DesignerDashboardService designerDashboardService; + +- @ApiOperation("获取我的个人资料(已废弃,请使用 /admin/profile/me)") ++ @ApiOperation(value = "获取我的个人资料(已废弃,请使用 /admin/profile/me)", notes = "已废弃接口。" ++ + "\n\n**关联字典**:\n" ++ + "- designer_cert_level(认证等级):返回字段certLevel(none/bronze/silver/gold/diamond)") + @GetMapping("/profile") + public Result getMyProfile(HttpServletRequest request) { + Long adminId = getAdminId(request); + return Result.success(designerProfileService.getMyProfile(adminId)); + } + +- @ApiOperation("更新我的个人资料(已废弃,请使用 PUT /admin/profile/me)") ++ @ApiOperation(value = "更新我的个人资料(已废弃,请使用 PUT /admin/profile/me)", ++ notes = "已废弃接口,请迁移至 PUT /admin/profile/me。\n\n" ++ + "**权限**:需要管理员登录。") + @PutMapping("/profile") + public Result updateMyProfile(HttpServletRequest request, + @Valid @RequestBody UpdateDesignerProfileRequest body) { +@@ -45,14 +49,18 @@ public class AdminDesignerController { + return Result.success(designerProfileService.updateMyProfile(adminId, body)); + } + +- @ApiOperation("工作台概览(已废弃,请使用 /admin/profile/dashboard)") ++ @ApiOperation(value = "工作台概览(已废弃,请使用 /admin/profile/dashboard)", ++ notes = "已废弃接口,请迁移至 GET /admin/profile/dashboard。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/dashboard") + public Result getDashboard(HttpServletRequest request) { + Long adminId = getAdminId(request); + return Result.success(designerDashboardService.getDashboard(adminId, "today")); + } + +- @ApiOperation("我的订单列表(已废弃,请使用 /admin/profile/orders)") ++ @ApiOperation(value = "我的订单列表(已废弃,请使用 /admin/profile/orders)", notes = "已废弃接口。" ++ + "\n\n**关联字典**:\n" ++ + "- order_status(订单状态):请求参数status和返回字段status") + @GetMapping("/orders") + public Result>> getMyOrders( + HttpServletRequest request, +@@ -64,7 +72,9 @@ public class AdminDesignerController { + return Result.success(designerDashboardService.getMyOrders(adminId, page, pageSize, status, keyword)); + } + +- @ApiOperation("我的产品列表(已废弃,请使用 /admin/profile/products)") ++ @ApiOperation(value = "我的产品列表(已废弃,请使用 /admin/profile/products)", notes = "已废弃接口。" ++ + "\n\n**关联字典**:\n" ++ + "- product_status(产品状态):请求参数status和返回字段status") + @GetMapping("/products") + public Result>> getMyProducts( + HttpServletRequest request, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java +index ebe2d88..f6fe95a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminExploreCategoryController.java +@@ -24,7 +24,9 @@ public class AdminExploreCategoryController { + + private final ExploreCategoryService exploreCategoryService; + +- @ApiOperation("探索分类列表") ++ @ApiOperation(value = "探索分类列表", notes = "分页查询探索分类列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listCategories( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,13 +37,20 @@ public class AdminExploreCategoryController { + return Result.success(result); + } + +- @ApiOperation("探索分类详情") ++ @ApiOperation(value = "探索分类详情", ++ notes = "获取指定探索分类的详细信息,包括标题、封面图、描述、关联的景区资源列表等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getCategory(@ApiParam("分类ID") @PathVariable Long id) { + return Result.success(exploreCategoryService.getCategory(id)); + } + +- @ApiOperation("创建探索分类") ++ @ApiOperation(value = "创建探索分类", ++ notes = "创建新的探索分类,用于小程序探索页面的分类展示。\n" ++ + "可关联多个景区资源,设置封面图和描述文字。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "创建探索分类", module = "探索管理") + @PostMapping + public Result createCategory(@ApiParam("分类创建请求") @Valid @RequestBody ExploreCategoryRequest request, +@@ -51,7 +60,9 @@ public class AdminExploreCategoryController { + return Result.success(); + } + +- @ApiOperation("更新探索分类") ++ @ApiOperation(value = "更新探索分类", ++ notes = "更新指定探索分类的标题、封面图、描述、关联资源、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新探索分类", module = "探索管理") + @PutMapping("/{id}") + public Result updateCategory(@ApiParam("分类ID") @PathVariable Long id, +@@ -60,7 +71,10 @@ public class AdminExploreCategoryController { + return Result.success(); + } + +- @ApiOperation("删除探索分类") ++ @ApiOperation(value = "删除探索分类", ++ notes = "删除指定的探索分类(软删除),同时清除关联的资源绑定关系。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序探索页面将不再展示该分类。") + @OperationLog(value = "删除探索分类", module = "探索管理") + @DeleteMapping("/{id}") + public Result deleteCategory(@ApiParam("分类ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java +index 61a2dbb..11e1fdd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFaqController.java +@@ -26,20 +26,28 @@ public class AdminFaqController { + + // ==================== 分类 ==================== + +- @ApiOperation("分类列表") ++ @ApiOperation(value = "分类列表", ++ notes = "获取所有FAQ分类的完整列表(不分页)。\n" ++ + "每个分类包含名称、排序号、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/categories") + public Result> listCategories() { + return Result.success(faqService.listCategories()); + } + +- @ApiOperation("创建分类") ++ @ApiOperation(value = "创建分类", ++ notes = "创建新的FAQ分类,用于对常见问题进行归类。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:分类名称不能重复。") + @OperationLog(value = "创建FAQ分类", module = "常见问题管理") + @PostMapping("/categories") + public Result createCategory(@Valid @RequestBody FaqCategoryRequest request) { + return Result.success(faqService.createCategory(request)); + } + +- @ApiOperation("更新分类") ++ @ApiOperation(value = "更新分类", ++ notes = "更新指定FAQ分类的名称、排序号、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新FAQ分类", module = "常见问题管理") + @PutMapping("/categories/{id}") + public Result updateCategory(@ApiParam("分类ID") @PathVariable Long id, +@@ -47,7 +55,10 @@ public class AdminFaqController { + return Result.success(faqService.updateCategory(id, request)); + } + +- @ApiOperation("删除分类") ++ @ApiOperation(value = "删除分类", ++ notes = "删除指定的FAQ分类(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除分类不会删除其下的条目,但条目将变为无分类状态。") + @OperationLog(value = "删除FAQ分类", module = "常见问题管理") + @DeleteMapping("/categories/{id}") + public Result deleteCategory(@ApiParam("分类ID") @PathVariable Long id) { +@@ -57,21 +68,29 @@ public class AdminFaqController { + + // ==================== 条目 ==================== + +- @ApiOperation("条目列表") ++ @ApiOperation(value = "条目列表", ++ notes = "查询FAQ条目列表,支持按分类ID筛选。\n" ++ + "返回问题标题、回答内容(富文本)、排序号等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/items") + public Result> listItems( + @ApiParam("分类ID(可选)") @RequestParam(required = false) Long categoryId) { + return Result.success(faqService.listItems(categoryId)); + } + +- @ApiOperation("创建条目") ++ @ApiOperation(value = "创建条目", ++ notes = "创建一条常见问题,包含问题标题和回答(支持富文本)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:需指定所属分类ID,排序号越小越靠前。") + @OperationLog(value = "创建FAQ条目", module = "常见问题管理") + @PostMapping("/items") + public Result createItem(@Valid @RequestBody FaqItemRequest request) { + return Result.success(faqService.createItem(request)); + } + +- @ApiOperation("更新条目") ++ @ApiOperation(value = "更新条目", ++ notes = "更新指定FAQ条目的问题标题、回答内容、排序号等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新FAQ条目", module = "常见问题管理") + @PutMapping("/items/{id}") + public Result updateItem(@ApiParam("条目ID") @PathVariable Long id, +@@ -79,7 +98,10 @@ public class AdminFaqController { + return Result.success(faqService.updateItem(id, request)); + } + +- @ApiOperation("删除条目") ++ @ApiOperation(value = "删除条目", ++ notes = "删除指定的FAQ条目(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序FAQ页面将不再展示该条目。") + @OperationLog(value = "删除FAQ条目", module = "常见问题管理") + @DeleteMapping("/items/{id}") + public Result deleteItem(@ApiParam("条目ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java +index e81218e..5f5117b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminFrontendConfigController.java +@@ -24,7 +24,9 @@ public class AdminFrontendConfigController { + + private final FrontendConfigService frontendConfigService; + +- @ApiOperation("配置列表") ++ @ApiOperation(value = "配置列表", notes = "分页查询前端配置列表,支持按关键词、分组和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listConfigs( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -35,7 +37,10 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.listConfigs(page, pageSize, keyword, configGroup, status)); + } + +- @ApiOperation("配置列表(不分页)") ++ @ApiOperation(value = "配置列表(不分页)", ++ notes = "获取所有前端配置项的完整列表(不分页),支持按分组和状态筛选。\n" ++ + "适用于需要一次性加载全部配置的场景。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/all") + public Result> listAllConfigs( + @ApiParam("配置分组") @RequestParam(required = false) String configGroup, +@@ -43,25 +48,37 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.listAllConfigs(configGroup, status)); + } + +- @ApiOperation("配置详情") ++ @ApiOperation(value = "配置详情", ++ notes = "根据配置ID获取指定前端配置项的详细信息,包括key、value、分组、描述等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/{id}") + public Result getConfig(@ApiParam("配置ID") @PathVariable Long id) { + return Result.success(frontendConfigService.getConfig(id)); + } + +- @ApiOperation("按key查询配置") ++ @ApiOperation(value = "按key查询配置", ++ notes = "根据配置键(configKey)获取指定的前端配置项。\n" ++ + "configKey为全局唯一标识,如 app_name、primary_color 等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/by-key/{key}") + public Result getConfigByKey(@ApiParam("配置键") @PathVariable String key) { + return Result.success(frontendConfigService.getConfigByKey(key)); + } + +- @ApiOperation("获取所有分组") ++ @ApiOperation(value = "获取所有分组", ++ notes = "获取前端配置中所有已使用的分组名称列表。\n" ++ + "用于配置管理页面的分组筛选下拉框。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/groups") + public Result> listGroups() { + return Result.success(frontendConfigService.listGroups()); + } + +- @ApiOperation("创建配置") ++ @ApiOperation(value = "创建配置", ++ notes = "创建新的前端配置项,用于控制前端页面的展示和行为。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:configKey 必须全局唯一,不能与已有配置重复。" ++ + "可通过 sensitive 字段标记是否为敏感配置(敏感配置不会通过公开接口暴露给小程序)。") + @OperationLog(value = "创建前端配置", module = "前端配置管理") + @PostMapping + public Result createConfig( +@@ -71,7 +88,10 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.createConfig(request, adminId)); + } + +- @ApiOperation("更新配置") ++ @ApiOperation(value = "更新配置", ++ notes = "更新指定前端配置项的值、分组、描述、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:修改后前端会实时使用新值(如有缓存需等待刷新)。") + @OperationLog(value = "更新前端配置", module = "前端配置管理") + @PutMapping("/{id}") + public Result updateConfig( +@@ -80,7 +100,10 @@ public class AdminFrontendConfigController { + return Result.success(frontendConfigService.updateConfig(id, request)); + } + +- @ApiOperation("删除配置") ++ @ApiOperation(value = "删除配置", ++ notes = "删除指定的前端配置项(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后前端将无法获取该配置,可能影响页面展示,请确认无引用后再删除。") + @OperationLog(value = "删除前端配置", module = "前端配置管理") + @DeleteMapping("/{id}") + public Result deleteConfig(@ApiParam("配置ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java +index e174243..6558bc2 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminProfileController.java +@@ -29,7 +29,12 @@ public class AdminProfileController { + private final FinanceDashboardService financeDashboardService; + private final MaterialDashboardService materialDashboardService; + +- @ApiOperation("获取我的个人资料") ++ @ApiOperation(value = "获取我的个人资料", ++ notes = "获取当前登录管理员的个人资料,根据角色返回不同的资料内容。\n" ++ + "定制师角色会返回认证等级、个人简介、擅长领域等附加信息。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- designer_cert_level(认证等级):返回字段certLevel(none/bronze/silver/gold/diamond)") + @GetMapping("/me") + public Result getMyProfile(HttpServletRequest request) { + Long adminId = getAdminId(request); +@@ -37,7 +42,10 @@ public class AdminProfileController { + return Result.success(profileService.getProfile(adminId, role)); + } + +- @ApiOperation("更新我的个人资料") ++ @ApiOperation(value = "更新我的个人资料", ++ notes = "更新当前登录管理员的个人资料,支持修改昵称、头像、个人简介等。\n" ++ + "定制师角色可额外更新擅长领域、服务区域等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @PutMapping("/me") + public Result updateMyProfile(HttpServletRequest request, + @Valid @RequestBody UpdateDesignerProfileRequest body) { +@@ -46,9 +54,19 @@ public class AdminProfileController { + return Result.success(profileService.updateProfile(adminId, role, body)); + } + +- @ApiOperation("工作台仪表盘(角色分发,支持时间范围)") ++ @ApiOperation(value = "工作台仪表盘(角色分发,支持时间范围)", notes = "根据当前管理员角色返回不同的仪表盘数据。" ++ + "CUSTOMIZER(定制师):待处理订单数、产品数、评价统计等。" ++ + "SUPER_ADMIN/ADMIN:全局概览(订单、收入、用户增长等)。" ++ + "ROOM_MANAGER(客房管理):房间分配概览。" ++ + "VEHICLE_MANAGER(车辆管理):车辆调度概览。" ++ + "FINANCE(财务):收支统计。" ++ + "MATERIAL_ADMIN(素材管理):素材库概览。" ++ + "period取值:today=今日 week=本周 month=本月。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- order_status(订单状态):仪表盘中订单统计按状态分组展示") + @GetMapping("/dashboard") +- public Result getDashboard( ++ public Result getDashboard( + HttpServletRequest request, + @ApiParam("时间范围: today/week/month") @RequestParam(defaultValue = "today") String period) { + Long adminId = getAdminId(request); +@@ -72,7 +90,9 @@ public class AdminProfileController { + } + } + +- @ApiOperation("我的评价列表") ++ @ApiOperation(value = "我的评价列表", notes = "查询当前定制师收到的评价列表,支持按评价等级筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- rating_level(评价等级):GOOD=好评, MEDIUM=中评, BAD=差评(筛选条件+列表展示)\n") + @GetMapping("/reviews") + public Result>> getReviews( + HttpServletRequest request, +@@ -83,7 +103,9 @@ public class AdminProfileController { + return Result.success(designerDashboardService.getMyReviews(adminId, page, pageSize, ratingLevel)); + } + +- @ApiOperation("订单列表") ++ @ApiOperation(value = "订单列表", notes = "查询当前定制师的订单列表,支持按状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- order_status(订单状态):请求参数status和返回字段status") + @GetMapping("/orders") + public Result>> getOrders( + HttpServletRequest request, +@@ -95,7 +117,9 @@ public class AdminProfileController { + return Result.success(designerDashboardService.getMyOrders(adminId, page, pageSize, status, keyword)); + } + +- @ApiOperation("产品列表") ++ @ApiOperation(value = "产品列表", notes = "查询当前定制师的产品列表,支持按状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- product_status(产品状态):请求参数status和返回字段status") + @GetMapping("/products") + public Result>> getProducts( + HttpServletRequest request, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java +index 7d2e9bc..e6766e3 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminTopicController.java +@@ -23,7 +23,9 @@ public class AdminTopicController { + + private final TopicService topicService; + +- @ApiOperation("专题列表") ++ @ApiOperation(value = "专题列表", notes = "分页查询探索专题列表,支持按关键词和状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):请求参数status和返回字段status(0=禁用, 1=启用)") + @GetMapping + public Result> listTopics( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -34,13 +36,20 @@ public class AdminTopicController { + return Result.success(result); + } + +- @ApiOperation("专题详情") ++ @ApiOperation(value = "专题详情", ++ notes = "获取指定探索专题的详细信息,包括标题、封面图、描述、关联资源等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- common_status(通用状态):返回字段status(0=禁用, 1=启用)") + @GetMapping("/{id}") + public Result getTopic(@ApiParam("专题ID") @PathVariable Long id) { + return Result.success(topicService.getTopic(id)); + } + +- @ApiOperation("创建专题") ++ @ApiOperation(value = "创建专题", ++ notes = "创建新的探索专题,用于小程序探索页面展示主题推荐内容。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:创建时需设置标题、封面图等基本信息。") + @OperationLog(value = "创建专题", module = "探索专题管理") + @PostMapping + public Result createTopic(@ApiParam("专题创建请求") @Valid @RequestBody TopicRequest request, +@@ -49,7 +58,9 @@ public class AdminTopicController { + return Result.success(topicService.createTopic(request, adminId)); + } + +- @ApiOperation("更新专题") ++ @ApiOperation(value = "更新专题", ++ notes = "更新指定探索专题的标题、封面图、描述、状态等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @OperationLog(value = "更新专题", module = "探索专题管理") + @PutMapping("/{id}") + public Result updateTopic(@ApiParam("专题ID") @PathVariable Long id, +@@ -57,7 +68,10 @@ public class AdminTopicController { + return Result.success(topicService.updateTopic(id, request)); + } + +- @ApiOperation("删除专题") ++ @ApiOperation(value = "删除专题", ++ notes = "删除指定的探索专题(软删除)。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:删除后小程序探索页面将不再展示该专题。") + @OperationLog(value = "删除专题", module = "探索专题管理") + @DeleteMapping("/{id}") + public Result deleteTopic(@ApiParam("专题ID") @PathVariable Long id) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java +index 2b3f74a..0344258 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AdminUserController.java +@@ -26,7 +26,12 @@ public class AdminUserController { + + private final AdminUserService adminUserService; + +- @ApiOperation("创建管理员") ++ @ApiOperation(value = "创建管理员", notes = "创建新的后台管理员账号。" ++ + "默认密码为Admin@123456,管理员首次登录后建议修改密码。" ++ + "可通过roleIds分配多个角色,也兼容旧的单角色roleId参数。" ++ + "需要SUPER_ADMIN或ADMIN角色。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用\n") + @OperationLog(value = "创建管理员", module = "管理员管理") + @PostMapping + public Result createAdmin(@ApiParam("创建管理员请求") @Valid @RequestBody CreateAdminRequest request) { +@@ -34,7 +39,9 @@ public class AdminUserController { + return Result.success(admin); + } + +- @ApiOperation("更新管理员") ++ @ApiOperation(value = "更新管理员", notes = "更新管理员信息,包括用户名、状态、角色分配等。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用\n") + @OperationLog(value = "更新管理员", module = "管理员管理") + @PutMapping("/{adminId}") + public Result updateAdmin(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -43,7 +50,10 @@ public class AdminUserController { + return Result.success(admin); + } + +- @ApiOperation("删除管理员") ++ @ApiOperation(value = "删除管理员", notes = "删除指定管理员账号(软删除)。" ++ + "不能删除自己的账号,不能删除SUPER_ADMIN角色的账号(除非操作者也是SUPER_ADMIN)。" ++ + "删除后该管理员的登录状态自动失效。" ++ + "需要SUPER_ADMIN或ADMIN角色。") + @OperationLog(value = "删除管理员", module = "管理员管理") + @DeleteMapping("/{adminId}") + public Result deleteAdmin(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -54,7 +64,9 @@ public class AdminUserController { + return Result.success(); + } + +- @ApiOperation("解锁管理员") ++ @ApiOperation(value = "解锁管理员", notes = "解锁因登录失败次数过多而被锁定的管理员账号。" ++ + "管理员连续5次登录失败后账号自动锁定30分钟,此接口可立即解锁。" ++ + "需要SUPER_ADMIN或ADMIN角色。") + @OperationLog(value = "解锁管理员", module = "管理员管理") + @PostMapping("/{adminId}/unlock") + public Result unlockAdmin(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -65,7 +77,10 @@ public class AdminUserController { + return Result.success(); + } + +- @ApiOperation("重置密码") ++ @ApiOperation(value = "重置密码", notes = "将指定管理员的密码重置为默认密码(Admin@123456)。" ++ + "用于管理员忘记密码时由上级管理员操作重置。" ++ + "重置后管理员可用默认密码登录,建议立即修改。" ++ + "需要SUPER_ADMIN或ADMIN角色。") + @OperationLog(value = "重置密码", module = "管理员管理") + @PostMapping("/{adminId}/reset-password") + public Result resetPassword(@ApiParam("管理员ID") @PathVariable Long adminId, +@@ -76,7 +91,10 @@ public class AdminUserController { + return Result.success(); + } + +- @ApiOperation("修改企业微信绑定(支持换绑)") ++ @ApiOperation(value = "修改企业微信绑定(支持换绑)", notes = "为管理员绑定或更换企业微信账号。" ++ + "绑定后管理员可通过企业微信扫码登录,并可接收审批通知。" ++ + "如果目标企微ID已被其他管理员绑定,需设置forceRebind=true强制换绑。" ++ + "需要管理员认证。") + @OperationLog(value = "修改企业微信绑定", module = "管理员管理") + @PutMapping("/{adminId}/wechat-binding") + public Result> updateWechatBinding( +@@ -92,14 +110,21 @@ public class AdminUserController { + return Result.success(result); + } + +- @ApiOperation("获取管理员详情") ++ @ApiOperation(value = "获取管理员详情", notes = "获取指定管理员的完整信息。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用\n") + @GetMapping("/{adminId}") + public Result getAdmin(@ApiParam("管理员ID") @PathVariable Long adminId) { + AdminUser admin = adminUserService.getAdminById(adminId); + return Result.success(admin); + } + +- @ApiOperation("管理员列表") ++ @ApiOperation(value = "管理员列表", notes = "分页查询管理员列表,支持按角色、状态、企微绑定状态筛选。" ++ + "status取值:ACTIVE=正常 LOCKED=已锁定 DISABLED=已禁用。" ++ + "wechatBound:true=已绑定企业微信 false=未绑定。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- admin_status(管理员状态):ACTIVE=启用, LOCKED=锁定, DISABLED=禁用(筛选条件+列表展示)\n") + @GetMapping + public Result> listAdmins( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java +index bf6beb1..84bf6c9 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/AuthController.java +@@ -30,7 +30,10 @@ public class AuthController { + @Value("${auth.2fa-confirm-enabled:false}") + private boolean twoFaConfirmEnabled; + +- @ApiOperation("管理员登录") ++ @ApiOperation(value = "管理员登录", notes = "管理员通过用户名+密码登录后台管理系统。" ++ + "首次在新设备登录时需要进行企业微信扫码二次验证(2FA),返回needTwoFa=true。" ++ + "登录失败5次后账号将被锁定30分钟。" ++ + "无需认证即可调用。") + @PostMapping("/login") + public Result login(@ApiParam("管理员登录请求") @Valid @RequestBody AdminLoginRequest request, + HttpServletRequest httpRequest) { +@@ -41,7 +44,10 @@ public class AuthController { + return Result.success(response); + } + +- @ApiOperation("2FA验证") ++ @ApiOperation(value = "2FA验证", notes = "新设备登录时的企业微信二次验证。" ++ + "管理员登录返回needTwoFa=true后,前端调用此接口提交验证码完成登录。" ++ + "验证通过后设备将被标记为可信设备,后续登录不再需要2FA。" ++ + "无需认证即可调用。") + @PostMapping("/wechat/verify-2fa") + public Result verifyTwoFa(@ApiParam("管理员ID") @RequestParam Long adminId, + @ApiParam("2FA验证请求") @Valid @RequestBody TwoFaVerifyRequest request, +@@ -53,7 +59,10 @@ public class AuthController { + return Result.success(response); + } + +- @ApiOperation("修改密码") ++ @ApiOperation(value = "修改密码", notes = "管理员修改自己的登录密码。" ++ + "需验证旧密码正确后才能设置新密码,新密码须满足复杂度要求(8-128位,含大小写字母和数字)。" ++ + "修改成功后当前Token仍然有效,无需重新登录。" ++ + "需要管理员认证(Token中的adminId)。") + @OperationLog(value = "修改密码", module = "认证管理") + @PutMapping("/password") + public Result changePassword(HttpServletRequest request, +@@ -63,7 +72,9 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("管理员登出") ++ @ApiOperation(value = "管理员登出", notes = "清除管理员的登录状态并使当前Token失效。" ++ + "前端应在登出后清除本地存储的Token和用户信息。" ++ + "需要管理员认证。") + @PostMapping("/logout") + public Result logout(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +@@ -71,14 +82,20 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("生成2FA扫码会话") ++ @ApiOperation(value = "生成2FA扫码会话", notes = "生成企业微信扫码二维码的会话信息,用于新设备二次验证。" ++ + "返回包含qrcodeUrl(二维码链接)和state(会话标识)。" ++ + "前端展示二维码后通过轮询 /2fa/check 接口检查扫码状态。" ++ + "无需认证即可调用(登录流程中使用)。") + @GetMapping("/2fa/qrcode") + public Result> generate2FaQrcode(@ApiParam("管理员ID") @RequestParam Long adminId) { + Map data = adminAuthService.generate2FaQrSession(adminId); + return Result.success(data); + } + +- @ApiOperation("2FA企微扫码回调") ++ @ApiOperation(value = "2FA企微扫码回调", notes = "企业微信OAuth回调地址,用户扫码授权后微信服务器回调此接口。" ++ + "此接口由微信服务器调用,非前端直接调用。" ++ + "回调成功后将state对应的会话标记为已扫码,前端轮询 /2fa/check 即可获取结果。" ++ + "返回HTML页面(成功/失败提示),不返回JSON。") + @GetMapping(value = "/2fa/callback", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String handle2FaCallback(@ApiParam("授权码") @RequestParam String code, @ApiParam("会话状态") @RequestParam String state) { +@@ -120,14 +137,19 @@ public class AuthController { + + // ==================== WeChat QR Direct Login ==================== + +- @ApiOperation("生成企业微信扫码登录会话") ++ @ApiOperation(value = "生成企业微信扫码登录会话", notes = "生成企业微信扫码直接登录的会话信息(非2FA验证,而是扫码替代密码登录)。" ++ + "返回包含qrcodeUrl和state。前端展示二维码后通过轮询 /wechat-qr/status 检查登录状态。" ++ + "无需认证即可调用。") + @GetMapping("/wechat-qr") + public Result> generateWechatLoginQr() { + Map data = adminAuthService.generateWechatLoginQrSession(); + return Result.success(data); + } + +- @ApiOperation("企业微信扫码登录回调") ++ @ApiOperation(value = "企业微信扫码登录回调", notes = "企业微信OAuth回调地址,扫码登录授权后微信服务器回调此接口。" ++ + "此接口由微信服务器调用,非前端直接调用。" ++ + "回调后标记会话为已扫码,前端通过轮询 /wechat-qr/status 获取登录结果。" ++ + "返回HTML页面,不返回JSON。") + @GetMapping(value = "/wechat-qr/callback", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String handleWechatLoginCallback(@ApiParam("授权码") @RequestParam String code, @ApiParam("会话状态") @RequestParam String state) { +@@ -167,7 +189,10 @@ public class AuthController { + } + } + +- @ApiOperation("查询企业微信扫码登录状态") ++ @ApiOperation(value = "查询企业微信扫码登录状态", notes = "前端轮询此接口检查扫码登录是否完成。" ++ + "返回status字段:PENDING=等待扫码,SCANNED=已扫码登录成功(附带token和用户信息)。" ++ + "建议轮询间隔2秒,超过5分钟未扫码会话自动失效。" ++ + "无需认证即可调用。") + @GetMapping("/wechat-qr/status") + public Result> checkWechatLoginStatus(@ApiParam("会话状态") @RequestParam String state, + HttpServletRequest httpRequest) { +@@ -178,7 +203,11 @@ public class AuthController { + return Result.success(data); + } + +- @ApiOperation("手动确认扫码(内网穿透环境workaround,默认关闭)") ++ @ApiOperation(value = "手动确认扫码(内网穿透环境workaround,默认关闭)", ++ notes = "在内网穿透环境下,企微回调可能无法正常到达,此接口作为手动替代方案。\n" ++ + "需在Nacos配置中开启 auth.2fa-confirm-enabled=true 才可使用。\n\n" ++ + "**权限**:无需认证(登录流程中使用)。\n" ++ + "**注意**:生产环境应保持关闭,仅限开发/测试时使用。") + @PostMapping("/2fa/confirm") + public Result confirm2FaScan(@ApiParam("会话状态") @RequestParam String state, + @ApiParam("管理员ID") @RequestParam String adminId, +@@ -195,7 +224,10 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("查询2FA扫码状态") ++ @ApiOperation(value = "查询2FA扫码状态", notes = "前端轮询此接口检查2FA扫码验证是否完成。" ++ + "返回status字段:PENDING=等待扫码,SCANNED=已完成验证(附带token和用户信息)。" ++ + "建议轮询间隔2秒,超过5分钟未扫码会话自动失效。" ++ + "无需认证即可调用(登录流程中使用)。") + @GetMapping("/2fa/check") + public Result> check2FaStatus(@ApiParam("会话状态") @RequestParam String state, + HttpServletRequest httpRequest) { +@@ -206,7 +238,10 @@ public class AuthController { + return Result.success(data); + } + +- @ApiOperation("切换当前角色") ++ @ApiOperation(value = "切换当前角色", notes = "多角色管理员切换当前活跃角色。" ++ + "切换后返回新的Token和角色对应的菜单权限,前端需更新本地Token并刷新菜单。" ++ + "只能切换到该管理员已分配的角色,否则报错。" ++ + "需要管理员认证。") + @OperationLog(value = "切换角色", module = "认证管理") + @PostMapping("/switch-role") + public Result switchRole(HttpServletRequest request, +@@ -216,7 +251,10 @@ public class AuthController { + return Result.success(response); + } + +- @ApiOperation("更新头像") ++ @ApiOperation(value = "更新头像", notes = "管理员更新自己的头像。" ++ + "需先通过文件服务上传图片获取OSS URL和fileId,再调用此接口绑定。" ++ + "旧头像的文件引用会自动解绑。" ++ + "需要管理员认证。") + @OperationLog(value = "更新头像", module = "认证管理") + @PutMapping("/avatar") + public Result updateAvatar(HttpServletRequest request, +@@ -226,7 +264,9 @@ public class AuthController { + return Result.success(); + } + +- @ApiOperation("获取当前管理员信息") ++ @ApiOperation(value = "获取当前管理员信息", notes = "获取当前登录管理员的完整信息,包括用户名、头像、角色列表、当前角色、菜单权限等。" ++ + "前端页面初始化时调用此接口获取用户信息和权限数据。" ++ + "需要管理员认证。") + @GetMapping("/info") + public Result getAdminInfo(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java +index 0b374f0..79a06b4 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/FavoriteController.java +@@ -22,7 +22,12 @@ public class FavoriteController { + + private final FavoriteService favoriteService; + +- @ApiOperation("添加收藏") ++ @ApiOperation(value = "添加收藏", notes = "将指定资源添加到当前用户的收藏列表。" ++ + "同一用户对同一资源不可重复收藏,重复收藏会报错。" ++ + "targetType取值:SCENIC_SPOT/ACTIVITY/HOTEL/PRODUCT/EXPLORE等。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索(请求参数targetType)\n") + @PostMapping + public Result addFavorite(HttpServletRequest request, + @ApiParam("收藏请求") @Valid @RequestBody FavoriteRequest favoriteRequest) { +@@ -31,7 +36,11 @@ public class FavoriteController { + return Result.success(favorite); + } + +- @ApiOperation("收藏列表") ++ @ApiOperation(value = "收藏列表", notes = "分页查询当前用户的所有收藏记录,按收藏时间倒序排列。" ++ + "返回收藏记录的基础信息(不包含资源详情),需前端根据targetType和targetId再查详情。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):返回字段targetType,前端据此判断跳转到哪种资源详情页\n") + @GetMapping + public Result> listFavorites(HttpServletRequest request, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -41,7 +50,9 @@ public class FavoriteController { + return Result.success(result); + } + +- @ApiOperation("删除收藏") ++ @ApiOperation(value = "删除收藏", notes = "根据收藏记录ID取消收藏。" ++ + "只能删除自己的收藏记录,删除他人的收藏会报权限错误。" ++ + "需要小程序用户认证。") + @DeleteMapping("/{favoriteId}") + public Result deleteFavorite(HttpServletRequest request, + @ApiParam("收藏ID") @PathVariable Long favoriteId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java +index 2616fdc..a24102e 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/FootprintController.java +@@ -22,7 +22,13 @@ public class FootprintController { + + private final FootprintService footprintService; + +- @ApiOperation("添加足迹") ++ @ApiOperation(value = "添加足迹", notes = "记录用户浏览资源的足迹。" ++ + "同一用户对同一资源多次浏览只保留最新一条记录(更新时间)。" ++ + "resourceType取值:SCENIC_SPOT/ACTIVITY/HOTEL/PRODUCT等。" ++ + "通常由前端在进入资源详情页时自动调用。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品(请求参数resourceType)\n") + @PostMapping + public Result addFootprint(HttpServletRequest request, + @ApiParam("足迹请求") @Valid @RequestBody FootprintRequest footprintRequest) { +@@ -31,7 +37,10 @@ public class FootprintController { + return Result.success(footprint); + } + +- @ApiOperation("足迹列表") ++ @ApiOperation(value = "足迹列表", notes = "分页查询当前用户的浏览足迹,按浏览时间倒序排列。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):返回字段resourceType,前端据此判断跳转到哪种资源详情页\n") + @GetMapping + public Result> listFootprints(HttpServletRequest request, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -41,7 +50,9 @@ public class FootprintController { + return Result.success(result); + } + +- @ApiOperation("删除足迹") ++ @ApiOperation(value = "删除足迹", notes = "根据足迹记录ID删除单条浏览足迹。" ++ + "只能删除自己的足迹记录。" ++ + "需要小程序用户认证。") + @DeleteMapping("/{footprintId}") + public Result deleteFootprint(HttpServletRequest request, + @ApiParam("足迹ID") @PathVariable Long footprintId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java +index 37a5069..bdd7f6d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalApprovalController.java +@@ -22,7 +22,7 @@ import java.util.*; + * Called by other services via Feign (not exposed via gateway). + */ + @Slf4j +-@Api(tags = "【内部接口】审批(Feign调用)") ++@Api(tags = "【内部接口】审批(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/wechat") + @RequiredArgsConstructor +@@ -129,7 +129,11 @@ public class InternalApprovalController { + @Value("${approval.product.control-ids.reason:}") + private String controlIdProductReason; + +- @ApiOperation("Submit approval to enterprise WeChat OA") ++ @ApiOperation(value = "提交企业微信OA审批", notes = "内部接口,由其他服务通过Feign调用提交企微审批申请。" ++ + "根据templateId自动路由到对应的审批模板(资源上下架/产品上下架/退款申请/退款申诉)。" ++ + "需提供adminId(管理员提交)或wechatUserId(代理提交)。" ++ + "返回企微审批单号spNo,用于后续查询审批状态。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/submit-approval") + public Result submitApproval(@RequestBody ApprovalSubmitDTO dto) { + if (dto.getTemplateId() == null || dto.getTemplateId().isEmpty()) { +@@ -183,7 +187,10 @@ public class InternalApprovalController { + return Result.success(result); + } + +- @ApiOperation("Revoke a pending approval in enterprise WeChat OA") ++ @ApiOperation(value = "撤销企业微信OA审批", notes = "内部接口,撤销一个待审批的企微OA审批申请。" ++ + "仅PENDING状态的审批可以撤销,已审批的无法撤销。" ++ + "撤销失败不会抛异常(降级处理),业务侧需自行处理状态。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/revoke-approval/{spNo}") + public Result revokeApproval(@PathVariable String spNo) { + if (spNo == null || spNo.isEmpty()) { +@@ -200,7 +207,12 @@ public class InternalApprovalController { + return Result.success(); + } + +- @ApiOperation("Get approval status from enterprise WeChat OA") ++ @ApiOperation(value = "查询企业微信OA审批状态", notes = "内部接口,根据审批单号查询企微审批的详细状态。" ++ + "返回审批状态(spStatus:1=审批中 2=已通过 3=已驳回 4=已撤销)、申请人、表单数据等。" ++ + "用于审批轮询兜底方案(ApprovalPollingService)。" ++ + "不经过Gateway,仅服务间调用。" ++ + "\n\n**关联字典**:\n" ++ + "- approval_sp_status(审批状态):返回字段spStatus(1=审批中, 2=已通过, 3=已驳回, 4=已撤销)") + @GetMapping("/approval-status/{spNo}") + @SuppressWarnings("unchecked") + public Result> getApprovalStatus(@PathVariable String spNo) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java +index c2204f9..df482d7 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBadgeController.java +@@ -13,7 +13,7 @@ import java.util.Map; + * 徽章内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/badge") + @RequiredArgsConstructor +@@ -21,7 +21,10 @@ public class InternalBadgeController { + + private final BadgeService badgeService; + +- @ApiOperation("获取用户徽章数据") ++ @ApiOperation(value = "获取用户徽章数据", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取指定用户的各类未读数和待处理徽章数据(如未读消息数、待付款订单数等)。\n" ++ + "用于小程序个人中心页面的红点/数字徽章展示。") + @GetMapping + public Result> getUserBadgeData(@RequestParam Long userId) { + return Result.success(badgeService.getUserBadgeData(userId)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java +index 4df5705..b339c1f 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalBannerController.java +@@ -16,7 +16,7 @@ import java.util.List; + * Banner内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/banner") + @RequiredArgsConstructor +@@ -24,7 +24,9 @@ public class InternalBannerController { + + private final BannerService bannerService; + +- @ApiOperation("获取当前有效Banner列表") ++ @ApiOperation(value = "获取当前有效Banner列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取所有状态为启用的Banner列表,按排序号排列,用于小程序首页轮播展示。") + @GetMapping("/active") + public Result> listActiveBanners() { + return Result.success(bannerService.listActiveBanners()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java +index d38d4a3..dc412e7 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalContactController.java +@@ -16,7 +16,7 @@ import java.util.List; + * 联系我们内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/contact") + @RequiredArgsConstructor +@@ -24,7 +24,10 @@ public class InternalContactController { + + private final ContactService contactService; + +- @ApiOperation("获取当前有效联系方式列表") ++ @ApiOperation(value = "获取当前有效联系方式列表", notes = "内部接口,获取所有状态为上线的联系方式。" ++ + "不经过Gateway,仅服务间调用。" ++ + "\n\n**关联字典**:\n" ++ + "- contact_channel_type(联系渠道类型):返回字段channelType(ABOUT=关于我们, ONLINE_CS=在线客服, PHONE=电话咨询)\n") + @GetMapping("/active") + public Result> listActiveContacts() { + return Result.success(contactService.listActiveContacts()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java +index 969a9d2..f96ec05 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalDesignerController.java +@@ -14,7 +14,7 @@ import java.util.List; + * C端定制师内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/designer") + @RequiredArgsConstructor +@@ -22,20 +22,28 @@ public class InternalDesignerController { + + private final DesignerService designerService; + +- @ApiOperation("定制师列表") ++ @ApiOperation(value = "定制师列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "分页获取已上线的定制师列表,用于小程序定制师展示页面。\n" ++ + "返回定制师头像、昵称、认证等级、擅长领域等信息。") + @GetMapping + public Result> listDesigners(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int limit) { + return Result.success(designerService.listDesigners(page, limit)); + } + +- @ApiOperation("推荐定制师") ++ @ApiOperation(value = "推荐定制师", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取一位推荐定制师,用于小程序首页推荐位展示。\n" ++ + "推荐逻辑由后端按权重排序选取。") + @GetMapping("/featured") + public Result getFeaturedDesigner() { + return Result.success(designerService.getFeaturedDesigner()); + } + +- @ApiOperation("定制师详情") ++ @ApiOperation(value = "定制师详情", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取指定定制师的详细信息,包括个人简介、擅长领域、服务案例等。") + @GetMapping("/{id}") + public Result getDesignerDetail(@PathVariable Long id) { + return Result.success(designerService.getDesignerDetail(id)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java +index 1e7bf8d..02ea651 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalExploreCategoryController.java +@@ -26,7 +26,7 @@ import java.util.stream.Collectors; + * 探索分类内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "探索分类小程序接口") ++@Api(tags = "探索分类小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/explore") + @RequiredArgsConstructor +@@ -38,7 +38,10 @@ public class InternalExploreCategoryController { + private final FavoriteService favoriteService; + private final UserLikeService userLikeService; + +- @ApiOperation("获取上线探索分类列表") ++ @ApiOperation(value = "获取上线探索分类列表", notes = "内部接口,获取已上线的探索分类列表,支持排序。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):仅返回status=1(启用)的分类\n" ++ + "- explore_sort_type(排序方式):请求参数sortType(comprehensive=综合, newest=最新, hottest=最热)") + @GetMapping("/active") + public Result> listActive( + @ApiParam("排序方式:comprehensive=综合 newest=最新 hottest=最热") @RequestParam(defaultValue = "comprehensive") String sortType, +@@ -47,7 +50,10 @@ public class InternalExploreCategoryController { + return Result.success(exploreCategoryService.listActive(sortType, page, pageSize)); + } + +- @ApiOperation("获取探索分类详情(自动增加浏览量)") ++ @ApiOperation(value = "获取探索分类详情(自动增加浏览量)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取指定分类的详细信息,同时自动增加浏览量计数。\n" ++ + "如果传入 X-User-Id 请求头,还会返回当前用户的点赞和收藏状态。") + @GetMapping("/{id}") + public Result getActiveDetail( + @ApiParam("分类ID") @PathVariable Long id, +@@ -65,14 +71,19 @@ public class InternalExploreCategoryController { + return Result.success(exploreCategoryService.getActiveDetail(id, isLiked, isFavorited)); + } + +- @ApiOperation("增加浏览量") ++ @ApiOperation(value = "增加浏览量", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "手动增加指定探索分类的浏览量计数(+1)。") + @PostMapping("/{id}/view") + public Result incrementViewCount(@ApiParam("分类ID") @PathVariable Long id) { + exploreCategoryService.incrementViewCount(id); + return Result.success(); + } + +- @ApiOperation("切换收藏状态") ++ @ApiOperation(value = "切换收藏状态", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "切换用户对指定探索分类的收藏状态:已收藏则取消,未收藏则添加。\n" ++ + "返回 true=已收藏,false=已取消收藏。同时更新分类的收藏计数。") + @PostMapping("/{id}/favorite") + public Result toggleFavorite( + @ApiParam("分类ID") @PathVariable Long id, +@@ -101,7 +112,9 @@ public class InternalExploreCategoryController { + } + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "检查用户是否已收藏指定的探索分类,返回 true/false。") + @GetMapping("/{id}/favorite/check") + public Result checkFavorite( + @ApiParam("分类ID") @PathVariable Long id, +@@ -109,7 +122,10 @@ public class InternalExploreCategoryController { + return Result.success(favoriteService.checkFavorite(userId, TARGET_TYPE_EXPLORE, id)); + } + +- @ApiOperation("切换点赞状态") ++ @ApiOperation(value = "切换点赞状态", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "切换用户对指定探索分类的点赞状态:已点赞则取消,未点赞则添加。\n" ++ + "返回 true=已点赞,false=已取消。同时更新分类的点赞计数。") + @PostMapping("/{id}/like") + public Result toggleLike( + @ApiParam("分类ID") @PathVariable Long id, +@@ -119,7 +135,9 @@ public class InternalExploreCategoryController { + return Result.success(liked); + } + +- @ApiOperation("检查是否已点赞") ++ @ApiOperation(value = "检查是否已点赞", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "检查用户是否已点赞指定的探索分类,返回 true/false。") + @GetMapping("/{id}/like/check") + public Result checkLike( + @ApiParam("分类ID") @PathVariable Long id, +@@ -127,7 +145,10 @@ public class InternalExploreCategoryController { + return Result.success(userLikeService.checkLike(userId, TARGET_TYPE_EXPLORE, id)); + } + +- @ApiOperation("获取同分类的景区资源列表") ++ @ApiOperation(value = "获取同分类的景区资源列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据景区ID查找与其同一探索分类下的其他景区资源,用于'相关推荐'展示。\n" ++ + "返回资源ID、名称、描述、封面图等基本信息。") + @GetMapping("/related-scenic") + public Result>> getRelatedScenic( + @ApiParam("景区ID") @RequestParam Long scenicId, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java +index 90d24df..e00222c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFaqController.java +@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController; + + import java.util.List; + +-@Api(tags = "【内部接口】常见问题(Feign调用)") ++@Api(tags = "【内部接口】常见问题(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/faq") + @RequiredArgsConstructor +@@ -20,7 +20,9 @@ public class InternalFaqController { + + private final FaqService faqService; + +- @ApiOperation("获取所有启用的FAQ(含分类和条目)") ++ @ApiOperation(value = "获取所有启用的FAQ(含分类和条目)", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "获取所有状态为启用的FAQ分类及其下属条目,按排序号排列。") + @GetMapping("/all") + public Result> getAllActiveFaq() { + return Result.success(faqService.getAllActiveFaq()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java +index 1f32c3b..4976f91 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalFrontendConfigController.java +@@ -14,7 +14,7 @@ import java.util.List; + * 前端配置内部接口(仅供其他服务通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "【内部接口】前端配置(Feign调用)") ++@Api(tags = "【内部接口】前端配置(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/frontend-config") + @RequiredArgsConstructor +@@ -22,32 +22,42 @@ public class InternalFrontendConfigController { + + private final FrontendConfigService frontendConfigService; + +- @ApiOperation("获取所有启用的前端配置") ++ @ApiOperation(value = "获取所有启用的前端配置", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "获取所有状态为启用的前端配置项列表(含敏感配置)。") + @GetMapping("/all") + public Result> listAllActiveConfigs() { + return Result.success(frontendConfigService.listAllActiveConfigs()); + } + +- @ApiOperation("按分组获取启用的配置") ++ @ApiOperation(value = "按分组获取启用的配置", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "按配置分组名获取该分组下所有已启用的配置项。") + @GetMapping("/group/{group}") + public Result> listActiveConfigsByGroup(@PathVariable String group) { + return Result.success(frontendConfigService.listActiveConfigsByGroup(group)); + } + +- @ApiOperation("按key获取单个配置") ++ @ApiOperation(value = "按key获取单个配置", ++ notes = "内部服务间调用接口,由其他微服务通过 Feign 调用。\n" ++ + "根据 configKey 获取单个已启用的配置项,不存在则返回错误。") + @GetMapping("/key/{key}") + public Result getActiveConfigByKey(@PathVariable String key) { + FrontendConfigVO vo = frontendConfigService.getActiveConfigByKey(key); + return vo != null ? Result.success(vo) : Result.error("配置项不存在"); + } + +- @ApiOperation("获取所有非敏感的前端配置(供小程序使用)") ++ @ApiOperation(value = "获取所有非敏感的前端配置(供小程序使用)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取所有已启用且非敏感(sensitive=false)的配置项,安全地暴露给小程序C端。") + @GetMapping("/public") + public Result> listPublicConfigs() { + return Result.success(frontendConfigService.listPublicConfigs()); + } + +- @ApiOperation("按分组获取非敏感配置(供小程序使用)") ++ @ApiOperation(value = "按分组获取非敏感配置(供小程序使用)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "按分组获取非敏感配置,过滤掉标记为敏感的配置项。") + @GetMapping("/public/group/{group}") + public Result> listPublicConfigsByGroup(@PathVariable String group) { + return Result.success(frontendConfigService.listPublicConfigsByGroup(group)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java +index aba407f..a14b558 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLikeController.java +@@ -14,7 +14,7 @@ import java.util.*; + * 通用点赞内部接口(供 hl-mp-service BFF 通过 Feign 调用) + * 支持任意资源类型:REVIEW, EXPLORE, GUIDE 等 + */ +-@Api(tags = "【内部接口】通用点赞(Feign调用)") ++@Api(tags = "【内部接口】通用点赞(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/like") + @RequiredArgsConstructor +@@ -22,7 +22,9 @@ public class InternalLikeController { + + private final UserLikeService userLikeService; + +- @ApiOperation("切换点赞状态(通用)") ++ @ApiOperation(value = "切换点赞状态(通用)", notes = "内部接口,切换用户对指定资源的点赞状态。" ++ + "\n\n**关联字典**:\n" ++ + "- like_target_type(点赞目标类型):请求参数targetType(REVIEW=评价, EXPLORE=探索, GUIDE=攻略)") + @PostMapping("/toggle") + public Result> toggleLike( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -36,7 +38,9 @@ public class InternalLikeController { + return Result.success(data); + } + +- @ApiOperation("检查是否已点赞(通用)") ++ @ApiOperation(value = "检查是否已点赞(通用)", notes = "内部接口,检查用户是否已点赞指定资源。" ++ + "\n\n**关联字典**:\n" ++ + "- like_target_type(点赞目标类型):请求参数targetType(REVIEW=评价, EXPLORE=探索, GUIDE=攻略)") + @GetMapping("/check") + public Result checkLike( + @ApiParam("目标类型") @RequestParam String targetType, +@@ -45,7 +49,9 @@ public class InternalLikeController { + return Result.success(userLikeService.checkLike(userId, targetType, targetId)); + } + +- @ApiOperation("批量检查是否已点赞(接受字符串ID,避免JS大数精度丢失)") ++ @ApiOperation(value = "批量检查是否已点赞(接受字符串ID,避免JS大数精度丢失)", notes = "内部接口,批量检查用户是否已点赞指定资源列表。" ++ + "\n\n**关联字典**:\n" ++ + "- like_target_type(点赞目标类型):请求参数targetType(REVIEW=评价, EXPLORE=探索, GUIDE=攻略)") + @PostMapping("/batch-check") + public Result> batchCheckLiked( + @ApiParam("目标类型") @RequestParam String targetType, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java +index 124fb4f..179904b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalLoginLogController.java +@@ -24,7 +24,7 @@ import java.util.stream.Collectors; + * Internal endpoint for monitor-service to query login logs. + * NOT exposed via gateway. + */ +-@Api(tags = "【内部接口】登录日志(Feign调用)") ++@Api(tags = "【内部接口】登录日志(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal") + @RequiredArgsConstructor +@@ -35,7 +35,14 @@ public class InternalLoginLogController { + + private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + +- @ApiOperation("Query login logs") ++ @ApiOperation(value = "查询登录日志", notes = "内部接口,供hl-monitor-service通过Feign查询管理员登录日志。" ++ + "支持按管理员ID、登录状态、时间范围筛选。" ++ + "status取值:SUCCESS=登录成功 FAILED=登录失败。" ++ + "时间格式:yyyy-MM-dd HH:mm:ss。" ++ + "不经过Gateway,仅服务间调用。" ++ + "\n\n**关联字典**:\n" ++ + "- login_status(登录状态):请求参数status和返回字段status(SUCCESS=成功, FAILED=失败)\n" ++ + "- login_method(登录方式):返回字段loginMethod(PASSWORD=密码, WECHAT_QR=企微扫码, TWO_FA=二次验证)") + @GetMapping("/login-logs") + public Result> queryLoginLogs( + @RequestParam(defaultValue = "1") int page, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java +index a8f1de8..8e53118 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpCommonController.java +@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.*; + import java.util.List; + import java.util.Map; + +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/common") + @RequiredArgsConstructor +@@ -19,19 +19,26 @@ public class InternalMpCommonController { + + private final CommonService commonService; + +- @ApiOperation("应用配置") ++ @ApiOperation(value = "应用配置", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "获取小程序应用的基础配置信息,如版本号、客服电话等。") + @GetMapping("/config") + public Result> getConfig() { + return Result.success(commonService.getConfig()); + } + +- @ApiOperation("FAQ列表") ++ @ApiOperation(value = "FAQ列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "获取所有启用的FAQ分类及其条目,用于小程序帮助中心页面展示。") + @GetMapping("/faq") + public Result>> listFaq() { + return Result.success(commonService.listFaq()); + } + +- @ApiOperation("提交反馈") ++ @ApiOperation(value = "提交反馈", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "提交用户反馈意见,包括反馈内容、联系方式等。\n" ++ + "需传入 userId 参数标识提交反馈的用户。") + @PostMapping("/feedback") + public Result submitFeedback(@RequestParam Long userId, + @RequestBody UserFeedback feedback) { +@@ -39,13 +46,18 @@ public class InternalMpCommonController { + return Result.success(null); + } + +- @ApiOperation("获取协议文本") ++ @ApiOperation(value = "获取协议文本", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "根据协议类型(如 user_agreement、privacy_policy)获取协议的富文本内容。\n" ++ + "用于小程序协议详情页面展示。") + @GetMapping("/agreement/{type}") + public Result> getAgreement(@PathVariable String type) { + return Result.success(commonService.getAgreement(type)); + } + +- @ApiOperation("获取所有已上线协议列表") ++ @ApiOperation(value = "获取所有已上线协议列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 调用。\n" ++ + "获取所有状态为启用的协议列表,用于小程序注册/登录时展示需要同意的协议链接。") + @GetMapping("/agreement/list") + public Result>> listActiveAgreements() { + return Result.success(commonService.listActiveAgreements()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java +index e634ded..6028ac3 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpDictController.java +@@ -19,7 +19,7 @@ import java.util.stream.Collectors; + * C端字典内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/dict") + @RequiredArgsConstructor +@@ -27,7 +27,9 @@ public class InternalMpDictController { + + private final SysDictService sysDictService; + +- @ApiOperation("获取所有字典数据(C端小程序)") ++ @ApiOperation(value = "获取所有字典数据(C端小程序)", notes = "内部接口,供hl-mp-service通过Feign获取小程序可用的字典数据。" ++ + "返回格式:[{dictType, dictName, dataList}],与管理端字典数据格式一致。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/all") + public Result>> getAllDict() { + List dictList = sysDictService.getAllDictForMiniApp(); +@@ -44,7 +46,8 @@ public class InternalMpDictController { + return Result.success(result); + } + +- @ApiOperation("按字典类型获取字典数据列表") ++ @ApiOperation(value = "按字典类型获取字典数据列表", notes = "内部接口,根据字典类型编码(如order_status)获取该类型下的所有字典数据项。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/type/{dictType}") + public Result> getDictDataByType( + @ApiParam("字典类型编码") @PathVariable String dictType) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java +index 4921435..f32737c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpMessageController.java +@@ -14,7 +14,7 @@ import java.util.HashMap; + import java.util.List; + import java.util.Map; + +-@Api(tags = "小程序消息接口") ++@Api(tags = "小程序消息接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/message") + @RequiredArgsConstructor +@@ -22,19 +22,32 @@ public class InternalMpMessageController { + + private final UserMessageService userMessageService; + +- @ApiOperation("消息分类列表(含未读数和最新消息预览)") ++ @ApiOperation(value = "消息分类列表(含未读数和最新消息预览)", notes = "获取用户的消息分类汇总信息。" ++ + "每个分类返回:分类名称、未读消息数、最新一条消息的标题和时间。" ++ + "用于消息中心首页展示各分类入口。" ++ + "内部接口,由hl-mp-service通过Feign调用。" ++ + "\n\n**关联字典**:\n" ++ + "- message_category(消息分类):返回字段code(ORDER=订单消息, TRIP=行程消息, SYSTEM=系统消息, PROMO=营销消息)") + @GetMapping("/categories") + public Result> getCategories(@RequestParam("userId") Long userId) { + return Result.success(userMessageService.getCategorySummaries(userId)); + } + +- @ApiOperation("消息摘要(兼容旧接口)") ++ @ApiOperation(value = "消息摘要(兼容旧接口)", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "功能同 /categories 接口,保留用于向后兼容旧版本小程序。") + @GetMapping("/summary") + public Result> getSummary(@RequestParam("userId") Long userId) { + return Result.success(userMessageService.getCategorySummaries(userId)); + } + +- @ApiOperation("分类内消息列表(进入后自动标记已读)") ++ @ApiOperation(value = "分类内消息列表(进入后自动标记已读)", notes = "分页查询指定分类下的消息列表,按时间倒序排列。" ++ + "进入该分类后自动将该分类的所有消息标记为已读。" ++ + "categoryCode参数支持旧参数名category(向后兼容)。" ++ + "内部接口,由hl-mp-service通过Feign调用。" ++ + "\n\n**关联字典**:\n" ++ + "- message_category(消息分类):请求参数categoryCode(ORDER=订单消息, TRIP=行程消息, SYSTEM=系统消息, PROMO=营销消息)\n" ++ + "- message_biz_type(关联业务类型):返回字段bizType(ORDER=订单, REFUND=退款, CONTRACT=合同)") + @GetMapping("/list") + public Result> listMessages( + @RequestParam("userId") Long userId, +@@ -47,7 +60,9 @@ public class InternalMpMessageController { + return Result.success(userMessageService.listMessages(userId, code, page, pageSize)); + } + +- @ApiOperation("获取总未读数") ++ @ApiOperation(value = "获取总未读数", notes = "获取用户所有分类的未读消息总数。" ++ + "返回{count: N}格式,用于小程序Tab栏消息角标显示。" ++ + "内部接口,由hl-mp-service通过Feign调用。") + @GetMapping("/unread-count") + public Result> getUnreadCount(@RequestParam("userId") Long userId) { + Map result = new HashMap<>(); +@@ -55,7 +70,10 @@ public class InternalMpMessageController { + return Result.success(result); + } + +- @ApiOperation("全部标记已读") ++ @ApiOperation(value = "全部标记已读", notes = "将消息标记为已读。" ++ + "如果传入categoryCode,则只标记该分类下的消息为已读。" ++ + "如果不传categoryCode,则标记所有消息为已读。" ++ + "内部接口,由hl-mp-service通过Feign调用。") + @PutMapping("/read-all") + public Result markAllRead( + @RequestParam("userId") Long userId, +@@ -70,7 +88,9 @@ public class InternalMpMessageController { + return Result.success(null); + } + +- @ApiOperation("标记已读") ++ @ApiOperation(value = "标记已读", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "将单条消息标记为已读(兼容旧接口,实际已被分类级别标记替代)。") + @PutMapping("/{id}/read") + public Result markRead( + @RequestParam("userId") Long userId, +@@ -79,7 +99,9 @@ public class InternalMpMessageController { + return Result.success(null); + } + +- @ApiOperation("删除消息") ++ @ApiOperation(value = "删除消息", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "删除指定的用户消息记录,删除后不可恢复。") + @DeleteMapping("/{id}") + public Result deleteMessage( + @RequestParam("userId") Long userId, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java +index 69c0674..67190a9 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalMpUserController.java +@@ -22,7 +22,7 @@ import java.util.Map; + * C端用户内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/user") + @RequiredArgsConstructor +@@ -37,26 +37,37 @@ public class InternalMpUserController { + + // ==================== Auth ==================== + +- @ApiOperation("发送短信验证码") ++ @ApiOperation(value = "发送短信验证码", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "向指定手机号发送6位数字短信验证码,有效期5分钟,60秒内不可重复发送。") + @PostMapping("/sms/send") + public Result sendSmsCode(@Valid @RequestBody SendSmsRequest request) { + smsService.sendVerificationCode(request.getPhone()); + return Result.success(); + } + +- @ApiOperation("短信登录") ++ @ApiOperation(value = "短信登录", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "小程序用户通过手机号+短信验证码登录,首次登录自动注册。\n" ++ + "返回JWT Token和用户基本信息。") + @PostMapping("/login/sms") + public Result loginBySms(@Valid @RequestBody SmsLoginRequest request) { + return Result.success(userService.loginBySms(request)); + } + +- @ApiOperation("微信登录") ++ @ApiOperation(value = "微信登录", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "小程序用户通过微信授权码(wx.login获取的code)登录,首次登录自动注册。\n" ++ + "返回JWT Token和用户基本信息,含 needProfile 字段标识是否需要补全资料。") + @PostMapping("/login") + public Result login(@Valid @RequestBody LoginRequest request) { + return Result.success(userService.login(request)); + } + +- @ApiOperation("获取用户信息") ++ @ApiOperation(value = "获取用户信息", notes = "内部接口,获取用户个人资料,含真实手机号。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType") + @GetMapping("/profile") + public Result getProfile(@RequestParam Long userId) { + UserVO vo = userService.getProfile(userId); +@@ -65,21 +76,31 @@ public class InternalMpUserController { + return Result.success(vo); + } + +- @ApiOperation("更新用户信息") ++ @ApiOperation(value = "更新用户信息", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "更新用户个人资料,包括昵称、头像、性别、实名信息等。\n" ++ + "首次补全资料时 realName/idCardType/idCardNo 为必填。\n\n" ++ + "**关联字典**:\n" ++ + "- gender(性别):请求字段gender\n" ++ + "- id_card_type(证件类型):请求字段idCardType") + @PutMapping("/profile") + public Result updateProfile(@RequestParam Long userId, + @Valid @RequestBody UpdateProfileRequest request) { + return Result.success(userService.updateProfile(userId, request)); + } + +- @ApiOperation("用户登出") ++ @ApiOperation(value = "用户登出", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "清除指定用户的登录状态,使Token失效。") + @PostMapping("/logout") + public Result logout(@RequestParam Long userId) { + userService.logout(userId); + return Result.success(); + } + +- @ApiOperation("注销账号") ++ @ApiOperation(value = "注销账号", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "永久注销用户账号(软删除),注销后该手机号可重新注册。") + @DeleteMapping("/account") + public Result deleteAccount(@RequestParam Long userId) { + userService.deleteAccount(userId); +@@ -88,14 +109,18 @@ public class InternalMpUserController { + + // ==================== Favorite ==================== + +- @ApiOperation("添加收藏") ++ @ApiOperation(value = "添加收藏", notes = "内部接口,为用户添加收藏。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索)") + @PostMapping("/favorite") + public Result addFavorite(@RequestParam Long userId, + @Valid @RequestBody FavoriteRequest request) { + return Result.success(favoriteService.addFavorite(userId, request)); + } + +- @ApiOperation("收藏列表") ++ @ApiOperation(value = "收藏列表", notes = "内部接口,获取用户收藏列表。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType和返回字段targetType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索)") + @GetMapping("/favorite") + public Result> listFavorites(@RequestParam Long userId, + @RequestParam(required = false) String targetType, +@@ -104,7 +129,9 @@ public class InternalMpUserController { + return Result.success(favoriteService.listFavorites(userId, targetType, page, pageSize)); + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", notes = "内部接口,检查用户是否已收藏指定资源。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType") + @GetMapping("/favorite/check") + public Result checkFavorite(@RequestParam Long userId, + @RequestParam String targetType, +@@ -112,7 +139,9 @@ public class InternalMpUserController { + return Result.success(favoriteService.checkFavorite(userId, targetType, targetId)); + } + +- @ApiOperation("批量删除收藏") ++ @ApiOperation(value = "批量删除收藏", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据收藏记录ID列表批量删除用户的收藏记录。") + @DeleteMapping("/favorite/batch") + public Result batchDeleteFavorites(@RequestParam Long userId, + @RequestBody List ids) { +@@ -120,7 +149,9 @@ public class InternalMpUserController { + return Result.success(); + } + +- @ApiOperation("按目标取消收藏") ++ @ApiOperation(value = "按目标取消收藏", notes = "内部接口,按目标类型和ID取消收藏。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):请求参数targetType") + @DeleteMapping("/favorite/by-target") + public Result deleteFavoriteByTarget(@RequestParam Long userId, + @RequestParam String targetType, +@@ -129,7 +160,9 @@ public class InternalMpUserController { + return Result.success(); + } + +- @ApiOperation("取消收藏") ++ @ApiOperation(value = "取消收藏", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据收藏记录ID删除单条收藏记录。") + @DeleteMapping("/favorite/{id}") + public Result deleteFavorite(@RequestParam Long userId, @PathVariable Long id) { + favoriteService.deleteFavorite(userId, id); +@@ -138,14 +171,18 @@ public class InternalMpUserController { + + // ==================== Footprint ==================== + +- @ApiOperation("记录足迹") ++ @ApiOperation(value = "记录足迹", notes = "内部接口,记录用户浏览足迹。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):请求参数resourceType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品)") + @PostMapping("/footprint") + public Result addFootprint(@RequestParam Long userId, + @Valid @RequestBody FootprintRequest request) { + return Result.success(footprintService.addFootprint(userId, request)); + } + +- @ApiOperation("足迹列表") ++ @ApiOperation(value = "足迹列表", notes = "内部接口,获取用户足迹列表。" ++ + "\n\n**关联字典**:\n" ++ + "- footprint_resource_type(足迹资源类型):请求参数resourceType和返回字段resourceType(SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品)") + @GetMapping("/footprint") + public Result> listFootprints(@RequestParam Long userId, + @RequestParam(required = false) String resourceType, +@@ -154,7 +191,9 @@ public class InternalMpUserController { + return Result.success(footprintService.listFootprints(userId, resourceType, page, pageSize)); + } + +- @ApiOperation("批量删除足迹") ++ @ApiOperation(value = "批量删除足迹", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据足迹记录ID列表批量删除用户的浏览足迹。") + @DeleteMapping("/footprint/batch") + public Result batchDeleteFootprints(@RequestParam Long userId, + @RequestBody List ids) { +@@ -162,7 +201,9 @@ public class InternalMpUserController { + return Result.success(); + } + +- @ApiOperation("删除足迹") ++ @ApiOperation(value = "删除足迹", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "根据足迹记录ID删除单条浏览足迹。") + @DeleteMapping("/footprint/{id}") + public Result deleteFootprint(@RequestParam Long userId, @PathVariable Long id) { + footprintService.deleteFootprint(userId, id); +@@ -171,26 +212,45 @@ public class InternalMpUserController { + +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java +index df5bc72..581cc22 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalOrderUserController.java +@@ -17,7 +17,7 @@ import java.util.Map; + /** + * Internal API for order service + */ +-@Api(tags = "【内部接口】订单用户(Feign调用)") ++@Api(tags = "【内部接口】订单用户(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/order/user") + @RequiredArgsConstructor +@@ -25,7 +25,10 @@ public class InternalOrderUserController { + + private final UserService userService; + +- @ApiOperation("获取用户基本信息(供订单服务查询使用)") ++ @ApiOperation(value = "获取用户基本信息(供订单服务查询使用)", ++ notes = "内部服务间调用接口,由 hl-order-service 通过 Feign 调用。\n" ++ + "根据 userId 获取用户基本信息(userId、realName、phone),用于订单详情展示。\n" ++ + "**注意**:返回的手机号为真实手机号(未脱敏)。") + @GetMapping("/info") + public Result> getUserInfo(@RequestParam Long userId) { + User user = userService.getById(userId); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java +index fba4363..e432e26 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalTopicController.java +@@ -16,7 +16,7 @@ import java.util.List; + * 探索专题内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/topic") + @RequiredArgsConstructor +@@ -24,7 +24,9 @@ public class InternalTopicController { + + private final TopicService topicService; + +- @ApiOperation("获取当前有效专题列表") ++ @ApiOperation(value = "获取当前有效专题列表", ++ notes = "内部服务间调用接口,由 hl-mp-service 通过 Feign 调用。\n" ++ + "获取所有状态为启用的探索专题列表,按排序号排列,用于小程序探索页面展示。") + @GetMapping("/active") + public Result> listActiveTopics() { + return Result.success(topicService.listActiveTopics()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java +index 6e38f29..d41fb78 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalUserController.java +@@ -29,7 +29,7 @@ import java.util.*; + import java.util.stream.Collectors; + + @Slf4j +-@Api(tags = "【内部接口】用户信息(Feign调用)") ++@Api(tags = "【内部接口】用户信息(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/user") + @RequiredArgsConstructor +@@ -44,7 +44,8 @@ public class InternalUserController { + private final WechatMiniAppClient wechatMiniAppClient; + private final UserService userService; + +- @ApiOperation("Get admin basic info by ID") ++ @ApiOperation(value = "根据ID获取管理员基本信息", notes = "内部接口,供其他服务通过Feign查询管理员基础信息(ID、用户名、头像、企微姓名)。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/admin/info/{adminId}") + public Result getAdminInfo(@PathVariable Long adminId) { + AdminUser admin = adminUserMapper.selectById(adminId); +@@ -55,7 +56,9 @@ public class InternalUserController { + return Result.success(toBasicDTO(admin, wechatNameMap)); + } + +- @ApiOperation("Batch get admin basic info") ++ @ApiOperation(value = "批量获取管理员基本信息", notes = "内部接口,批量查询多个管理员的基础信息。" ++ + "传入adminId列表,返回对应的管理员信息列表。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/admin/batch-info") + public Result> batchGetAdminInfo(@RequestBody List adminIds) { + if (adminIds == null || adminIds.isEmpty()) { +@@ -69,7 +72,9 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Get all departments") ++ @ApiOperation(value = "获取所有部门列表", notes = "内部接口,获取企业微信同步的所有部门数据。" ++ + "用于通知规则配置等场景中的部门选择。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/departments") + public Result> getDepartments() { + List depts = wechatDepartmentMapper.selectList(null); +@@ -85,7 +90,10 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Get admin IDs belonging to a department") ++ @ApiOperation(value = "获取部门下的管理员ID列表", notes = "内部接口,查询指定部门下所有活跃管理员的ID。" ++ + "通过企微用户的部门归属关联到管理员账号。" ++ + "用于通知规则引擎按部门发送通知。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/admin/dept-members/{deptId}") + public Result> getDeptAdminIds(@PathVariable Long deptId) { + // Find wechat users in this department using FIND_IN_SET for exact match +@@ -113,7 +121,9 @@ public class InternalUserController { + return Result.success(adminIds); + } + +- @ApiOperation("Get admins by role key") ++ @ApiOperation(value = "根据角色标识获取管理员列表", notes = "内部接口,根据角色标识(如CUSTOMIZER、FINANCE等)查询该角色下所有活跃管理员。" ++ + "用于通知规则引擎按角色发送通知。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/admin/by-role-key") + public Result> getAdminsByRoleKey(@RequestParam String roleKey) { + if (roleKey == null || roleKey.isBlank()) { +@@ -148,7 +158,10 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Find C-end user ID by phone number") ++ @ApiOperation(value = "根据手机号查找C端用户ID", notes = "内部接口,根据手机号查找活跃的小程序用户。" ++ + "用于订单绑定流程中通过联系人手机号匹配用户。" ++ + "找不到时返回null(不报错)。" ++ + "不经过Gateway,仅服务间调用。") + @GetMapping("/find-by-phone") + public Result findUserByPhone(@RequestParam String phone) { + if (phone == null || phone.isBlank()) { +@@ -162,7 +175,9 @@ public class InternalUserController { + return Result.success(user != null ? user.getUserId() : null); + } + +- @ApiOperation("Generate mini program URL Link for sharing") ++ @ApiOperation(value = "生成小程序URL Link", notes = "内部接口,生成小程序短链接用于分享。" ++ + "通过微信API生成URL Link,可在浏览器/短信中打开小程序指定页面。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/wechat/miniapp/generate-url-link") + public Result> generateUrlLink( + @RequestParam String path, @RequestParam String query) { +@@ -170,7 +185,10 @@ public class InternalUserController { + return Result.success(result); + } + +- @ApiOperation("Send WeChat message to users") ++ @ApiOperation(value = "发送企业微信消息", notes = "内部接口,向指定的企微用户发送文本消息。" ++ + "toUserIds为企微用户ID列表,支持一次发送给多人。" ++ + "用于审批通知、订单提醒等场景。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/wechat/send-message") + public Result sendWechatMessage(@RequestBody WechatMessageDTO dto) { + if (dto.getToUserIds() == null || dto.getToUserIds().isEmpty()) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java +index e0d5a6d..d192b76 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWechatController.java +@@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.*; + * No JWT auth required (excluded from TokenInterceptor via /internal/** pattern). + */ + @Slf4j +-@Api(tags = "【内部接口】企微同步(Feign调用)") ++@Api(tags = "【内部接口】企微同步(Feign调用)", hidden = true) + @RestController + @RequestMapping("/internal/wechat") + @RequiredArgsConstructor +@@ -27,9 +27,11 @@ public class InternalWechatController { + private final WechatSyncService wechatSyncService; + private final ExternalContactNotifyService externalContactNotifyService; + +- @ApiOperation("Sync single user from callback") ++ @ApiOperation(value = "同步单个企微用户(回调触发)", notes = "内部接口,由hl-callback-service在收到企微通讯录变更回调时调用。" ++ + "将单个用户的信息同步到本地wechat_user表。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/user/sync") +- public Result syncUser(@RequestBody WechatUserSyncDTO dto) { ++ public Result syncUser(@RequestBody WechatUserSyncDTO dto) { + log.info("Internal: sync user userid={}", dto.getUserid()); + try { + wechatSyncService.syncSingleUserFromDto(dto); +@@ -40,9 +42,11 @@ public class InternalWechatController { + } + } + +- @ApiOperation("Delete single user from callback") ++ @ApiOperation(value = "删除单个企微用户(回调触发)", notes = "内部接口,由hl-callback-service在收到企微成员离职回调时调用。" ++ + "从本地wechat_user表中删除该用户记录。" ++ + "不经过Gateway,仅服务间调用。") + @DeleteMapping("/user/{userid}") +- public Result deleteUser(@PathVariable("userid") String userid) { ++ public Result deleteUser(@PathVariable("userid") String userid) { + log.info("Internal: delete user userid={}", userid); + try { + wechatSyncService.deleteSingleUser(userid); +@@ -53,9 +57,11 @@ public class InternalWechatController { + } + } + +- @ApiOperation("Sync single department from callback") ++ @ApiOperation(value = "同步单个企微部门(回调触发)", notes = "内部接口,由hl-callback-service在收到企微部门变更回调时调用。" ++ + "将单个部门的信息同步到本地wechat_department表。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/department/sync") +- public Result syncDepartment(@RequestBody WechatDeptSyncDTO dto) { ++ public Result syncDepartment(@RequestBody WechatDeptSyncDTO dto) { + log.info("Internal: sync department deptId={}", dto.getId()); + try { + wechatSyncService.syncSingleDepartmentFromDto(dto); +@@ -66,18 +72,22 @@ public class InternalWechatController { + } + } + +- @ApiOperation("Receive external contact change event") ++ @ApiOperation(value = "接收外部联系人变更事件", notes = "内部接口,由hl-callback-service在收到企微外部联系人变更回调时调用。" ++ + "处理客户添加/删除等事件,异步执行通知逻辑。" ++ + "不经过Gateway,仅服务间调用。") + @PostMapping("/external-contact/event") +- public Result handleExternalContactEvent(@RequestBody ExternalContactEventDTO dto) { ++ public Result handleExternalContactEvent(@RequestBody ExternalContactEventDTO dto) { + log.info("Internal: external contact event changeType={}, userId={}, externalUserId={}", + dto.getChangeType(), dto.getUserId(), dto.getExternalUserId()); + externalContactNotifyService.processEventAsync(dto); + return Result.success(); + } + +- @ApiOperation("Delete single department from callback") ++ @ApiOperation(value = "删除单个企微部门(回调触发)", notes = "内部接口,由hl-callback-service在收到企微部门删除回调时调用。" ++ + "从本地wechat_department表中删除该部门记录。" ++ + "不经过Gateway,仅服务间调用。") + @DeleteMapping("/department/{deptId}") +- public Result deleteDepartment(@PathVariable("deptId") Long deptId) { ++ public Result deleteDepartment(@PathVariable("deptId") Long deptId) { + log.info("Internal: delete department deptId={}", deptId); + try { + wechatSyncService.deleteSingleDepartment(deptId); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java +index 44641ef..e3cf403 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/InternalWishController.java +@@ -15,7 +15,7 @@ import java.util.Map; + * 祈愿内部接口(仅供 hl-mp-service BFF 通过 Feign 调用) + * 不经过认证拦截器(/internal/** 已排除) + */ +-@Api(tags = "小程序接口") ++@Api(tags = "小程序接口", hidden = true) + @RestController + @RequestMapping("/internal/mp/wish") + @RequiredArgsConstructor +@@ -23,13 +23,17 @@ public class InternalWishController { + + private final WishService wishService; + +- @ApiOperation("获取用户祈愿列表") ++ @ApiOperation(value = "获取用户祈愿列表", notes = "内部接口,获取用户的祈愿列表。" ++ + "\n\n**关联字典**:\n" ++ + "- wish_type(心愿类型):返回字段wishType(1=想去的地方, 2=想做的事, 3=其他)") + @GetMapping + public Result> listWishes(@RequestParam Long userId) { + return Result.success(wishService.listWishes(userId)); + } + +- @ApiOperation("创建祈愿") ++ @ApiOperation(value = "创建祈愿", notes = "内部接口,创建用户祈愿。" ++ + "\n\n**关联字典**:\n" ++ + "- wish_type(心愿类型):请求参数wishType(1=想去的地方, 2=想做的事, 3=其他)") + @PostMapping + public Result createWish(@RequestParam Long userId, + @RequestBody Map request) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java +index 5acc247..753577c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/OfficialAccountCallbackController.java +@@ -24,7 +24,7 @@ import java.util.Map; + @RestController + @RequestMapping("/oa/callback") + @RequiredArgsConstructor +-@Api(tags = "【回调接口】公众号回调") ++@Api(tags = "【回调接口】公众号回调", hidden = true) + public class OfficialAccountCallbackController { + + private final WechatOfficialAccountClient oaClient; +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java +index 6d1ec31..38f0ad6 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/PublicDictController.java +@@ -24,7 +24,12 @@ public class PublicDictController { + + private final SysDictService sysDictService; + +- @ApiOperation("获取所有字典数据") ++ @ApiOperation(value = "获取所有字典数据(公开接口)", notes = "获取系统全部字典类型及其字典数据,供小程序C端使用。" ++ + "无需认证即可调用。返回格式与管理端 /admin/dict/all 一致。" ++ + "\n\n**字典层级说明**:\n" ++ + "- 每个元素包含 dictType(编码)、dictName(名称)、dataList(字典数据列表)\n" ++ + "- 前端通过 dictType 匹配业务字段,用 dataList 中的 dictValue/dictLabel 做翻译展示\n" ++ + "- 常用字典:order_status、product_status、id_card_type、gender、traveler_type、favorite_resource_type、footprint_resource_type\n") + @GetMapping("/all") + public Result> getAllDict() { + return Result.success(sysDictService.getAllDictForPublic()); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java +index 5be6ee7..260eadd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysDictController.java +@@ -26,7 +26,14 @@ public class SysDictController { + + // ======================== All Dict ======================== + +- @ApiOperation("获取所有字典数据") ++ @ApiOperation(value = "获取所有字典数据", notes = "获取系统全部字典类型及其字典数据,按字典类型分组返回。" ++ + "用于后台管理系统初始化时一次性加载所有下拉选项。" ++ + "返回结果包含dictType编码、dictName名称、dataList数据列表。" ++ + "需要管理员认证。" ++ + "\n\n**字典层级说明**:\n" ++ + "- 字典类型(SysDictType):一级分类,如 admin_status、order_status、id_card_type 等\n" ++ + "- 字典数据(SysDictData):二级选项,归属于某个字典类型,如 admin_status 下的 ACTIVE/LOCKED/DISABLED\n" ++ + "- 前端通过 dictType 编码查找对应的 dataList,用 dictValue 匹配实际数据进行翻译展示\n") + @GetMapping("/all") + public Result> getAllDict() { + return Result.success(sysDictService.getAllDictForPublic()); +@@ -34,14 +41,21 @@ public class SysDictController { + + // ======================== Dict Type ======================== + +- @ApiOperation("创建字典类型") ++ @ApiOperation(value = "创建字典类型", notes = "新建一个字典类型(如:订单状态、证件类型等)。" ++ + "字典类型编码(dictType)全局唯一,创建后不可修改。" ++ + "需要管理员认证,建议仅SUPER_ADMIN/ADMIN角色操作。" ++ + "\n\n**已有字典类型示例**:\n" ++ + "- admin_status(管理员状态)、common_status(通用状态)、login_status(登录状态)\n" ++ + "- order_status(订单状态)、product_status(产品状态)、rating_level(评价等级)\n" ++ + "- id_card_type(证件类型)、gender(性别)、traveler_type(出行人类型)\n" ++ + "- contact_channel_type(联系方式渠道类型)、favorite_resource_type(收藏资源类型)、footprint_resource_type(足迹资源类型)\n") + @OperationLog(value = "创建字典类型", module = "字典管理") + @PostMapping("/type") + public Result createDictType(@ApiParam("创建字典类型请求") @Valid @RequestBody CreateDictTypeRequest request) { + return Result.success(sysDictService.createDictType(request)); + } + +- @ApiOperation("更新字典类型") ++ @ApiOperation(value = "更新字典类型", notes = "更新字典类型的名称、分类、备注等信息。字典类型编码(dictType)不可修改。") + @OperationLog(value = "更新字典类型", module = "字典管理") + @PutMapping("/type/{id}") + public Result updateDictType(@ApiParam("字典类型ID") @PathVariable Long id, +@@ -49,7 +63,9 @@ public class SysDictController { + return Result.success(sysDictService.updateDictType(id, request)); + } + +- @ApiOperation("删除字典类型") ++ @ApiOperation(value = "删除字典类型", notes = "删除字典类型及其下所有字典数据(软删除)。" ++ + "如果该字典类型已被业务引用,删除后不影响已有数据,但新的表单将无法选择该字典值。" ++ + "需要管理员认证。") + @OperationLog(value = "删除字典类型", module = "字典管理") + @DeleteMapping("/type/{id}") + public Result deleteDictType(@ApiParam("字典类型ID") @PathVariable Long id) { +@@ -57,7 +73,8 @@ public class SysDictController { + return Result.success(); + } + +- @ApiOperation("分页查询字典类型") ++ @ApiOperation(value = "分页查询字典类型", notes = "分页查询字典类型列表,支持按分类(category)筛选。" ++ + "字典类型是字典数据的上级分组,管理字典类型即管理有哪些可供前端使用的下拉选项组。") + @GetMapping("/type") + public Result> listDictTypes( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -66,7 +83,7 @@ public class SysDictController { + return Result.success(sysDictService.listDictTypes(page, pageSize, category)); + } + +- @ApiOperation("根据ID获取字典类型详情") ++ @ApiOperation(value = "根据ID获取字典类型详情", notes = "获取单个字典类型的详细信息,包括编码、名称、分类、状态等。") + @GetMapping("/type/{dictTypeId}") + public Result getDictTypeById(@ApiParam("字典类型ID") @PathVariable Long dictTypeId) { + return Result.success(sysDictService.getDictTypeById(dictTypeId)); +@@ -74,14 +91,16 @@ public class SysDictController { + + // ======================== Dict Data ======================== + +- @ApiOperation("创建字典数据") ++ @ApiOperation(value = "创建字典数据", notes = "在指定字典类型下新增一条字典数据项。" ++ + "dictValue为前端匹配的值(如ACTIVE),dictLabel为前端展示的标签(如'启用')。" ++ + "支持树形字典数据(通过parentId设置父级)。") + @OperationLog(value = "创建字典数据", module = "字典管理") + @PostMapping("/data") + public Result createDictData(@ApiParam("创建字典数据请求") @Valid @RequestBody CreateDictDataRequest request) { + return Result.success(sysDictService.createDictData(request)); + } + +- @ApiOperation("更新字典数据") ++ @ApiOperation(value = "更新字典数据", notes = "更新字典数据项的标签、样式类型、排序号等。dictValue建议不修改以免影响已有业务数据。") + @OperationLog(value = "更新字典数据", module = "字典管理") + @PutMapping("/data/{id}") + public Result updateDictData(@ApiParam("字典数据ID") @PathVariable Long id, +@@ -89,7 +108,7 @@ public class SysDictController { + return Result.success(sysDictService.updateDictData(id, request)); + } + +- @ApiOperation("删除字典数据") ++ @ApiOperation(value = "删除字典数据", notes = "删除指定字典数据项(软删除)。删除后不影响已引用该字典值的业务数据。") + @OperationLog(value = "删除字典数据", module = "字典管理") + @DeleteMapping("/data/{id}") + public Result deleteDictData(@ApiParam("字典数据ID") @PathVariable Long id) { +@@ -97,19 +116,23 @@ public class SysDictController { + return Result.success(); + } + +- @ApiOperation("根据ID获取字典数据详情") ++ @ApiOperation(value = "根据ID获取字典数据详情", notes = "获取单个字典数据项的详细信息,包括dictValue、dictLabel、cssClass等。") + @GetMapping("/data/detail/{dictDataId}") + public Result getDictDataById(@ApiParam("字典数据ID") @PathVariable Long dictDataId) { + return Result.success(sysDictService.getDictDataById(dictDataId)); + } + +- @ApiOperation("按类型查询字典数据(树形结构)") ++ @ApiOperation(value = "按类型查询字典数据(树形结构)", notes = "根据字典类型ID查询其下所有字典数据,以树形结构返回(支持父子级字典数据)。" ++ + "用于多级联动下拉框场景(如省市区)。" ++ + "需要管理员认证。") + @GetMapping("/data/tree/{dictTypeId}") + public Result> getDictDataTree(@ApiParam("字典类型ID") @PathVariable Long dictTypeId) { + return Result.success(sysDictService.getDictDataTree(dictTypeId)); + } + +- @ApiOperation("按类型查询字典数据") ++ @ApiOperation(value = "按类型查询字典数据", notes = "根据字典类型编码(如order_status)查询其下所有字典数据(平铺列表)。" ++ + "用于单层下拉框场景。" ++ + "需要管理员认证。") + @GetMapping("/data/{dictType}") + public Result> getDictDataByType(@ApiParam("字典类型编码") @PathVariable String dictType) { + return Result.success(sysDictService.getDictDataByType(dictType)); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java +index 22b99cb..d58905e 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysJobController.java +@@ -5,9 +5,9 @@ import com.hulalv.common.result.PageResult; + import com.hulalv.common.result.Result; + import com.hulalv.user.dto.CreateJobRequest; + import com.hulalv.user.dto.UpdateJobRequest; +-import com.hulalv.user.entity.SysJob; +-import com.hulalv.user.entity.SysJobLog; + import com.hulalv.user.service.SysJobService; ++import com.hulalv.user.vo.SysJobLogVO; ++import com.hulalv.user.vo.SysJobVO; + import io.swagger.annotations.Api; + import io.swagger.annotations.ApiOperation; + import io.swagger.annotations.ApiParam; +@@ -24,22 +24,39 @@ public class SysJobController { + + private final SysJobService sysJobService; + +- @ApiOperation("创建定时任务") ++ @ApiOperation(value = "创建定时任务", notes = "创建新的定时任务。" ++ + "invokeTarget格式为'Bean名称.方法名'(如wechatSyncService.syncAll),方法必须是无参公开方法。" ++ + "cronExpression为标准6位Cron表达式(秒 分 时 日 月 周)。" ++ + "创建后任务默认为暂停状态(PAUSED),需手动调用[恢复任务]接口启用。" ++ + "\n\n**关联字典**:\n" ++ + "- job_group(任务分组):DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步\n" ++ + "- job_misfire_policy(执行策略):DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发\n" ++ + "- job_status(任务状态):ACTIVE=启用, PAUSED=已暂停\n\n" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "创建定时任务", module = "定时任务") + @PostMapping +- public Result createJob(@ApiParam("创建定时任务请求") @Valid @RequestBody CreateJobRequest request) { ++ public Result createJob(@ApiParam("创建定时任务请求") @Valid @RequestBody CreateJobRequest request) { + return Result.success(sysJobService.createJob(request)); + } + +- @ApiOperation("更新定时任务") ++ @ApiOperation(value = "更新定时任务", ++ notes = "更新指定定时任务的名称、Cron表达式、调用目标等信息。\n" ++ + "修改Cron表达式后任务将按新的计划执行。\n\n" ++ + "**关联字典**:\n" ++ + "- job_group(任务分组):DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步\n" ++ + "- job_misfire_policy(执行策略):DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。") + @OperationLog(value = "更新定时任务", module = "定时任务") + @PutMapping("/{jobId}") +- public Result updateJob(@ApiParam("定时任务ID") @PathVariable Long jobId, ++ public Result updateJob(@ApiParam("定时任务ID") @PathVariable Long jobId, + @ApiParam("更新定时任务请求") @Valid @RequestBody UpdateJobRequest request) { + return Result.success(sysJobService.updateJob(jobId, request)); + } + +- @ApiOperation("删除定时任务") ++ @ApiOperation(value = "删除定时任务", ++ notes = "删除指定的定时任务(软删除),同时从调度器中移除该任务。\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。\n" ++ + "**注意**:删除后任务将不再执行,但历史执行日志仍可查看。") + @OperationLog(value = "删除定时任务", module = "定时任务") + @DeleteMapping("/{jobId}") + public Result deleteJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -47,15 +64,22 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("分页查询定时任务") ++ @ApiOperation(value = "分页查询定时任务", notes = "分页查询定时任务列表。" ++ + "\n\n**关联字典**:\n" ++ + "- job_group(任务分组):DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步\n" ++ + "- job_misfire_policy(执行策略):DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发\n" ++ + "- job_status(任务状态):ACTIVE=启用, PAUSED=已暂停") + @GetMapping +- public Result> listJobs( ++ public Result> listJobs( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, + @ApiParam("每页条数") @RequestParam(defaultValue = "20") int pageSize) { + return Result.success(sysJobService.listJobs(page, pageSize)); + } + +- @ApiOperation("暂停任务") ++ @ApiOperation(value = "暂停任务", notes = "暂停指定的定时任务,任务状态变为PAUSED。" ++ + "暂停后任务不再按Cron计划执行,但可通过[恢复任务]接口重新启用。" ++ + "\n\n**关联字典**:job_status(任务状态):ACTIVE=启用, PAUSED=已暂停\n\n" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "暂停任务", module = "定时任务") + @PostMapping("/{jobId}/pause") + public Result pauseJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -63,7 +87,10 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("恢复任务") ++ @ApiOperation(value = "恢复任务", notes = "恢复已暂停的定时任务,任务状态变为ACTIVE。" ++ + "恢复后任务按Cron计划继续执行。" ++ + "\n\n**关联字典**:job_status(任务状态):ACTIVE=启用, PAUSED=已暂停\n\n" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "恢复任务", module = "定时任务") + @PostMapping("/{jobId}/resume") + public Result resumeJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -71,7 +98,10 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("立即执行一次") ++ @ApiOperation(value = "立即执行一次", notes = "立即触发一次定时任务的执行,不影响原有的Cron计划。" ++ + "无论任务当前状态是ACTIVE还是PAUSED,都可以手动触发。" ++ + "执行结果可在任务日志中查看。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "立即执行任务", module = "定时任务") + @PostMapping("/{jobId}/trigger") + public Result triggerJob(@ApiParam("定时任务ID") @PathVariable Long jobId) { +@@ -79,9 +109,12 @@ public class SysJobController { + return Result.success(); + } + +- @ApiOperation("查询任务日志") ++ @ApiOperation(value = "查询任务日志", notes = "分页查询指定定时任务的执行日志,按执行时间倒序排列。" ++ + "日志包含执行状态(成功/失败)、执行耗时、异常信息等。" ++ + "\n\n**关联字典**:job_log_status(日志状态):SUCCESS=成功, FAIL=失败\n\n" ++ + "需要管理员认证。") + @GetMapping("/{jobId}/logs") +- public Result> listJobLogs( ++ public Result> listJobLogs( + @ApiParam("定时任务ID") @PathVariable Long jobId, + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, + @ApiParam("每页条数") @RequestParam(defaultValue = "20") int pageSize) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java +index 46e8615..44e4293 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysMenuController.java +@@ -24,14 +24,27 @@ public class SysMenuController { + + private final SysMenuService sysMenuService; + +- @ApiOperation("创建菜单") ++ @ApiOperation(value = "创建菜单", notes = "创建新的菜单/目录/按钮。" ++ + "menuType取值:DIRECTORY=目录(含子菜单) MENU=页面菜单 BUTTON=操作按钮。" ++ + "目录和菜单需设置path路由路径,菜单还需设置component组件路径。" ++ + "按钮类型需设置permissionCode权限标识(如system:user:add)。" ++ + "需要SUPER_ADMIN角色。" ++ + "\n\n**关联字典**:\n" ++ + "- menu_type(菜单类型):请求/返回字段menuType(DIRECTORY=目录, MENU=菜单, BUTTON=按钮)\n" ++ + "- common_status(通用状态):返回字段status") + @OperationLog(value = "创建菜单", module = "菜单管理") + @PostMapping + public Result createMenu(@ApiParam("创建菜单请求") @Valid @RequestBody CreateMenuRequest request) { + return Result.success(sysMenuService.createMenu(request)); + } + +- @ApiOperation("更新菜单") ++ @ApiOperation(value = "更新菜单", ++ notes = "更新指定菜单的名称、路径、组件、图标、排序、状态等信息。\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。\n" ++ + "**注意**:修改后需清除 Redis 菜单缓存才能生效。\n\n" ++ + "**关联字典**:\n" ++ + "- menu_type(菜单类型):请求字段menuType(DIRECTORY=目录, MENU=菜单, BUTTON=按钮)\n" ++ + "- common_status(通用状态):请求字段status") + @OperationLog(value = "更新菜单", module = "菜单管理") + @PutMapping("/{menuId}") + public Result updateMenu(@ApiParam("菜单ID") @PathVariable Long menuId, +@@ -39,7 +52,11 @@ public class SysMenuController { + return Result.success(sysMenuService.updateMenu(menuId, request)); + } + +- @ApiOperation("删除菜单") ++ @ApiOperation(value = "删除菜单", ++ notes = "删除指定的菜单/目录/按钮(软删除)。\n\n" ++ + "**权限**:需要SUPER_ADMIN角色。\n" ++ + "**注意**:如果该菜单有子菜单,需先删除子菜单才能删除父菜单。" ++ + "删除后需清除 Redis 菜单缓存才能生效。") + @OperationLog(value = "删除菜单", module = "菜单管理") + @DeleteMapping("/{menuId}") + public Result deleteMenu(@ApiParam("菜单ID") @PathVariable Long menuId) { +@@ -47,25 +64,42 @@ public class SysMenuController { + return Result.success(); + } + +- @ApiOperation("获取菜单详情") ++ @ApiOperation(value = "获取菜单详情", ++ notes = "获取指定菜单的详细信息,包括名称、路径、组件、图标、排序、权限标识等。\n\n" ++ + "**权限**:需要管理员登录。\n\n" ++ + "**关联字典**:\n" ++ + "- menu_type(菜单类型):返回字段menuType(DIRECTORY=目录, MENU=菜单, BUTTON=按钮)\n" ++ + "- common_status(通用状态):返回字段status") + @GetMapping("/{menuId}") + public Result getMenu(@ApiParam("菜单ID") @PathVariable Long menuId) { + return Result.success(sysMenuService.getMenuById(menuId)); + } + +- @ApiOperation("获取完整菜单树") ++ @ApiOperation(value = "获取完整菜单树", notes = "获取系统所有菜单的完整树形结构。" ++ + "用于角色权限配置页面展示完整的菜单树供勾选。" ++ + "仅SUPER_ADMIN可查看完整菜单树。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- menu_type(菜单类型):返回字段menuType\n" ++ + "- common_status(通用状态):返回字段status") + @GetMapping("/tree") + public Result> getMenuTree() { + return Result.success(sysMenuService.getMenuTree()); + } + +- @ApiOperation("获取角色菜单树") ++ @ApiOperation(value = "获取角色菜单树", ++ notes = "获取指定角色已分配的菜单树形结构。\n" ++ + "用于角色权限配置页面,展示该角色已拥有的菜单权限。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/tree/role/{roleId}") + public Result> getMenuTreeByRoleId(@ApiParam("角色ID") @PathVariable Long roleId) { + return Result.success(sysMenuService.getMenuTreeByRoleId(roleId)); + } + +- @ApiOperation("获取当前管理员菜单") ++ @ApiOperation(value = "获取当前管理员菜单", notes = "获取当前登录管理员的菜单树(基于其当前角色的权限)。" ++ + "SUPER_ADMIN角色返回完整菜单树,其他角色返回已授权的菜单子集。" ++ + "前端登录后调用此接口动态生成路由和侧边栏菜单。" ++ + "需要管理员认证。") + @GetMapping("/my") + public Result> getMyMenus(HttpServletRequest request) { + Long adminId = (Long) request.getAttribute("adminId"); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java +index 1e4979d..52f6507 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/SysRoleController.java +@@ -25,14 +25,19 @@ public class SysRoleController { + + private final SysRoleService sysRoleService; + +- @ApiOperation("创建角色") ++ @ApiOperation(value = "创建角色", notes = "创建新的系统角色。" ++ + "角色标识(roleKey)全局唯一,创建后不可修改,用于代码中的权限判断。" ++ + "创建后需通过[分配菜单权限]接口为角色授权菜单。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "创建角色", module = "角色管理") + @PostMapping + public Result createRole(@ApiParam("创建角色请求") @Valid @RequestBody CreateRoleRequest request) { + return Result.success(sysRoleService.createRole(request)); + } + +- @ApiOperation("更新角色") ++ @ApiOperation(value = "更新角色", notes = "更新角色名称、状态等信息。角色标识(roleKey)不可修改。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):ACTIVE=启用, DISABLED=禁用\n") + @OperationLog(value = "更新角色", module = "角色管理") + @PutMapping("/{roleId}") + public Result updateRole(@ApiParam("角色ID") @PathVariable Long roleId, +@@ -40,7 +45,10 @@ public class SysRoleController { + return Result.success(sysRoleService.updateRole(roleId, request)); + } + +- @ApiOperation("删除角色") ++ @ApiOperation(value = "删除角色", notes = "删除指定角色(软删除)。" ++ + "如果该角色下还有关联的管理员,将无法删除,需先解除绑定关系。" ++ + "内置角色(SUPER_ADMIN等)不可删除。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "删除角色", module = "角色管理") + @DeleteMapping("/{roleId}") + public Result deleteRole(@ApiParam("角色ID") @PathVariable Long roleId) { +@@ -48,13 +56,17 @@ public class SysRoleController { + return Result.success(); + } + +- @ApiOperation("获取角色详情(含菜单ID)") ++ @ApiOperation(value = "获取角色详情(含菜单ID)", notes = "获取角色基本信息及其已分配的菜单ID列表。" ++ + "返回role对象和menuIds数组,用于角色编辑页面回显已勾选的菜单。" ++ + "需要管理员认证。") + @GetMapping("/{roleId}") + public Result> getRoleDetail(@ApiParam("角色ID") @PathVariable Long roleId) { + return Result.success(sysRoleService.getRoleDetail(roleId)); + } + +- @ApiOperation("分页查询角色") ++ @ApiOperation(value = "分页查询角色", notes = "分页查询系统角色列表,支持按状态筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- common_status(通用状态):ACTIVE=启用, DISABLED=禁用(筛选条件+列表展示)\n") + @GetMapping + public Result> listRoles( + @ApiParam("页码") @RequestParam(defaultValue = "1") int page, +@@ -63,13 +75,19 @@ public class SysRoleController { + return Result.success(sysRoleService.listRoles(page, pageSize, status)); + } + +- @ApiOperation("获取所有角色(下拉)") ++ @ApiOperation(value = "获取所有角色(下拉)", notes = "获取所有状态正常的角色列表,用于下拉选择框。" ++ + "不分页,返回全部角色。创建管理员、筛选管理员列表时使用。" ++ + "需要管理员认证。") + @GetMapping("/all") + public Result> getAllRoles() { + return Result.success(sysRoleService.getAllRoles()); + } + +- @ApiOperation("分配菜单权限") ++ @ApiOperation(value = "分配菜单权限", notes = "为指定角色分配菜单权限(全量覆盖模式)。" ++ + "传入的menuIds将完全替换该角色原有的菜单权限。" ++ + "分配后该角色的所有在线管理员下次请求 /admin/menu/my 时会获取到新的菜单树。" ++ + "注意:需同步清除Redis中的菜单缓存,否则前端拿到的是旧菜单。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "分配菜单权限", module = "角色管理") + @PutMapping("/{roleId}/menus") + public Result assignMenus(@ApiParam("角色ID") @PathVariable Long roleId, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java +index 5f71654..ac3f257 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/TravelerController.java +@@ -22,7 +22,15 @@ public class TravelerController { + + private final TravelerService travelerService; + +- @ApiOperation("新增出行人") ++ @ApiOperation(value = "新增出行人", notes = "为当前用户添加一位出行人信息,用于下单时选择。" ++ + "出行人类型(成人/儿童/婴儿)根据出生日期自动判断,无需手动传入。" ++ + "如果传入身份证号,后端自动校验格式并解析性别。" ++ + "每个用户最多可添加20位出行人。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):请求/返回字段gender(0=女, 1=男)\n" ++ + "- id_card_type(证件类型):请求/返回字段idCardType(ID_CARD=身份证, PASSPORT=护照等)\n" ++ + "- traveler_type(出行人类型):返回字段travelerType(ADULT=成人, CHILD=儿童, INFANT=婴儿,自动计算)") + @PostMapping + public Result addTraveler(HttpServletRequest request, + @ApiParam("出行人信息") @Valid @RequestBody TravelerRequest travelerRequest) { +@@ -31,7 +39,14 @@ public class TravelerController { + return Result.success(traveler); + } + +- @ApiOperation("出行人列表") ++ @ApiOperation(value = "出行人列表", notes = "获取当前用户的所有出行人列表。" ++ + "如果用户已完成实名认证(realName不为空),列表首项会自动注入一个'本人'虚拟出行人(travelerId=0)。" ++ + "默认出行人排在前面,其余按创建时间排序。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType\n" ++ + "- traveler_type(出行人类型):返回字段travelerType") + @GetMapping + public Result> listTravelers(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -39,7 +54,11 @@ public class TravelerController { + return Result.success(travelers); + } + +- @ApiOperation("出行人详情") ++ @ApiOperation(value = "出行人详情", notes = "获取指定出行人的详细信息。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):返回字段gender\n" ++ + "- id_card_type(证件类型):返回字段idCardType\n" ++ + "- traveler_type(出行人类型):返回字段travelerType") + @GetMapping("/{travelerId}") + public Result getTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId) { +@@ -48,7 +67,11 @@ public class TravelerController { + return Result.success(traveler); + } + +- @ApiOperation("更新出行人") ++ @ApiOperation(value = "更新出行人", notes = "更新指定出行人的信息。" ++ + "\n\n**关联字典**:\n" ++ + "- gender(性别):请求/返回字段gender\n" ++ + "- id_card_type(证件类型):请求/返回字段idCardType\n" ++ + "- traveler_type(出行人类型):返回字段travelerType(自动计算)") + @PutMapping("/{travelerId}") + public Result updateTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId, +@@ -58,7 +81,10 @@ public class TravelerController { + return Result.success(traveler); + } + +- @ApiOperation("删除出行人") ++ @ApiOperation(value = "删除出行人", ++ notes = "删除指定的出行人记录(软删除)。\n\n" ++ + "**权限**:需要小程序用户认证。\n" ++ + "**注意**:如果该出行人已关联到未完成的订单,删除不影响订单中的出行人快照数据。") + @DeleteMapping("/{travelerId}") + public Result deleteTraveler(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId) { +@@ -67,7 +93,10 @@ public class TravelerController { + return Result.success(); + } + +- @ApiOperation("设为默认出行人") ++ @ApiOperation(value = "设为默认出行人", notes = "将指定出行人设为默认。" ++ + "每个用户只能有一个默认出行人,设置新的默认会自动取消原来的默认。" ++ + "默认出行人在下单时会被自动选中。" ++ + "需要小程序用户认证。") + @PutMapping("/{travelerId}/default") + public Result setDefault(HttpServletRequest request, + @ApiParam("出行人ID") @PathVariable Long travelerId) { +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java +index f5d5dc0..24ecd04 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/UserController.java +@@ -29,28 +29,42 @@ public class UserController { + private final SmsService smsService; + private final FavoriteService favoriteService; + +- @ApiOperation("发送短信验证码") ++ @ApiOperation(value = "发送短信验证码", notes = "向指定手机号发送6位数字短信验证码,用于小程序手机号登录。" ++ + "同一手机号60秒内不可重复发送,每日最多发送10次。" ++ + "验证码有效期5分钟。" ++ + "无需认证即可调用。") + @PostMapping("/sms/send") + public Result sendSmsCode(@ApiParam("发送短信验证码请求") @Valid @RequestBody SendSmsRequest request) { + smsService.sendVerificationCode(request.getPhone()); + return Result.success(); + } + +- @ApiOperation("手机号验证码登录") ++ @ApiOperation(value = "手机号验证码登录", notes = "小程序用户通过手机号+短信验证码登录。" ++ + "首次登录自动注册账号,返回JWT Token。" ++ + "登录成功后若needProfile=true,表示需要补充个人信息(实名认证),前端应跳转到信息补充页。" ++ + "无需认证即可调用。") + @PostMapping("/login/sms") + public Result loginBySms(@ApiParam("短信验证码登录请求") @Valid @RequestBody SmsLoginRequest request) { + LoginResponse response = userService.loginBySms(request); + return Result.success(response); + } + +- @ApiOperation("微信登录") ++ @ApiOperation(value = "微信登录", notes = "小程序用户通过微信授权码(wx.login获取的code)登录。" ++ + "可选传入phoneCode用于获取手机号绑定,avatar和nickname用于设置头像昵称。" ++ + "首次登录自动注册,返回JWT Token。needProfile=true表示需补充实名信息。" ++ + "无需认证即可调用。") + @PostMapping("/login") + public Result login(@ApiParam("微信登录请求") @Valid @RequestBody LoginRequest request) { + LoginResponse response = userService.login(request); + return Result.success(response); + } + +- @ApiOperation("获取用户信息") ++ @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的个人资料,包括昵称、头像、手机号(脱敏)、实名信息等。" ++ + "手机号返回脱敏格式(如138****0000),证件号同样脱敏处理。" ++ + "需要小程序用户认证(Token中的userId)。" ++ + "\n\n**关联字典**:\n" ++ + "- id_card_type(证件类型):ID_CARD=身份证, PASSPORT=护照\n" ++ + "- gender(性别):0=女, 1=男\n") + @GetMapping("/profile") + public Result getProfile(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -58,7 +72,14 @@ public class UserController { + return Result.success(user); + } + +- @ApiOperation("更新用户信息") ++ @ApiOperation(value = "更新用户信息", notes = "更新当前用户的个人资料。" ++ + "首次登录补充信息时realName/idCardType/idCardNo为必填(使用ProfileCompletion验证组)。" ++ + "如果传入身份证号,后端自动解析性别和出生日期。" ++ + "更新手机号后会自动绑定匹配的待绑定订单。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- id_card_type(证件类型):ID_CARD=身份证, PASSPORT=护照(请求参数idCardType)\n" ++ + "- gender(性别):0=女, 1=男\n") + @PutMapping("/profile") + public Result updateProfile(HttpServletRequest request, + @ApiParam("更新用户信息请求") @Valid @RequestBody UpdateProfileRequest updateRequest) { +@@ -67,7 +88,8 @@ public class UserController { + return Result.success(user); + } + +- @ApiOperation("用户登出") ++ @ApiOperation(value = "用户登出", notes = "清除当前用户的登录状态并使Token失效。" ++ + "需要小程序用户认证。") + @PostMapping("/logout") + public Result logout(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -75,7 +97,10 @@ public class UserController { + return Result.success(); + } + +- @ApiOperation("注销账号") ++ @ApiOperation(value = "注销账号", notes = "永久注销当前用户账号(软删除)。" ++ + "注销后该账号的openid和手机号将被释放,可用于重新注册。" ++ + "注销操作不可撤销,请谨慎调用。" ++ + "需要小程序用户认证。") + @DeleteMapping("/account") + public Result deleteAccount(HttpServletRequest request) { + Long userId = (Long) request.getAttribute("userId"); +@@ -83,7 +108,12 @@ public class UserController { + return Result.success(); + } + +- @ApiOperation("检查是否已收藏") ++ @ApiOperation(value = "检查是否已收藏", notes = "检查当前用户是否已收藏指定类型的资源。" ++ + "返回true=已收藏,false=未收藏。" ++ + "targetType取值:SCENIC_SPOT/ACTIVITY/HOTEL/PRODUCT/EXPLORE等。" ++ + "需要小程序用户认证。" ++ + "\n\n**关联字典**:\n" ++ + "- favorite_resource_type(收藏资源类型):SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索(请求参数targetType)\n") + @GetMapping("/favorite/check") + public Result checkFavorite(HttpServletRequest request, + @ApiParam("目标类型") @RequestParam String targetType, +``` + +### `hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java b/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java +index 2b68e9c..03cca6a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/controller/WechatSyncController.java +@@ -23,7 +23,10 @@ public class WechatSyncController { + + private final WechatSyncService wechatSyncService; + +- @ApiOperation("手动同步部门") ++ @ApiOperation(value = "手动同步部门", notes = "从企业微信拉取最新的部门列表并同步到本地数据库。" ++ + "通常在企业微信后台调整组织架构后手动触发。" ++ + "也可通过定时任务自动执行。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "手动同步部门", module = "企业微信同步") + @PostMapping("/sync/departments") + public Result syncDepartments() { +@@ -31,7 +34,10 @@ public class WechatSyncController { + return Result.success(); + } + +- @ApiOperation("手动同步用户") ++ @ApiOperation(value = "手动同步用户", notes = "从企业微信拉取所有部门的成员列表并同步到本地数据库。" ++ + "包括姓名、手机号、职位、部门归属等信息。" ++ + "需先同步部门再同步用户,或直接使用[同步全部]接口。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "手动同步用户", module = "企业微信同步") + @PostMapping("/sync/users") + public Result syncUsers() { +@@ -39,7 +45,10 @@ public class WechatSyncController { + return Result.success(); + } + +- @ApiOperation("手动同步全部(部门+用户)") ++ @ApiOperation(value = "手动同步全部(部门+用户)", notes = "一键同步企业微信的部门和用户数据,先同步部门再同步用户。" ++ + "推荐使用此接口而非单独同步,确保部门和用户数据一致性。" ++ + "同步过程为异步执行,接口立即返回成功。" ++ + "需要SUPER_ADMIN角色。") + @OperationLog(value = "手动同步全部", module = "企业微信同步") + @PostMapping("/sync/all") + public Result syncAll() { +@@ -47,7 +56,13 @@ public class WechatSyncController { + return Result.success(); + } + +- @ApiOperation("查询企业微信用户(分页+搜索)") ++ @ApiOperation(value = "查询企业微信用户(分页+搜索)", notes = "分页查询已同步的企业微信用户列表。" ++ + "支持按姓名/手机号/职位关键词搜索,按部门ID和状态筛选。" ++ + "status取值:1=已激活 2=已禁用 4=未关注。" ++ + "用于管理员绑定企微账号时选择企微用户。" ++ + "需要管理员认证。" ++ + "\n\n**关联字典**:\n" ++ + "- wechat_user_status(企微用户状态):请求参数status和返回字段status(1=已激活, 2=已禁用, 4=未关注)") + @GetMapping("/users") + public Result> listWechatUsers( + @ApiParam("页码") @RequestParam(defaultValue = "1") Integer page, +@@ -58,21 +73,29 @@ public class WechatSyncController { + return Result.success(wechatSyncService.listWechatUsers(page, pageSize, keyword, deptId, status)); + } + +- @ApiOperation("部门列表(部门管理页面)") ++ @ApiOperation(value = "部门列表(部门管理页面)", ++ notes = "获取已同步的所有企业微信部门列表(平铺结构),用于部门管理页面展示。\n" ++ + "包含部门ID、名称、上级部门ID、排序等信息。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/departments") + public Result> listAllDepartments() { + List departments = wechatSyncService.listAllDepartments(); + return Result.success(departments); + } + +- @ApiOperation("部门树(下拉筛选)") ++ @ApiOperation(value = "部门树(下拉筛选)", notes = "以树形结构返回企业微信部门数据。" ++ + "用于部门筛选下拉框,每个节点包含id/label/children。" ++ + "需要管理员认证。") + @GetMapping("/departments/tree") + public Result>> listDepartmentsTree() { + List> tree = wechatSyncService.listDepartmentsTree(); + return Result.success(tree); + } + +- @ApiOperation("同步状态(最后同步时间)") ++ @ApiOperation(value = "同步状态(最后同步时间)", ++ notes = "获取企业微信数据的最后同步时间和状态。\n" ++ + "返回部门和用户各自的最后同步时间,用于管理页面展示同步状态。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/sync/status") + public Result> getSyncStatus() { + Map status = wechatSyncService.getSyncStatus(); +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java +index 3dcbbb3..3bde0cd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/AdminLoginRequest.java +@@ -6,13 +6,15 @@ import lombok.Data; + import javax.validation.constraints.NotBlank; + + @Data +-@ApiModel("管理员登录请求") ++@ApiModel(value = "管理员登录请求", description = "后台管理员通过用户名+密码登录,新设备首次登录需2FA验证") + public class AdminLoginRequest { +- @ApiModelProperty(value = "用户名", required = true, example = "admin") ++ @ApiModelProperty(value = "用户名", required = true, example = "admin", ++ notes = "管理员账号的用户名,由SUPER_ADMIN创建时指定") + @NotBlank(message = "用户名不能为空") + private String username; + +- @ApiModelProperty(value = "密码", required = true, example = "Admin@2026") ++ @ApiModelProperty(value = "密码", required = true, example = "Admin@2026", ++ notes = "须包含大小写字母和数字,长度8-128位。默认密码为Admin@123456") + @NotBlank(message = "密码不能为空") + private String password; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java +index 9c59721..160c8c7 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/ContactRequest.java +@@ -9,7 +9,7 @@ import javax.validation.constraints.NotBlank; + @Data + @ApiModel("联系我们请求") + public class ContactRequest { +- @ApiModelProperty(value = "渠道类型:ABOUT=关于我们 ONLINE_CS=在线客服 PHONE=电话咨询", required = true, example = "PHONE") ++ @ApiModelProperty(value = "渠道类型,关联字典contact_channel_type:ABOUT=关于我们, ONLINE_CS=在线客服, PHONE=电话咨询", required = true, example = "PHONE") + @NotBlank(message = "渠道类型不能为空") + private String channelType; + +@@ -32,6 +32,6 @@ public class ContactRequest { + @ApiModelProperty(value = "排序号(越小越靠前)", example = "1") + private Integer sortOrder; + +- @ApiModelProperty(value = "状态:0=下线 1=上线", example = "1") ++ @ApiModelProperty(value = "状态,关联字典common_status:0=下线, 1=上线", example = "1") + private Integer status; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java +index 5d0ffe3..72f20fd 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateAdminRequest.java +@@ -7,17 +7,20 @@ import javax.validation.constraints.NotBlank; + import java.util.List; + + @Data +-@ApiModel("创建管理员请求") ++@ApiModel(value = "创建管理员请求", description = "创建后台管理员账号,默认密码Admin@123456") + public class CreateAdminRequest { +- @ApiModelProperty(value = "用户名", required = true, example = "zhangsan") ++ @ApiModelProperty(value = "用户名", required = true, example = "zhangsan", ++ notes = "全局唯一的登录用户名,创建后不可修改") + @NotBlank(message = "用户名不能为空") + private String username; + + /** 角色ID列表(多角色),兼容旧的单角色 roleId */ +- @ApiModelProperty(value = "角色ID列表(多角色)", example = "[1,2]") ++ @ApiModelProperty(value = "角色ID列表(多角色)", example = "[1,2]", ++ notes = "支持分配多个角色,管理员登录后可通过切换角色接口切换当前活跃角色") + private List roleIds; + + /** @deprecated 兼容旧接口,优先使用 roleIds */ +- @ApiModelProperty(value = "角色ID(已废弃,请使用roleIds)", example = "1") ++ @ApiModelProperty(value = "角色ID(已废弃,请使用roleIds)", example = "1", ++ notes = "兼容旧接口的单角色参数,优先使用roleIds") + private Long roleId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java +index dff93b6..5d8d05b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/CreateJobRequest.java +@@ -12,18 +12,18 @@ public class CreateJobRequest { + @NotBlank(message = "任务名称不能为空") + private String jobName; + +- @ApiModelProperty(value = "任务分组", example = "SYSTEM") ++ @ApiModelProperty(value = "任务分组,字典类型:job_group(DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步)", example = "SYSTEM") + private String jobGroup; + +- @ApiModelProperty(value = "调用目标(Bean名称.方法名)", required = true, example = "wechatSyncService.syncDepartments") ++ @ApiModelProperty(value = "调用目标(Bean名称.方法名),方法必须是无参公开方法", required = true, example = "wechatSyncService.syncDepartments") + @NotBlank(message = "调用目标不能为空") + private String invokeTarget; + +- @ApiModelProperty(value = "Cron表达式", required = true, example = "0 0 2 * * ?") ++ @ApiModelProperty(value = "Cron表达式,标准6位(秒 分 时 日 月 周)", required = true, example = "0 0 2 * * ?") + @NotBlank(message = "Cron表达式不能为空") + private String cronExpression; + +- @ApiModelProperty(value = "计划执行策略:0=默认 1=立即触发 2=触发一次 3=不触发", example = "0") ++ @ApiModelProperty(value = "计划执行策略,字典类型:job_misfire_policy(DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发)", example = "DEFAULT") + private String misfirePolicy; + + @ApiModelProperty(value = "是否允许并发执行", example = "false") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java +index cbb0455..b7b4fbb 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/FavoriteRequest.java +@@ -7,13 +7,15 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.NotNull; + + @Data +-@ApiModel("收藏请求") ++@ApiModel(value = "收藏请求", description = "添加收藏时的请求体,指定收藏的资源类型和ID") + public class FavoriteRequest { +- @ApiModelProperty(value = "收藏类型", required = true, example = "SCENIC_SPOT") ++ @ApiModelProperty(value = "收藏类型,关联字典favorite_resource_type", required = true, example = "SCENIC_SPOT", ++ notes = "可选值:SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品, EXPLORE=探索分类") + @NotBlank(message = "目标类型不能为空") + private String targetType; + +- @ApiModelProperty(value = "收藏目标ID", required = true, example = "1") ++ @ApiModelProperty(value = "收藏目标ID", required = true, example = "1", ++ notes = "对应资源的ID,如景区ID、活动ID等") + @NotNull(message = "目标ID不能为空") + private Long targetId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java +index 6a9905c..a700a4d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/FootprintRequest.java +@@ -7,13 +7,15 @@ import javax.validation.constraints.NotBlank; + import javax.validation.constraints.NotNull; + + @Data +-@ApiModel("足迹请求") ++@ApiModel(value = "足迹请求", description = "记录用户浏览足迹时的请求体") + public class FootprintRequest { +- @ApiModelProperty(value = "资源类型", required = true, example = "SCENIC_SPOT") ++ @ApiModelProperty(value = "资源类型,关联字典footprint_resource_type", required = true, example = "SCENIC_SPOT", ++ notes = "可选值:SCENIC_SPOT=景区, ACTIVITY=活动, HOTEL=酒店, PRODUCT=产品") + @NotBlank(message = "资源类型不能为空") + private String resourceType; + +- @ApiModelProperty(value = "资源ID", required = true, example = "1") ++ @ApiModelProperty(value = "资源ID", required = true, example = "1", ++ notes = "对应资源的ID,同一用户同一资源只保留最新一条足迹") + @NotNull(message = "资源ID不能为空") + private Long resourceId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java +index e8ff874..bdc2f40 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/LoginRequest.java +@@ -6,18 +6,22 @@ import lombok.Data; + import javax.validation.constraints.NotBlank; + + @Data +-@ApiModel("微信小程序登录请求") ++@ApiModel(value = "微信小程序登录请求", description = "通过wx.login获取code进行登录,首次登录自动注册") + public class LoginRequest { +- @ApiModelProperty(value = "微信登录授权码", required = true, example = "0c3NKj000...") ++ @ApiModelProperty(value = "微信登录授权码", required = true, example = "0c3NKj000...", ++ notes = "通过wx.login()获取的临时授权码,后端用此code换取openid/unionid") + @NotBlank(message = "微信code不能为空") + private String code; + +- @ApiModelProperty(value = "手机号授权码(用于获取手机号)", example = "0c3NKj000...") ++ @ApiModelProperty(value = "手机号授权码(用于获取手机号)", example = "0c3NKj000...", ++ notes = "通过getPhoneNumber按钮获取的code,后端用此code换取用户手机号并绑定") + private String phoneCode; + +- @ApiModelProperty(value = "用户头像URL", example = "https://thirdwx.qlogo.cn/xxx") ++ @ApiModelProperty(value = "用户头像URL", example = "https://thirdwx.qlogo.cn/xxx", ++ notes = "微信头像地址,首次登录时传入用于设置用户头像") + private String avatar; + +- @ApiModelProperty(value = "用户昵称", example = "微信用户") ++ @ApiModelProperty(value = "用户昵称", example = "微信用户", ++ notes = "微信昵称,首次登录时传入用于设置用户昵称") + private String nickname; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java +index 48d700d..945424d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/SwitchRoleRequest.java +@@ -7,10 +7,11 @@ import lombok.Data; + import javax.validation.constraints.NotNull; + + @Data +-@ApiModel("角色切换请求") ++@ApiModel(value = "角色切换请求", description = "多角色管理员切换当前活跃角色") + public class SwitchRoleRequest { + + @NotNull(message = "角色ID不能为空") +- @ApiModelProperty(value = "目标角色ID", required = true) ++ @ApiModelProperty(value = "目标角色ID", required = true, ++ notes = "只能切换到当前管理员已分配的角色,切换后返回新Token和对应菜单权限") + private Long roleId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java +index f8d33c8..1c67bb6 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/TravelerRequest.java +@@ -15,10 +15,10 @@ public class TravelerRequest { + @Size(max = 50, message = "姓名长度不能超过50个字符") + private String name; + +- @ApiModelProperty(value = "出行人类型(无需传入,后端根据出生日期自动判断)", hidden = true) ++ @ApiModelProperty(value = "出行人类型,关联字典traveler_type:ADULT=成人, CHILD=儿童, INFANT=婴儿(无需传入,后端根据birthday自动判断)", hidden = true) + private String travelerType; // auto-resolved from birthday + +- @ApiModelProperty(value = "证件类型:ID_CARD=身份证 PASSPORT=护照", example = "ID_CARD") ++ @ApiModelProperty(value = "证件类型,关联字典id_card_type:ID_CARD=身份证, PASSPORT=护照", example = "ID_CARD") + private String idCardType; // Default: ID_CARD + + @ApiModelProperty(value = "证件号码", example = "110101199001011234") +@@ -29,7 +29,7 @@ public class TravelerRequest { + @Size(max = 20, message = "手机号长度不能超过20个字符") + private String phone; + +- @ApiModelProperty(value = "性别:0=女 1=男", example = "1") ++ @ApiModelProperty(value = "性别,关联字典gender:0=女, 1=男", example = "1") + private Integer gender; // 0=female, 1=male + + @ApiModelProperty(value = "出生日期(必填,后端根据此字段自动判断人员类型)", required = true, example = "1990-01-01") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java +index 273a9bc..1e4c1f4 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateAvatarRequest.java +@@ -7,13 +7,15 @@ import lombok.Data; + import javax.validation.constraints.NotBlank; + + @Data +-@ApiModel("头像更新请求") ++@ApiModel(value = "头像更新请求", description = "更新管理员头像,需先通过文件服务上传图片") + public class UpdateAvatarRequest { + + @NotBlank(message = "头像URL不能为空") +- @ApiModelProperty(value = "头像URL", required = true) ++ @ApiModelProperty(value = "头像URL", required = true, ++ notes = "文件服务返回的OSS URL地址") + private String avatar; + +- @ApiModelProperty("文件ID") ++ @ApiModelProperty(value = "文件ID", ++ notes = "文件服务返回的fileId,用于建立文件引用关系,传入后旧头像引用自动解绑") + private Long fileId; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java +index a42399c..4e85a2a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/dto/UpdateJobRequest.java +@@ -10,16 +10,16 @@ public class UpdateJobRequest { + @ApiModelProperty(value = "任务名称", example = "同步企微通讯录") + private String jobName; + +- @ApiModelProperty(value = "任务分组", example = "SYSTEM") ++ @ApiModelProperty(value = "任务分组,字典类型:job_group(DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步)", example = "SYSTEM") + private String jobGroup; + +- @ApiModelProperty(value = "调用目标(Bean名称.方法名)", example = "wechatSyncService.syncDepartments") ++ @ApiModelProperty(value = "调用目标(Bean名称.方法名),方法必须是无参公开方法", example = "wechatSyncService.syncDepartments") + private String invokeTarget; + +- @ApiModelProperty(value = "Cron表达式", example = "0 0 2 * * ?") ++ @ApiModelProperty(value = "Cron表达式,标准6位(秒 分 时 日 月 周)", example = "0 0 2 * * ?") + private String cronExpression; + +- @ApiModelProperty(value = "计划执行策略:0=默认 1=立即触发 2=触发一次 3=不触发", example = "0") ++ @ApiModelProperty(value = "计划执行策略,字典类型:job_misfire_policy(DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发)", example = "DEFAULT") + private String misfirePolicy; + + @ApiModelProperty(value = "是否允许并发执行", example = "false") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java b/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java +index d2b7b8d..aa20c4b 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/controller/AdminNotificationController.java +@@ -45,7 +45,10 @@ public class AdminNotificationController { + + // ==================== 事件配置 ==================== + +- @ApiOperation("获取通知配置列表(按分类分组)") ++ @ApiOperation(value = "获取通知配置列表(按分类分组)", notes = "获取所有通知事件配置,按消息分类(categoryCode)分组返回。" ++ + "每个事件配置包含各通知渠道的开关状态(smsEnabled/inappEnabled/weworkEnabled等)。" ++ + "\n\n**关联字典**:\n" ++ + "- notification_channel(通知渠道):sms=短信, inapp=站内信, wework=企业微信, miniapp_subscribe=小程序订阅消息, official_account=公众号模板消息\n") + @GetMapping("/config") + public Result>> listConfigs() { + Map> grouped = configService.listGroupedByCategory(); +@@ -66,7 +69,9 @@ public class AdminNotificationController { + return Result.success(result); + } + +- @ApiOperation("切换通道开关") ++ @ApiOperation(value = "切换通道开关", notes = "切换指定通知事件的某个渠道开关。" ++ + "channel取值:sms/inapp/wework/miniapp_subscribe/official_account。" ++ + "注意:只允许开启渠道,不建议关闭已有渠道。") + @PutMapping("/config/{id}/toggle") + public Result toggleChannel(@PathVariable Long id, + @Valid @RequestBody ChannelToggleRequest request) { +@@ -74,7 +79,10 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("编辑事件配置详情") ++ @ApiOperation(value = "编辑事件配置详情", ++ notes = "更新指定通知事件配置的详细信息,包括模板内容、接收人规则等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:修改模板内容后会立即影响后续的通知发送。") + @PutMapping("/config/{id}") + public Result updateConfig(@PathVariable Long id, + @Valid @RequestBody EventConfigUpdateRequest request) { +@@ -84,7 +92,11 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("测试发送") ++ @ApiOperation(value = "测试发送", ++ notes = "使用测试数据触发一次通知发送,验证通知配置是否正确。\n" ++ + "会使用预设的测试参数(订单号、产品名等)填充模板。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:需指定 testUserId 或 testAdminId 作为接收人,发送结果可在发送日志中查看。") + @PostMapping("/config/{id}/test") + public Result testSend(@PathVariable Long id, + @Valid @RequestBody TestSendRequest request) { +@@ -125,7 +137,10 @@ public class AdminNotificationController { + + // ==================== 消息分类 ==================== + +- @ApiOperation("获取消息分类列表") ++ @ApiOperation(value = "获取消息分类列表", ++ notes = "获取所有通知消息分类,包括分类编码、名称、图标、描述等。\n" ++ + "消息分类用于将通知事件归组管理(如订单消息、系统消息等)。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/categories") + public Result> listCategories() { + List categories = categoryService.listAll(); +@@ -135,7 +150,10 @@ public class AdminNotificationController { + return Result.success(voList); + } + +- @ApiOperation("创建消息分类") ++ @ApiOperation(value = "创建消息分类", ++ notes = "创建新的通知消息分类,用于归组管理通知事件。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:分类编码(code)必须唯一,创建后不可修改。") + @PostMapping("/categories") + public Result createCategory(@Valid @RequestBody CategoryRequest request) { + MessageCategory category = new MessageCategory(); +@@ -148,7 +166,10 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("更新消息分类") ++ @ApiOperation(value = "更新消息分类", ++ notes = "更新指定消息分类的名称、图标、描述、排序等信息。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:分类编码(code)不可修改。") + @PutMapping("/categories/{id}") + public Result updateCategory(@PathVariable Long id, + @Valid @RequestBody CategoryRequest request) { +@@ -161,7 +182,10 @@ public class AdminNotificationController { + return Result.success(); + } + +- @ApiOperation("删除消息分类") ++ @ApiOperation(value = "删除消息分类", ++ notes = "删除指定的消息分类。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:如果该分类下有关联的通知事件配置,需先移除关联后才能删除。") + @DeleteMapping("/categories/{id}") + public Result deleteCategory(@PathVariable Long id) { + categoryService.delete(id); +@@ -170,13 +194,18 @@ public class AdminNotificationController { + + // ==================== 发送日志 ==================== + +- @ApiOperation("查询发送日志") ++ @ApiOperation(value = "查询发送日志", notes = "分页查询通知发送日志,支持按事件编码、渠道、状态等筛选。" ++ + "\n\n**关联字典**:\n" ++ + "- notification_channel(通知渠道):返回字段channel\n" ++ + "- notification_send_status(发送状态):返回字段status(SUCCESS=成功, FAILED=失败, SKIPPED=跳过)\n") + @GetMapping("/logs") + public Result> queryLogs(LogQueryRequest request) { + return Result.success(sendLogService.queryLogs(request)); + } + +- @ApiOperation("获取发送统计") ++ @ApiOperation(value = "获取发送统计", ++ notes = "获取通知发送的统计数据,包括总发送数、成功数、失败数、各渠道发送量等。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/logs/stats") + public Result getLogStats() { + return Result.success(sendLogService.getStats()); +@@ -184,7 +213,11 @@ public class AdminNotificationController { + + // ==================== 自定义推送 ==================== + +- @ApiOperation("自定义推送") ++ @ApiOperation(value = "自定义推送", ++ notes = "向指定用户发送自定义通知消息,支持选择推送渠道和目标用户。\n" ++ + "用于运营人员手动推送活动通知、系统公告等。\n\n" ++ + "**权限**:需要管理员登录。\n" ++ + "**注意**:推送记录会记入发送日志。") + @PostMapping("/custom-push") + public Result customPush(@Valid @RequestBody CustomPushRequest request, + HttpServletRequest httpRequest) { +@@ -193,7 +226,10 @@ public class AdminNotificationController { + return Result.success(result); + } + +- @ApiOperation("搜索用户(自定义推送选择目标)") ++ @ApiOperation(value = "搜索用户(自定义推送选择目标)", ++ notes = "按关键词搜索C端用户,用于自定义推送时选择推送目标。\n" ++ + "支持按真实姓名或手机号模糊搜索,最多返回20条结果。\n\n" ++ + "**权限**:需要管理员登录。") + @GetMapping("/custom-push/users") + public Result> searchUsersForPush(@RequestParam(required = false) String keyword) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java b/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java +index 228bb27..2a3ee4f 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/dto/CustomPushRequest.java +@@ -1,5 +1,7 @@ + package com.hulalv.user.notification.dto; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + import javax.validation.constraints.NotBlank; +@@ -10,28 +12,31 @@ import java.util.List; + * 自定义推送请求 + */ + @Data ++@ApiModel("自定义推送请求") + public class CustomPushRequest { + ++ @ApiModelProperty("推送标题") + @NotBlank(message = "推送标题不能为空") + private String title; + ++ @ApiModelProperty("推送内容") + @NotBlank(message = "推送内容不能为空") + private String content; + +- /** 推送通道: INAPP, SMS, WECHAT_WORK */ ++ @ApiModelProperty("推送通道: INAPP/SMS/WECHAT_WORK") + @NotNull(message = "请选择推送通道") + private String channel; + +- /** 目标类型: ALL_USERS, SPECIFIC_USERS */ ++ @ApiModelProperty("目标类型: ALL_USERS/SPECIFIC_USERS") + @NotNull(message = "请选择目标类型") + private String targetType; + +- /** targetType=SPECIFIC_USERS时必填 */ ++ @ApiModelProperty("目标用户ID列表(目标类型为SPECIFIC_USERS时必填)") + private List userIds; + +- /** 消息分类编码,默认SYSTEM */ ++ @ApiModelProperty("消息分类编码,默认SYSTEM") + private String categoryCode; + +- /** 跳转链接(站内信时使用) */ ++ @ApiModelProperty("跳转链接(站内信时使用)") + private String link; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java +index e3cdaf2..495cb3d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/CustomPushResultVO.java +@@ -1,19 +1,22 @@ + package com.hulalv.user.notification.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + /** + * 自定义推送结果 + */ + @Data ++@ApiModel("自定义推送结果VO") + public class CustomPushResultVO { + +- /** 推送总数 */ ++ @ApiModelProperty("推送总数") + private int totalCount; + +- /** 成功数 */ ++ @ApiModelProperty("成功数") + private int successCount; + +- /** 失败数 */ ++ @ApiModelProperty("失败数") + private int failCount; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java +index 8b7e7d1..7434992 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/EventConfigVO.java +@@ -21,7 +21,7 @@ public class EventConfigVO { + @ApiModelProperty("所属分类名称") + private String categoryName; + +- @ApiModelProperty("站内信开关") ++ @ApiModelProperty("站内信开关(0=关闭, 1=开启)") + private Integer inappEnabled; + + @ApiModelProperty("站内信标题模板") +@@ -33,7 +33,7 @@ public class EventConfigVO { + @ApiModelProperty("站内信跳转路径模板") + private String inappLinkTemplate; + +- @ApiModelProperty("短信开关") ++ @ApiModelProperty("短信开关(0=关闭, 1=开启)") + private Integer smsEnabled; + + @ApiModelProperty("阿里云短信模板编号") +@@ -42,7 +42,7 @@ public class EventConfigVO { + @ApiModelProperty("短信签名") + private String smsSignName; + +- @ApiModelProperty("小程序订阅消息开关") ++ @ApiModelProperty("小程序订阅消息开关(0=关闭, 1=开启)") + private Integer miniappEnabled; + + @ApiModelProperty("微信订阅消息模板ID") +@@ -54,7 +54,7 @@ public class EventConfigVO { + @ApiModelProperty("小程序字段映射JSON") + private String miniappFieldMapping; + +- @ApiModelProperty("公众号模板消息开关") ++ @ApiModelProperty("公众号模板消息开关(0=关闭, 1=开启)") + private Integer oaEnabled; + + @ApiModelProperty("公众号模板ID") +@@ -66,10 +66,10 @@ public class EventConfigVO { + @ApiModelProperty("公众号字段映射JSON") + private String oaFieldMapping; + +- @ApiModelProperty("企微通知开关") ++ @ApiModelProperty("企微通知开关(0=关闭, 1=开启)") + private Integer weworkEnabled; + +- @ApiModelProperty("企微接收人类型") ++ @ApiModelProperty("企微接收人类型(ROLE=按角色, DEPT=按部门, SPECIFIC=指定人员)") + private String weworkReceiverType; + + @ApiModelProperty("企微消息内容模板") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java +index 8e44260..52c307c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/SendLogVO.java +@@ -14,7 +14,7 @@ public class SendLogVO { + @ApiModelProperty("事件编码") + private String eventCode; + +- @ApiModelProperty("通道: INAPP/SMS/MINIAPP/OA/WEWORK") ++ @ApiModelProperty("通道,关联字典notification_channel:INAPP=站内信, SMS=短信, MINIAPP=小程序订阅, OA=公众号模板, WEWORK=企业微信") + private String channel; + + @ApiModelProperty("用户ID") +@@ -38,7 +38,7 @@ public class SendLogVO { + @ApiModelProperty("关联业务类型") + private String bizType; + +- @ApiModelProperty("发送状态: 0成功 1失败 2跳过") ++ @ApiModelProperty("发送状态,关联字典notification_send_status:0=成功, 1=失败, 2=跳过") + private Integer status; + + @ApiModelProperty("失败原因") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java +index 448b5df..9ad4b62 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/notification/vo/UserSimpleVO.java +@@ -1,18 +1,25 @@ + package com.hulalv.user.notification.vo; + ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; + import lombok.Data; + + /** + * 用户简要信息(自定义推送选择目标用户时使用) + */ + @Data ++@ApiModel("用户简要信息VO") + public class UserSimpleVO { + ++ @ApiModelProperty("用户ID") + private Long id; + ++ @ApiModelProperty("真实姓名") + private String realName; + ++ @ApiModelProperty("手机号") + private String phone; + ++ @ApiModelProperty("头像URL") + private String avatarUrl; + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/service/SysJobService.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/service/SysJobService.java b/hl-user-service/src/main/java/com/hulalv/user/service/SysJobService.java +index a969c76..3572ae2 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/service/SysJobService.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/service/SysJobService.java +@@ -13,12 +13,17 @@ import com.hulalv.user.entity.SysJob; + import com.hulalv.user.entity.SysJobLog; + import com.hulalv.user.mapper.SysJobLogMapper; + import com.hulalv.user.mapper.SysJobMapper; ++import com.hulalv.user.vo.SysJobLogVO; ++import com.hulalv.user.vo.SysJobVO; + import lombok.RequiredArgsConstructor; + import lombok.extern.slf4j.Slf4j; + import org.quartz.*; ++import org.springframework.beans.BeanUtils; + import org.springframework.stereotype.Service; + import org.springframework.transaction.annotation.Transactional; + ++import java.util.stream.Collectors; ++ + @Slf4j + @Service + @RequiredArgsConstructor +@@ -28,7 +33,7 @@ public class SysJobService extends ServiceImpl { + private final Scheduler scheduler; + + @Transactional +- public SysJob createJob(CreateJobRequest request) { ++ public SysJobVO createJob(CreateJobRequest request) { + SysJob job = new SysJob(); + job.setJobName(request.getJobName()); + job.setJobGroup(request.getJobGroup() != null ? request.getJobGroup() : "DEFAULT"); +@@ -41,11 +46,11 @@ public class SysJobService extends ServiceImpl { + save(job); + + log.info("Job created: name={}, target={}", job.getJobName(), job.getInvokeTarget()); +- return job; ++ return toVO(job); + } + + @Transactional +- public SysJob updateJob(Long jobId, UpdateJobRequest request) { ++ public SysJobVO updateJob(Long jobId, UpdateJobRequest request) { + SysJob job = getById(jobId); + if (job == null) { + throw new NotFoundException("定时任务不存在"); +@@ -68,7 +73,7 @@ public class SysJobService extends ServiceImpl { + createSchedulerJob(job); + } + +- return job; ++ return toVO(job); + } + + @Transactional +@@ -136,23 +141,27 @@ public class SysJobService extends ServiceImpl { + } + } + +- public PageResult listJobs(int page, int pageSize) { ++ public PageResult listJobs(int page, int pageSize) { + Page pageParam = PageUtil.safePage(page, pageSize); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .orderByDesc(SysJob::getCreatedAt) + .orderByDesc(SysJob::getJobId); + Page result = page(pageParam, wrapper); +- return PageResult.of(result.getRecords(), result.getTotal(), page, pageSize); ++ return PageResult.of( ++ result.getRecords().stream().map(this::toVO).collect(Collectors.toList()), ++ result.getTotal(), page, pageSize); + } + +- public PageResult listJobLogs(Long jobId, int page, int pageSize) { ++ public PageResult listJobLogs(Long jobId, int page, int pageSize) { + Page pageParam = PageUtil.safePage(page, pageSize); + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(SysJobLog::getJobId, jobId) + .orderByDesc(SysJobLog::getStartTime) + .orderByDesc(SysJobLog::getJobLogId); + Page result = jobLogMapper.selectPage(pageParam, wrapper); +- return PageResult.of(result.getRecords(), result.getTotal(), page, pageSize); ++ return PageResult.of( ++ result.getRecords().stream().map(this::toLogVO).collect(Collectors.toList()), ++ result.getTotal(), page, pageSize); + } + + void createSchedulerJob(SysJob job) { +@@ -199,4 +208,16 @@ public class SysJobService extends ServiceImpl { + log.error("Failed to remove scheduler job: jobId={}", job.getJobId(), e); + } + } ++ ++ private SysJobVO toVO(SysJob job) { ++ SysJobVO vo = new SysJobVO(); ++ BeanUtils.copyProperties(job, vo); ++ return vo; ++ } ++ ++ private SysJobLogVO toLogVO(SysJobLog jobLog) { ++ SysJobLogVO vo = new SysJobLogVO(); ++ BeanUtils.copyProperties(jobLog, vo); ++ return vo; ++ } + } +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java +index 8bd3d9d..53a203c 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/ContactVO.java +@@ -14,7 +14,7 @@ public class ContactVO { + @ApiModelProperty(value = "联系方式ID") + private String id; + +- @ApiModelProperty(value = "渠道类型:ABOUT=关于我们 ONLINE_CS=在线客服 PHONE=电话咨询") ++ @ApiModelProperty(value = "渠道类型,关联字典contact_channel_type:ABOUT=关于我们, ONLINE_CS=在线客服, PHONE=电话咨询") + private String channelType; + + @ApiModelProperty(value = "标题") +@@ -35,7 +35,7 @@ public class ContactVO { + @ApiModelProperty(value = "排序号") + private Integer sortOrder; + +- @ApiModelProperty(value = "状态:0=下线 1=上线") ++ @ApiModelProperty(value = "状态,关联字典common_status:0=下线, 1=上线") + private Integer status; + + @ApiModelProperty(value = "创建时间") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java +index d72a7b3..be9f83a 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/CustomerVO.java +@@ -26,7 +26,7 @@ public class CustomerVO { + @ApiModelProperty(value = "手机号(不脱敏)") + private String phone; + +- @ApiModelProperty(value = "状态:ACTIVE=正常 DISABLED=禁用") ++ @ApiModelProperty(value = "状态,关联字典user_status:ACTIVE=正常, BANNED=已封禁") + private String status; + + @ApiModelProperty(value = "创建时间") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java +index 89620fe..3582c3d 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/LoginLogVO.java +@@ -18,7 +18,7 @@ public class LoginLogVO { + @ApiModelProperty(value = "管理员名称") + private String adminName; + +- @ApiModelProperty(value = "登录方式:PASSWORD=密码 WECHAT=企微扫码 TWO_FA=二次验证") ++ @ApiModelProperty(value = "登录方式,关联字典login_method:PASSWORD=密码登录, WECHAT_QR=企微扫码登录, TWO_FA=二次验证登录") + private String loginMethod; + + @ApiModelProperty(value = "登录IP地址") +@@ -36,7 +36,7 @@ public class LoginLogVO { + @ApiModelProperty(value = "登录地区") + private String location; + +- @ApiModelProperty(value = "登录状态:SUCCESS=成功 FAILED=失败") ++ @ApiModelProperty(value = "登录状态,关联字典login_status:SUCCESS=成功, FAILED=失败") + private String status; + + @ApiModelProperty(value = "失败原因") +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/SysJobLogVO.java` (A) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/SysJobLogVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/SysJobLogVO.java +new file mode 100644 +index 0000000..3f031c1 +--- /dev/null ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/SysJobLogVO.java +@@ -0,0 +1,37 @@ ++package com.hulalv.user.vo; ++ ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; ++import lombok.Data; ++import java.time.LocalDateTime; ++ ++@Data ++@ApiModel("定时任务执行日志") ++public class SysJobLogVO { ++ @ApiModelProperty("日志ID") ++ private Long jobLogId; ++ ++ @ApiModelProperty("任务ID") ++ private Long jobId; ++ ++ @ApiModelProperty("任务名称") ++ private String jobName; ++ ++ @ApiModelProperty("调用目标") ++ private String invokeTarget; ++ ++ @ApiModelProperty(value = "执行状态", notes = "字典类型:job_log_status。可选值:SUCCESS=成功, FAIL=失败") ++ private String status; ++ ++ @ApiModelProperty("执行结果/异常信息") ++ private String message; ++ ++ @ApiModelProperty("开始时间") ++ private LocalDateTime startTime; ++ ++ @ApiModelProperty("结束时间") ++ private LocalDateTime endTime; ++ ++ @ApiModelProperty("创建时间") ++ private LocalDateTime createdAt; ++} +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/SysJobVO.java` (A) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/SysJobVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/SysJobVO.java +new file mode 100644 +index 0000000..1e84456 +--- /dev/null ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/SysJobVO.java +@@ -0,0 +1,43 @@ ++package com.hulalv.user.vo; ++ ++import io.swagger.annotations.ApiModel; ++import io.swagger.annotations.ApiModelProperty; ++import lombok.Data; ++import java.time.LocalDateTime; ++ ++@Data ++@ApiModel("定时任务信息") ++public class SysJobVO { ++ @ApiModelProperty("任务ID") ++ private Long jobId; ++ ++ @ApiModelProperty("任务名称") ++ private String jobName; ++ ++ @ApiModelProperty(value = "任务分组", notes = "字典类型:job_group。可选值:DEFAULT=默认分组, SYSTEM=系统任务, WECHAT=企微同步, INSURANCE=保险同步") ++ private String jobGroup; ++ ++ @ApiModelProperty("调用目标(Bean名称.方法名)") ++ private String invokeTarget; ++ ++ @ApiModelProperty("Cron表达式") ++ private String cronExpression; ++ ++ @ApiModelProperty(value = "计划执行策略", notes = "字典类型:job_misfire_policy。可选值:DEFAULT=默认策略, FIRE_ONCE=立即触发一次, DO_NOTHING=不触发") ++ private String misfirePolicy; ++ ++ @ApiModelProperty("是否允许并发执行") ++ private Boolean concurrent; ++ ++ @ApiModelProperty(value = "任务状态", notes = "字典类型:job_status。可选值:ACTIVE=启用, PAUSED=已暂停") ++ private String status; ++ ++ @ApiModelProperty("备注") ++ private String remark; ++ ++ @ApiModelProperty("创建时间") ++ private LocalDateTime createdAt; ++ ++ @ApiModelProperty("更新时间") ++ private LocalDateTime updatedAt; ++} +``` + +### `hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java` (M) + +```diff +diff --git a/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java b/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java +index cb64d33..bbc0ede 100644 +--- a/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java ++++ b/hl-user-service/src/main/java/com/hulalv/user/vo/UserVO.java +@@ -29,20 +29,20 @@ public class UserVO { + @ApiModelProperty(value = "真实手机号(仅内部接口返回,用于订单预填)", hidden = true) + private String rawPhone; // 真实手机号(仅内部接口返回,用于订单预填) + +- @ApiModelProperty(value = "状态:ACTIVE=正常 DISABLED=禁用") ++ @ApiModelProperty(value = "状态,关联字典user_status:ACTIVE=正常, BANNED=已封禁") + private String status; + + // 个人信息字段(用于编辑"本人"出行人信息) + @ApiModelProperty(value = "真实姓名") + private String realName; + +- @ApiModelProperty(value = "证件类型:ID_CARD=身份证 PASSPORT=护照") ++ @ApiModelProperty(value = "证件类型,关联字典id_card_type:ID_CARD=身份证, PASSPORT=护照") + private String idCardType; + + @ApiModelProperty(value = "证件号码") + private String idCardNo; + +- @ApiModelProperty(value = "性别:0=女 1=男") ++ @ApiModelProperty(value = "性别,关联字典gender:0=女, 1=男") + private Integer gender; + + @ApiModelProperty(value = "出生日期") +``` + +### `hl-user-service/src/test/java/com/hulalv/user/service/SysJobServiceTest.java` (M) + +```diff +diff --git a/hl-user-service/src/test/java/com/hulalv/user/service/SysJobServiceTest.java b/hl-user-service/src/test/java/com/hulalv/user/service/SysJobServiceTest.java +index 64d284e..853dcd1 100644 +--- a/hl-user-service/src/test/java/com/hulalv/user/service/SysJobServiceTest.java ++++ b/hl-user-service/src/test/java/com/hulalv/user/service/SysJobServiceTest.java +@@ -10,6 +10,8 @@ import com.hulalv.user.dto.UpdateJobRequest; + import com.hulalv.user.entity.SysJob; + import com.hulalv.user.entity.SysJobLog; + import com.hulalv.user.mapper.SysJobLogMapper; ++import com.hulalv.user.vo.SysJobLogVO; ++import com.hulalv.user.vo.SysJobVO; + import org.junit.jupiter.api.BeforeEach; + import org.junit.jupiter.api.Test; + import org.junit.jupiter.api.extension.ExtendWith; +@@ -60,7 +62,7 @@ class SysJobServiceTest { + + doReturn(true).when(sysJobService).save(any(SysJob.class)); + +- SysJob result = sysJobService.createJob(request); ++ SysJobVO result = sysJobService.createJob(request); + + assertNotNull(result); + assertEquals("新任务", result.getJobName()); +@@ -82,7 +84,7 @@ class SysJobServiceTest { + + doReturn(true).when(sysJobService).save(any(SysJob.class)); + +- SysJob result = sysJobService.createJob(request); ++ SysJobVO result = sysJobService.createJob(request); + + assertEquals("SYSTEM", result.getJobGroup()); + assertEquals("FIRE_ONCE", result.getMisfirePolicy()); +@@ -99,7 +101,7 @@ class SysJobServiceTest { + doReturn(testJob).when(sysJobService).getById(3001L); + doReturn(true).when(sysJobService).updateById(any(SysJob.class)); + +- SysJob result = sysJobService.updateJob(3001L, request); ++ SysJobVO result = sysJobService.updateJob(3001L, request); + + assertEquals("更新任务名", result.getJobName()); + assertEquals("0 0/10 * * * ?", result.getCronExpression()); +@@ -121,7 +123,7 @@ class SysJobServiceTest { + when(scheduler.deleteJob(jobKey)).thenReturn(true); + when(scheduler.scheduleJob(any(JobDetail.class), any(Trigger.class))).thenReturn(null); + +- SysJob result = sysJobService.updateJob(3001L, request); ++ SysJobVO result = sysJobService.updateJob(3001L, request); + + assertNotNull(result); + verify(scheduler).deleteJob(jobKey); +@@ -248,10 +250,11 @@ class SysJobServiceTest { + + doReturn(mockPage).when(sysJobService).page(any(Page.class), any()); + +- PageResult result = sysJobService.listJobs(1, 10); ++ PageResult result = sysJobService.listJobs(1, 10); + + assertNotNull(result); + assertEquals(1, result.getRecords().size()); ++ assertInstanceOf(SysJobVO.class, result.getRecords().get(0)); + } + + @Test +@@ -268,9 +271,10 @@ class SysJobServiceTest { + when(jobLogMapper.selectPage(any(Page.class), any(LambdaQueryWrapper.class))) + .thenReturn(mockPage); + +- PageResult result = sysJobService.listJobLogs(3001L, 1, 10); ++ PageResult result = sysJobService.listJobLogs(3001L, 1, 10); + + assertNotNull(result); + assertEquals(1, result.getRecords().size()); ++ assertInstanceOf(SysJobLogVO.class, result.getRecords().get(0)); + } + } +``` +