主题
携岛 XieDao —— 项目架构全景(按业务功能模块)
本文档基于对代码库的全面探索整理而成,覆盖 4 个端 + 后端的 8 大业务域。最后更新:2026-07-06。 探索方法:通过 codegraph 索引(2544 文件 / 36028 节点 / 72840 边)+ 并行 subagent 深入各业务域。
目录
- 项目总览
- 模块 1️⃣ 订单 + 支付 + 退款 + 对账
- 模块 2️⃣ 商户体系 + 商品/产品/套餐 + 商城
- 模块 3️⃣ 履约服务类商品
- 模块 4️⃣ 用户 + 社交 + 钱包
- 模块 5️⃣ 笔记社区 + 旅游攻略 + IM
- 模块 6️⃣ 拼团 + 团购 + 营销活动
- 模块 7️⃣ 优惠券 + 新人礼包 + 推广分销
- 模块 8️⃣ 基础数据 + 通知 + 监控
- 模块间核心数据流
- 关键技术债与风险清单
- 关键技术栈速查
项目总览
携岛 XieDao 是基于 RuoYi-Vue 3.9.1 二次开发的海南旅游生活服务平台,覆盖"平台 + 商户 + 用户"三端 O2O 旅游电商(含酒店/租车/接送/摄影/定制游/笔记社区/商城/钱包/IM/微信支付分账)。域名 api.xiedao888.cn,WSL 工作目录为 /home/ubuntu/projects/xiedao。
端构成
| 端 | 路径 | 技术栈 | 用途 |
|---|---|---|---|
| 后端 | Api/ | Java 21 + Spring Boot 3.5.8 + MyBatis + 微信支付V3 | API 中枢 |
| 平台后台 | AdminWeb/ | Vue3 + Element Plus + Pinia + Vite 6 | 平台运营管理 |
| 商家 Web | MerchantWeb/ | 同上(RuoYi-Vue) | 商家 PC 管理 |
| 用户小程序 | App/ | 原生小程序 + glass-easel + tdesign | C 端用户 |
| 商家小程序 | MerchantApp/ | 原生小程序 + OpenIM | 商家移动办公 |
后端 URL 前缀约定
| 包 | URL 前缀 | 消费端 |
|---|---|---|
controller/app/ | /api/app/** | WeChat 小程序(用户) |
controller/merchant/ | /api/merchant/** | 商家 App |
controller/platform/ | /api/admin/** | AdminWeb 仪表盘 |
controller/system/、monitor/ | /system/**、/monitor/** | RuoYi 原生系统管理 |
后端 Maven 模块结构
ruoyi-admin Web 入口 + 全部 Controller(可执行 jar)
ruoyi-framework Spring Security/JWT/AOP/数据源路由
ruoyi-system 业务 domain + service + MyBatis mapper(业务核心)
ruoyi-common 通用工具/注解/常量
ruoyi-quartz 定时任务(微信支付查单/关单/退款同步/分账)
ruoyi-generator 代码生成器Controller 三端分布(共 107+ 个)
| 包 | 数量 | 主要内容 |
|---|---|---|
controller/app/ | 33 | 用户端:登录/酒店/租车/摄影/商城/拼团/笔记/钱包/IM/支付/PayScore |
controller/merchant/ | 26 | 商家端:登录/商品/订单/调度/核销/财务/提现/司机/IM |
controller/platform/ | 48 | 平台端:Admin*(CRUD)+ Xd*(业务实体管理) |
模块 1️⃣ 订单 + 支付 + 退款 + 对账(核心交易枢纽)
这是整个项目最核心、最复杂的子系统。代码主要分布在:
Api/ruoyi-system/src/main/java/com/xiedao/system/domain/— 实体Api/ruoyi-system/src/main/java/com/xiedao/system/service/{order,payment}/— 状态机与编排Api/ruoyi-system/src/main/java/com/xiedao/system/service/order/handler/— 9 种业务类型 HandlerApi/ruoyi-admin/src/main/java/com/xiedao/web/controller/{app,merchant,platform}/— 三端 ControllerApi/ruoyi-quartz/+Api/ruoyi-admin/.../web/task/— 定时任务
1.1 订单领域
| 实体 | 表 | 职责 |
|---|---|---|
XdOrder | xl_order | 瘦交易头:orderNo/userId/merchantId/activityType/各种分金额/状态字段/parentOrderNo(合单父单号) |
XdOrderItem | xl_order_item | 明细:unitPriceFen/paymentFeeFen/merchantIncomeFen/commissionRate/snapshotJson |
XdOrderEvent | xl_order_event | 状态变更审计日志(fromStatus/toStatus/operator/bizId) |
XdOrderVoucher | xl_order_voucher | 券码(12位)+ 状态(0未用/1已核销/4已预约)+validStart/End+verifyTime |
状态枚举与状态机
OrderStateMachine(唯一入口,乐观并发条件 UPDATE ... WHERE status=from + 0 行幂等检查):
markPaidPENDING_PAY→PAID(写 payTime + 发布OrderPaidEvent)cancelPendingOrderPENDING_PAY→CANCELLEDcompletePAID→COMPLETEDstartRefundPAID|COMPLETED→REFUNDING(多前置)markRefundedREFUNDING→REFUNDEDrestoreAfterRefundFailedREFUNDING→原状态
OrderSettlementStateMachine:NONE→PENDING_SETTLE→AVAILABLE→DEDUCTED
每次迁移都写一条 xl_order_event 审计日志。
创建编排(解耦多业务类型)
OrderOrchestrator.createOrder(OrderCreateContext):
OrderTypeHandlerRegistry.getRequired(activityType)取对应 Handlerhandler.buildOrderDraft(ctx)产出OrderDraft(order + items)- 金额汇总由 Orchestrator 自算(不信任请求传入)
- 写
xl_order+ 批量插xl_order_item,status=PENDING_PAY
订单号前缀(区分业务类型):
PH房 /CR车 /IR物品 /TF接送 /RM房型 /PK套餐 /ML商城 /OD团购- 预支付用
PAY_前缀作微信out_trade_no(修复了历史 OD_ 前缀的查单 bug)
OrderTypeHandler SPI(9 个实现,service/order/handler/): buildOrderDraft / onPaid / onCompleted / onCancelled / onRefunded / settlementPolicy()。 SettlementPolicy.plusDays(n) 工厂提供 T+N 可提现时效。 OrderPaidEventListener(@TransactionalEventListener AFTER_COMMIT) 异步调 handler.onPaid(ctx)。
合单(伪合单)概念
重要:服务商合单支付模式 + 特约商户号分账已在"阶段八"清理。当前为"伪合单"模型。
- 「子单 = 一笔
xl_order」,「合单 = 共享同一parentOrderNo的多笔订单」 XdOrder.parentOrderNo写入;多笔子单payAmountFen汇总发起一笔 JSAPI- 支付回调按父单号批量标记子单 PAID;券/钱包/券核销在子单粒度逐笔处理
1.2 支付领域
| 实体 | 表 | 职责 |
|---|---|---|
XdPaymentRecord | xl_payment_record | 支付主单:payNo/totalAmountFen/wechatAmountFen/walletAmountFen/status(PENDING/SUCCESS/CLOSED/REFUNDING/REFUNDED)/expireTime/version |
XdPaymentOrderRel | — | 支付主单↔订单 N:N 关系表(含微信/钱包分摊金额) |
两套配置(重要澄清)
| 配置类 | 当前状态 | 说明 |
|---|---|---|
PlatformWechatPayConfig | 唯一启用 | 平台直连商户号 V3,构建 RSAPublicKeyConfig/RefundService/NotificationParser 等官方 SDK Bean。@PostConstruct 强校验缺失即抛异常 |
WechatPayConfig(服务商 SP) | 已删除 | "阶段八"清理。无同名 Java 文件残留 |
WechatPayScoreConfig | 独立 | 微信支付分押金配置,含 mockMode 开关 |
PaymentOrchestrator
createPayment(orderIds, userId, openid)— 合并支付:写 payment_record + order_rel,调prepayJsapiByPaymentapplyPaymentSuccess(paymentId, transactionId, paidTime)— 幂等推进支付主单→SUCCESS → 调OrderStateMachine.markPaidclosePayment(paymentId, reason)— 关单;若微信返回 ORDERPAID 转调applyPaymentSuccess补偿refundOrder(orderId, reason)— 整单退款:按渠道独立跟踪wechat_refund_status / wallet_refund_status
IPlatformWechatPayService 关键方法
prepayJsapi/prepayTransferOrder/jsapiPrepayDeposit/nativePrepay/prepayJsapiByPaymentqueryByOutTradeNo/queryByTransactionId/closeOrderrefundDeposit/refundByPayNo/queryRefundByOutRefundNodownloadTradeBill/parsePayNotify/parseRefundNotify
dev_ 前缀 openid 走 mock 旁路。
支付相关 Controller
AppPayController/api/app/pay:prepay / confirm / status / notify / refund-notifyPayScoreNotifyController/api/pay-score:⚠️ 未验签、未 AES 解密、TODO 待实现
1.3 退款体系
XdRefundRecord (xl_refund_record) 关键字段:
- paymentId(新流程关联支付主单)/ sourceOrderStatus(退款前订单快照,用于失败回滚)
- wechatRefundStatus + walletRefundStatus 双渠道独立跟踪
- refundType:user_apply / appointment_cancel / pintuan_penalty / user_cancel 等
- status:PENDING/PROCESSING/SUCCESS/FAILED/PARTIAL_REFUNDED
- wxRefundId/wxStatus(PROCESSING/SUCCESS/CLOSED/ABNORMAL) + lastErrorCode/Error
关键方法(XdOrderServiceImpl):
applyRefund(userId, orderId, reason)— 用户申请auditMerchantRefund(merchantId, ...)— 商户审批入口auditRefund(refundId, status, ...)— 通过→调微信callWechatRefund;拒绝→restoreAfterRefundFailedhandleRefundCallback(RefundCallbackData)— 微信回调:SUCCESS 回填+推进 order→REFUNDED;CLOSED→回滚;ABNORMAL→人工介入- 故意不做 Java 短路幂等,让 SQL
WHERE wx_status != 'SUCCESS'兜底并支持自愈
拼团退款三分支:未成团全退(user_cancel) / 免费窗口全退 / 超窗扣手续费(pintuan_penalty 按 XdPintuanCategoryConfig.penaltyRate,含商户钱包扣减)
1.4 个体结算(替代微信分账)
散客"分账"概念已物理摘除:不再调用微信分账接口、不再用特约商户号,改用"商家转账到零钱"做个体(司机/摄影师)结算。
XdIndividualSettlement (xl_individual_settlement) 字段:settleDate/orderId/orderType(transfer/photography)/workerId/openid/openidAppid/amountFen/outBatchNo/outDetailNo/wxBatchId/wxDetailId/status(PENDING/PROCESSING/SUCCESS/FAILED/NO_OPENID)/failReason/retryCount。
IndividualSettlementService(走微信 /v3/transfer/batches):
runDailySettlement(T-1)扫已完成 → 幂等去重插入 →submitBatch(按 openidAppid 分组,姓名 PrivacyEncryptor 加密)pollBatchResults查批次状态manualRetry(settlementId)—retryCount < 3才重试
ICommissionCalculator 仅剩 SPI 扩展点,无默认实现且无任何调用方(分账逻辑已物理删除,平台佣金以"支付回调写入 XdOrderItem.merchantIncomeFen"方式完成)。
1.5 对账与发货同步
XdBillReconciliation (xl_bill_reconciliation):billDate/orderNo/transactionId/wxAmount/localAmount/diffAmount/status(matched/diff/missing/wx_missing)。 WechatBillReconcileTask(每天 10:30):下载 T-1 账单 → 解析 CSV → 比对 xl_order.payAmountFen → 写对账记录。
XdWxShipSync (xl_wx_ship_sync):orderId/orderNo/wxTransactionId/logisticsCompany/logisticsNo/status(PENDING/SUCCESS/FAILED/GIVEUP/SKIPPED)/retryCount/maxRetry。 MallShipSyncTask(每 5min):批量调 WxShippingApiService.uploadShippingInfo,参数错误→GIVEUP 人工介入,否则 markFailed,retryCount >= 5 → GIVEUP。
1.6 定时任务(兜底一致性)
| Job | 类型 | 频率 | 职责 |
|---|---|---|---|
PaymentExpireTask | Quartz | 30 秒 | 支付单过期关单 |
PayQueryTask | @Scheduled | 2 分钟 | 支付查单兜底,SUCCESS 补偿 |
RefundSyncTask | Quartz | 5 分钟 | 退款状态同步 |
RefundStateSyncTask | @Scheduled | 5 分钟 | 退款状态同步(两份近似实现⚠️) |
MallShipSyncTask | Quartz | 5 分钟 | 微信「发货信息管理」同步 |
MallAutoConfirmTask | Quartz | 每天 02:00 | 商城发货超 15 天自动确认收货 |
WechatBillReconcileTask | @Scheduled | 每天 10:30 | 下载 T-1 账单对账 |
IndividualSettlementTask | @Scheduled | 02:00 + 03:00 | 个体结算批次生成 + 查询 |
MerchantWalletSettlementTask | @Scheduled | 每天 01:00 | 商户钱包结算与分成入账(含专车司机/摄影师) |
RentalOverdueTask | Quartz | — | 租赁超期处理 |
XdVoucherExpireTask | — | — | 券码过期处理 |
1.7 关键 Controller
用户端 AppOrderController /api/app/orders
- POST /groupbuy, /pintuan, /package, /package/preview, /room, /mall —— 各类下单
- GET /list, /{orderNo} —— 列表/详情
- POST /{id}/cancel, /{id}/refund —— 取消/退款
- POST /api/app/hotel/appointments, /api/app/hotel/appointments/{id}/cancel —— 酒店预约
- POST /{id}/confirm-receive, GET /{orderNo}/logistics —— 商城收货/物流
商户端 MerchantOrderController /api/merchant/orders
- GET /list, /{id}, POST /{id}/verify, /vouchers/lookup, /verify-batch, PUT /{id}/refund(审批)
平台端 AdminOrderController /api/admin/orders
- GET /list, /{id}, /refund/list, PUT /refund/audit, GET /{orderId}/combine-detail, POST /voucher/verify
模块 2️⃣ 商户体系 + 商品/产品/套餐 + 商城
2.1 商户体系
XdMerchant (xl_merchant) 核心字段
- 标识:id/entryType(personal/merchant)/phone(唯一)/password(BCrypt)/openId
- 分类:businessType(locallife/hotel/mall/delivery) + categoryId + categoryCode(决定菜单/佣金费率/所需资料严苛度)
- 状态/审核:status
1待平台审核 / 2平台审核驳回 / 3待支付 / 4正常营业 / 5关店审核中 / 6已关店 / 7禁用(枚举MerchantStatus)+ rejectReason/orderNo(M 前缀保证金)/paidAt/auditBy - 费用/佣金:entryFee/deposit/totalAmount(分) + 3 套 commission(groupbuy/pindan/activity)+ couponRatioMerchant/Platform + promotionCommissionRate + newUserReward
- 平台直连入驻资料:subjectType(INDIVIDUAL/ENTERPRISE)+全部入驻资料(legalPersonIdCard/Mobile/BankAccountNumber AES 脱敏密文)
入驻与审核流程
apply(status=1 待审) → 平台审核 XdMerchantServiceImpl.auditMerchant
├ 通过 + 金额>0 → status=3 待付保证金 → prepay(Native/jsapi) → handlePayCallback
│ → status=4 营业(同时初始化钱包 + 绑首张银行卡)
├ 通过 + 金额=0 → status=4 营业
└ 驳回 → status=2 → resubmit → 回到 1
cancel(注销)
├ 未付 → status=6 已关店
└ 已付 → status=5 关店审(CAS 抢占)+ 建退款记录 + afterCommit 调微信退款
auditCloseMerchant(approve=true→6 退保证金 / false→回滚 4)XdMerchantMenu 商家菜单系统
- 与 RuoYi SysMenu 完全独立的另一套表(
xl_merchant_menu) - 字段结构对齐 SysMenu(menuId/parentId/menuType(M目录/C菜单)/path/component)
- 按
merchantTypes字段(逗号分隔或all)控制可见商户类型 - 商户端
GET /api/merchant/getRouters下发 - 平台端
AdminMerchantMenuController/api/admin/merchantMenu维护
商家钱包体系
| 实体 | 关键字段 |
|---|---|
XdMerchantWallet (xl_merchant_wallet) | merchantId/balanceFen(可用)/frozenFen(冻结)/pendingSettleFen/totalEarnedFen/totalWithdrawnFen |
XdMerchantWalletLog (xl_merchant_wallet_log) | amountFen/balanceAfterFen/bizType(ORDER_PENDING_SETTLE/ORDER_SETTLE_AVAILABLE/ORDER_COMPLETE/REFUND_DEDUCT/WITHDRAWAL/WITHDRAWAL_REJECT/WITHDRAWAL_PAID) |
XdMerchantWithdrawal (xl_merchant_withdrawal) | withdrawalNo(W 前缀)/status(PENDING/APPROVED/PAID/REJECTED/FAILED)/bankInfo/version(乐观锁) |
钱包闭环:creditForOrder(待结算入账:冻结+pendingSettle 抬升) → unfreezeForOrder(完成时:冻结→可用,写 ORDER_COMPLETE) → deductForRefund(退款扣减,写 REFUND_DEDUCT)。所有操作幂等(by order+bizType)。
提现流程:
applyWithdrawal(balance 原子扣减 + 写 PENDING + WITHDRAWAL 流水;已有 pending 不可再申请)
→ approve(CAS PENDING→APPROVED)
→ markPaid(APPROVED→PAID + frozen 减 + totalWithdrawn 加 + 写 WITHDRAWAL_PAID)
→ 支付失败 markFailed(余额退回)
→ 驳回 reject(余额退回 + 写 WITHDRAWAL_REJECT)所有状态变更带 version 乐观锁。
2.2 双套商品体系
A. XdProduct(到店核销类)
| 关联实体 | 作用 |
|---|---|
XdProduct (xl_product) | businessType(locallife/hotel/mall/delivery) + categoryId + roomTypeId(酒店必填) + bookingMode(0团购/1原价预订) |
XdProductActivity (xl_product_activity) | 一商品可挂多个活动,activityType(groupbuy/pintuan/package);priceMode = self(抽成)/floor(平台底价+商户加价);status(0待审/1启用/2下架/3禁用) |
XdProductPriceCalendar (xl_product_price_calendar) | activityExtraFee(平台)+settlementExtraFee(商户) + stock/sold + auditStatus 嵌主表(0无需/1待/2通过/3驳回) |
XdProductNoticeConfig (JSON 结构,非 DB 表) | 购买须知项:key/label/value/inputType(daterange/timerange/richtext/text/number)/sort |
定价双轨:self(抽成比例)vs floor(平台底价 settlementPrice + 商户加价);售价 = 活动基础价 + 日历加价。 日历 auditStatus 单独审核(直接嵌主表)。
B. XdMallProduct(电商履约类)
| 实体 | 关键字段 |
|---|---|
XdMallProduct (xl_mall_product) | productType/SKU/description/brand/unit/weight/auditRemark/salesCount/isFlashSale+flashSale*(秒杀)/isSubsidized+subsidyAmount(补贴)/isLocalSpecialty(海南特产) |
XdMallSku | specData(JSON 规格)+price/originalPrice(分)+stock+skuImage+skuCode |
XdMallCart | userId+productId+skuId+quantity+selected |
XdMallAddress | province/city/district/detailAddress+isDefault |
XdProduct vs XdMallProduct 边界:
- XdProduct:服务"到店核销"业态(团购/拼团/套餐/酒店/租车/摄影/接送),绑定 ProductActivity + PriceCalendar,资金进入钱包冻结→完成结算。
- XdMallProduct:服务"实物电商履约"业态(带物流),独立 SKU/库存/秒杀/补贴/特产标记。
- 商户要经营商城需
businessType=mall。
2.3 套餐(平台主表+商户报名的众包组合)
| 实体 | 关键字段 |
|---|---|
XdPackage (xl_package) | packageName/city/packagePrice/originalPrice(分)/groupRules/duration/itinerary(行程 JSON)/packageType/sortOrder/delFlag/items(关联) |
XdPackageItem (xl_package_item) | packageId/productId/activityId/platformPrice+originalPrice/groupName/groupKey(分组)/merchantId/applyStatus(报名状态)/auditBy/auditReason/sortOrder/dayNumber(行程天数)/areaId |
XdPackagePriceCalendar (xl_package_price_calendar) | packageId/date/extraFee/stock/sold/status |
核心校验:saveItemPrices 校验 "各 platformPrice 之和 == packagePrice"。
运营模式:套餐主表+价格日历由平台配置;套餐内每个商品由商户分别通过 MerchantPackageController 报名(applyStatus/audit 字段)并提交 platformPrice,平台审核通过后纳入套餐。
2.4 基础数据三件套
| 实体 | 表 | 作用 | 前端用法 |
|---|---|---|---|
XdCategory | xl_category | 统一分类树:businessType+parentId+level+code+entryFee+deposit(入驻费/保证金)+isEnabled | 商户入驻选分类/菜单推导/商品归类 |
XdTabGroup | xl_tab_group | App 首页 Tab 分组:sceneType(groupbuy/pintuan/package)+name+icon+sort+isEnabled,关联 categoryIds | App 按场景拉分组,分组下嵌套分类 |
XdRegion | xl_region | 区域字典(市县名,如海口、万宁)+sortOrder+status | 套餐选区/特产地理/+App 区域筛选 |
模块 3️⃣ 履约服务类商品(酒店/租车/租赁/接送/摄影/定制游)
3.1 酒店(双表审核机制)
| 实体 | 关键字段 |
|---|---|
XdHotelAppointment (xl_hotel_appointment) | orderId/orderNo/activityType(room/groupbuy/package)+sourceType(AUTO/MANUAL下单即预约 vs 手工预约)+roomTypeId/checkInDate/checkOutDate/nights/rooms/guestName/Phone/status(0待商户确认/1已确认/2协商中/3已撤销)+cancelSubReason(USER_DISAGREE/USER_TIMEOUT/MERCHANT_TIMEOUT/USER_CANCEL)+surchargeOrderNo(差价单号) |
XdRoomType (xl_room_type) | merchantId/roomName/roomType(大床/双床/套房)/totalRooms/basePrice(分)/bedInfo/area/maxGuests/facilities(JSON)/commissionRate |
XdRoomTypeAudit (xl_room_type_audit) | merchantId/roomTypeId/roomName/basePrice/totalRooms + auditStatus(1待审/2通过/3驳回) |
XdRoomCalendar (xl_room_calendar) | merchantId/roomTypeId/date/price(分)/extraFee/originalPrice/stock/sold/status(0售罄/1可售/2不可约) |
XdRoomCalendarAudit (xl_room_calendar_audit) | 双列对照:old/newPrice、old/newExtraFee、old/newStock、old/newStatus + auditStatus |
XdHotelHotArea / XdHotelHotKeyword | App 首页热门区域 / 热门搜索词 |
审核模式:酒店采用"双表双列"独立审计——商户新建/修改房型或日历时价不直接落库,写入审计表等待平台审批;通过时回写正式表。其他模块大多把 auditStatus 直接内嵌主表。
关键 Service:
IXdHotelAppointmentService:createFromRoomOrder/PackageOrder/PintuanOrder/VoucherRequest + confirm/submitNegotiation/userAgree/userDisagree/userCancel + scanMerchantTimeout/scanUserTimeout/cancelByTimeoutIXdRoomCalendarAuditService:insertAudit/batchInsertAudit + approveAudit/rejectAudit/approveBatch/rejectBatch
价格日历:酒店用 XdRoomCalendar.price 直接表达;其他业态(团购/套餐)另用 XdProductPriceCalendar。
3.2 租车与租赁(双链路同骨架)
| 维度 | 租车 car_rental | 非车租赁 rental |
|---|---|---|
| 履约单 | XdCarRentalDispatch | XdRentalOrderDispatch |
| 计价/库存 | 关联 XdCarModel + XdMerchantCar(物理车一辆辆登记) | 关联 rentalItemId(普通租赁商品 xl_product),按 quantity 叠加 |
| 计价模式 | 按日(dailyPrice),含里程/油量点检 | pricingMode + rentalStart/rentalEnd/rentalQuantity,按日/件计 |
| 押金 | XdRentalDeposit(businessType=car_rental) | XdRentalDeposit(businessType=rental) |
| 评价 | 共用 XdRentalReview(rentalItemId 双义键) | 同 |
车型层级:XdCarType(类目轿/SUV/MPV) → XdCarModel(PaaS标准车型库含 dailyPrice/depositAmount) → XdMerchantCar(商户挂车牌)。
押金 XdRentalDeposit(跨两业务通用):
depositMode:wechat_score(微信支付分冻结) /prepaid(预付金)status:0待收取 / 1已冻结 / 2已退还 / 3部分扣除 / 4全额扣除- 配套
XdRentalDepositService:freezeDeposit / refundDeposit / deductDeposit(amount, reason)
派单流程(IXdCarRentalDispatchService):
createDispatch → assignMerchant → accept/reject → pickupCar(点检里程/油量/照片)
→ returnCar(还车点检+损伤) → confirmComplete → settle 结算
定时任务 markOverdue 标记逾期并算 overdueFee3.3 接送机/包车(统一订单+三种计价)
计价实体(3 种 serviceType)
| 实体 | serviceType | 用法 |
|---|---|---|
XdTransferRoute (xl_transfer_route) | route | 固定价路线:routeName/startName/endName/distanceKm/economyPrice+luxuryPrice +对应 platformRatio |
XdTransferCharterPrice (xl_transfer_charter_price) | charter | vehicleType(economy/luxury) × charterType(hour/day) 二维表 + minQuantity |
XdTransferTaxiPrice (xl_transfer_taxi_price) | taxi | 分段计费:segmentOrder/basePrice+baseKm 起步/minKm-maxKm 区间/pricePerKm |
XdCharterPrice (旧版⚠️) | 兼容 | 含超出公里+远途分段两段计费,与新 CharterPrice 重叠 |
XdTransferPriceRule (区间规则⚠️) | 兼容 | 与 TaxiPrice 分段是两套并存配置 |
订单与派单
XdTransferOrder(xl_transfer_order):核心订单表,serviceType=taxi/charter/route决定价来源;含起点/终点经纬度、distanceKm(打车用)、charterType+charterQuantity(包车用)、routeId(路线用)、totalAmount/payAmount/platformAmount/driverAmount(分)、司机时间线。专车特例:payAmount = totalAmount(无优惠)XdTransferDispatch(xl_transfer_dispatch):与订单 1:1,dispatchStatus(0待派/1派单/2接单/3进行/4完成/5取消) + dispatchMode(manual/auto)
派单流程(IXdTransferDispatchService):
triggerAutoDispatch(支付成功后) → driverAccept/driverReject(尝试下一位) → startService(位置) → completeService(结算)
复用 XdDriverVehicle(司机端座驾) + XdDriverLocation(位置上行) + DriverController(司机上下线)计价 Service IXdTransferPriceService(提交订单时调用唯一入口):
calcTaxiPrice:按 TaxiPrice 逐段累计,第 1 段起步段;注释明确 pricePerKm 按 "元/km" DB 存,运行时 ×100 → 分/kmcalcCharterPrice:按 vehicleType+charterType 取规则,校验最小数量calcRoutePrice:按 routeId 取固定价,按 vehicleType 选 economy/luxury
3.4 摄影 + 定制游
旅拍
XdPhotographyPackage(xl_photography_package):平台维护的标准套餐(含 shootingDuration/costumeCount/sceneCount/deliveryDays/destination),App 直接下单XdPhotographyDispatch(xl_photography_dispatch):派单流程 assignPhotographer → accept/reject → startShooting → deliverWork(deliverUrl) → confirmComplete → settle
定制游(轻流程)
XdCustomTour(xl_custom_tour):userId/contactName/destination/startTime/endTime/days/remark + status(0待处理/1已联系)- 无订单/派单/结算——用户提交需求 → 后台销售人工联系 → status 0→1
3.5 跨业务共性
- 统一的派单状态机骨架:创建 → assign → 接/拒 → 开始 → 完成 → 结算(seettle) + settlementStatus + rejectReason
- 平台抽成通用字段:commissionRate / platformRatio / settlementRate
- 押金复用:
XdRentalDeposit单表跨两类业务 - 评价复用:
XdRentalReview跨两类 - 司机抽象:
XdDriverVehicle+XdDriverLocation+DriverController由专车+未来车辆类业务共用
模块 4️⃣ 用户 + 社交 + 钱包
4.1 用户与社交
| 实体 | 字段要点 |
|---|---|
XdAppUser (xl_app_user) | openid/unionid/phone/nickname/avatar/bio/gender/status(0正常/1禁用)/newcomerGiftReceived/lastLoginTime+IP + 推广体系:referCode(6位注册自动生成)+referrerId(扫码绑定) |
XdUserFollow (xl_user_follow) | followerId/followingId + isMutual(互关校验,IM 私信用) |
XdUserGuest (xl_user_guest) | userId+name+phone+isDefault —— 常用入住人,下单复用 |
XdWallet (xl_wallet) | balance/frozenAmount/totalRecharge/totalConsume/totalRefund/totalReward(分)+version(乐观锁) |
XdWalletTransaction (xl_wallet_transaction) | transactionNo/type/direction(收/支)/balanceBefore/balanceAfter/relatedOrderNo/remark |
4.2 登录与 JWT
AppLoginController.login 步骤:
WechatMiniAppService.jscode2session(code)拿 openid/unionid;本地无 secret 走 mock(dev_ 前缀 openid + 占位手机号)selectByOpenid—— 不存在则registerUser(isNewUser=true),存在则updateLoginInfo,禁用抛错tokenService.createAppToken(XdAppUser):fastUUID 作 appKey → Redis(TTL expireTime×24 min)+ JWT 含 LOGIN_USER_KEY/userId/USER_TYPE_APP- 返回 token+user+isNewUser+
grantNewcomerGift自动发券并返回giftCoupons - 滑动续期:剩余 < 2h 自动续;
delAppToken删 Redis
模块 5️⃣ 笔记社区 + 旅游攻略 + IM
5.1 笔记核心实体链
| 实体 | 要点 |
|---|---|
XdNote (xl_note) | authorType("user"/"merchant")/authorId/title/content/coverImage/images(列表)/videoUrl/location/lat/lng/viewCount/likeCount/collectCount/commentCount/status/rejectReason/isTop/isRecommend |
XdNoteDraft | 草稿(含 topicIds JSON 字符串) |
XdNoteComment | parentId(树形 self-ref)+replyToUserId+likeCount+status,children 子评论 |
XdNoteInteraction | type 字段记录点赞/收藏 |
XdNoteProductRel | 笔记→商品挂载(productTitle/productCover 快照) |
XdNoteViewLog | userId+noteId+duration(停留时长,喂个性化) |
话题系统:XdNoteTopic(话题) + XdNoteTopicRel(多对多),有 source(官方/用户)区分。
5.2 个性化推荐
XdNoteRecommendServiceImpl:
recordView(userId, noteId, duration):写 ViewLog + 增浏览数refreshUserInterest(userId):SQLselectInterestScoresByUser按近一周浏览计算话题兴趣分 → 写 Redis Hashnote:interest:{userId}(TTL 7 天)getUserInterestTopicIds(userId):从 Redis Hash 按分降序取 Top10 topicIds- 定时
NoteRecommendTask.refreshActiveUserInterests(建议 cron0 0 3 * * ?) - App list 用法:有登录且兴趣非空 →
selectRecommendedNoteList(interestTopicIds, topicId);否则selectHotNoteList(热门兜底)
5.3 三端入口
- 用户
AppNoteController/api/app/notes:list(个性化推荐,支持 seed)/ topics / 详情(带 liked/collected) / 发布 / 编辑(校验属主) / 我的 / 收藏 / 点赞 / 评论 / 上报浏览 / 按用户页+stats +AppNoteDraftController草稿 CRUD - 商家
MerchantNoteController/api/merchant/notes:商家发笔记(authorType="merchant") + 回复评论 - 平台
AdminNoteController/api/admin/notes:approve/reject/offline/top/recommend + user-stats +AdminNoteTopicController话题 CRUD +AdminNoteCommentController评论删除
5.4 旅游攻略
XdTravelGuide(xl_travel_guide):title/summary/content/coverImage/viewCount/sortOrder/statusXdTravelGuideProductRel:guideId/itemType/itemId(攻略挂多种业务商品:团/酒店等)- 用户
AppTravelGuideController列表/详情;平台AdminTravelGuideController发布/下线/CRUD
5.5 IM 客服
集成自建 OpenIM,业务后端不维护消息表,消息由 OpenIM 服务存储。
OpenIMConfig配置服务端 API、客户端 API、WebSocket、共享密钥和客服管理员账号OpenIMService负责幂等注册账号、签发用户 Token;三端统一通过/im/credentials获取凭证- 账号命名:
user_{userId}/merchant_{id}/admin_{userId}(客服) - C 端
canChat/{targetUserId}校验isMutual互关;公开customer-service客服号
模块 6️⃣ 拼团 + 团购 + 营销活动
6.1 拼团机制
| 实体 | 字段 |
|---|---|
XdGroup (xl_group) | productId/activityId/activityProductId/status(0等待中/1成团成功/2失败/3取消)/requiredCount/expireTime(成团截止)/creatorName/members/currentCount |
XdGroupMember | userId/orderId/isLeader(0普通/1团长)/joinTime |
状态流转(PintuanOrderHandler.onPaid 触发):
- 团长支付成功 →
createGroup建 status=0;expireTime = now + pintuan.timeout.hours(默认 24h) - 团员加入:
createPintuanGroup/joinPintuanGroup下单,支付回调按 orderId 幂等插 Member(防重) - 成团:
paidCount >= requiredCount→setGroupSuccess(status=1)→ 批量发券(券 valid_end 由PintuanCategoryConfig.verifyHours决定) - 超时:
handleTimeoutGroups扫过期 →setGroupFailed(2)→ 未支付取消返还券 / 已支付createAutoRefundForPintuanFailed自动退款 - 取消:
cancelGroupstatus=3
XdPintuanCategoryConfig (xl_pintuan_category_config):categoryId + verifyHours(核销时长)+cancelMinutes+penaltyRate(超窗费率)。退款扣手续费按此配置,由商户钱包 deductForRefund 扣减。
6.2 营销活动
XdProductActivity 字段:productId/merchantId/city/activityType/priceMode(amountPrice+commissionRate+settlementPrice+originalPrice)/limitPerUser/refundType/useRules/purchaseNotice/noticeConfigList(JSON)/validType(1天数/2日期)/validStart+End/sort/status(0待审/1启用/2下架/3禁用)+auditReason/auditBy/auditTime/platformMargin。
Service IXdProductActivityService:
insertActivity(校验同类型不可重复)auditActivity(id, status, reason, auditor)平台审核setActivityPrice(id, price)平台定价onlineByProductId/offlineByProductId批量上下架所有活动
模块 7️⃣ 优惠券 + 新人礼包 + 推广分销
7.1 优惠券
| 实体 | 要点 |
|---|---|
XdCouponTemplate + XdCouponVersion | 模板保存稳定业务身份,已发布版本固化满减/直减规则、默认商户承担金额、xd_category 适用分类和有效期 |
XdCouponClaimCampaign | 领券中心投放窗口、总量与已发数量;同一用户对同一模板只能主动领取一次 |
XdUserCoupon | 发放时固化规则、分类、承担金额和来源;状态按 AVAILABLE/LOCKED/USED/EXPIRED/VOID 流转 |
XdOrderCouponUsage + XdOrderCouponAllocation | 下单时固化实际优惠、商户/平台承担、结算和订单明细分摊,支付、钱包、详情及退款只读快照 |
7.2 新人礼包
XdCouponBundle/XdCouponBundleItem 组成通用礼包。新人礼包在 AppLoginController.login 首次登录时幂等发放全部优惠券;普通礼包支持 N 选 K,每个礼包每位用户只能领取一次。
7.3 推广分销
XdAppUser.referCode(6位注册自动生成)+referrerId(扫码绑定,防自绑+仅首次绑定)IXdAppUserService.getReferralStats/getReferralDetail:推广统计- 平台
AdminReferralController查看
模块 8️⃣ 基础数据 + 通知 + 监控
8.1 区域 / Tab / 短信 / 通知
XdRegion+XdTabGroup(见 §2.4)XdSmsLog(xl_sms_log):phone/code/templateCode/scene/sendDate/bizId(阿里云)/aliyunStatus/Code/errorMsgSmsService(阿里云 dysmsapi 20170525.Client):SMS_CODE_KEY="sms_code:"缓存验证码 5min;SMS_VERIFIED_KEY已校验状态 30min;发送间隔 60ssendCode(phone)生成 6 位 + 调阿里云 + 写 XdSmsLogverifyCode(phone, code)+isVerified(phone)
XdNoticeTemplate(xl_notice_template):key/label/inputType/defaultContent/sort/isEnabled —— 购买须知可配置项
8.2 三端短信/通知接口
- 用户/商户
SmsController/api/merchant/sms:send/verify(无需登录) - 平台
AdminSmsLogController/api/admin/sms-log:list/detail/syncStatus(回查阿里云)
8.3 RuoYi 原生(系统/监控)
保留原版系统管理、监控、代码生成模块(sys/monitor/tool),与业务并行使用。
模块间核心数据流
┌────────────────────────────────────────────────────────────┐
│ ④ 用户登录(app) → XdAppUser + NewcomerGift + │
│ Wallet(getOrCreate) │
└──────────────┬─────────────────────────────────────────────┘
↓
┌──── App:选 TabGroup/Region/Category → AppProduct 查商品 ────┐
│ │
│ 下单(9 种 OrderTypeHandler.buildOrderDraft) │
│ └─ 汇总金额 + XdOrderItem + parentOrderNo(PAY_) │
│ │
└──────────────────┬─────────────────────────────────┬─────────┘
↓ ↓
① PaymentOrchestrator.createPayment ⑤ 笔记社区
↓ (关联 ProductRel)
① PlatformWechatPayService.prepayJsapi
↓
wx.requestPayment
↓
notify → applyPaymentSuccess → OrderStateMachine.markPaid
↓ OrderPaidEvent(AFTER_COMMIT)
┌─────────┴──────────┬───────────┬───────────────┐
↓ ↓ ↓ ↓
扣库存/发券(券码) Handler.onPaid 记套餐占位 ⑤ 触发派单 Dispatch
(per-activityType) (auto-trigger)
│
┌───────┴─── 履约流程 ─────────────────────────────────┐
│ ③ 酒店:XdHotelAppointment 商户协商/确认→发券→核销 │
│ ③ 租车/租赁:Dispatch.assign→pickup→return→settle │
│ ③ 接送:TransferDispatch.autoAssign→接→起→完→settle │
│ ③ 摄影:PhotographyDispatch.assignPhotographer→交付 │
└──────────────────┬───────────────────────────────────┘
↓
OrderCompletionService.complete
↓ (SettlementPolicy T+N)
② MerchantWalletLedger.pendingSettle
↓
MerchantWalletSettlementTask(每天 01:00) → 可提现
↓
② MerchantWithdrawal → 提现审批 → 转账
── 对账 & 兜底:① 8 个 Quartz/Scheduled Task 保证最终一致
── 发货同步:① MallShipSyncTask → XdWxShipSync
── 个体结算:① IndividualSettlementTask → 微信 V3 转账零钱关键技术债与风险清单
PayScoreNotifyController未验签未 AES 解密,有 TODO 标注 —— 上线前必须补ICommissionCalculator是 SPI 残留:无实现、无调用方,建议清理或重新接入XdOrder大量@Deprecated桩方法(标 "remove in Phase 8")待清理RefundSyncTask(Quartz) 与RefundStateSyncTask(@Scheduled) 两份近似实现并存 —— 应统一XdCharterPrice与XdTransferCharterPrice、XdTransferPriceRule与XdTransferTaxiPrice都是新旧两套并存 —— 建议收敛WechatPayConfig(服务商合单模式)已物理删除 —— 历史代码层注释残留,新人易误解- 金额单位全系统统一为"分"(Long) —— 存在历史迁移脚本
money-to-fen.sql,前端须保持一致 - Druid 监控默认口令
ruoyi/123456—— 上线前替换 PAY_前缀修复了 OD_ 前缀的查单 bug —— 历史坑已规避但需明确文档- 平台抽佣已退化为支付回调时直写
XdOrderItem.merchantIncomeFen—— 无微信分账接口调用,分账体系已简化
关键技术栈速查
后端
| 类别 | 技术 | 版本 |
|---|---|---|
| 框架 | Spring Boot (BOM) | 3.5.8 |
| Java | — | 17 |
| 骨架 | RuoYi-Vue | 3.9.1 |
| 数据层 | MyBatis Spring Boot | 3.0.5 |
| 分页 | PageHelper | 2.1.1 |
| 连接池 | Druid | 1.2.27 |
| 数据库 | MySQL | 服务器实例(通过 SSH 隧道映射到本地 3306,库 xiedao_dev) |
| 缓存 | Redis(Lettuce 连接池)+ embedded-redis 1.4.3 兜底 | |
| 认证 | JWT (jjwt 0.9.1) + kaptcha 2.3.3 | |
| 文档 | springdoc-openapi | 2.8.14 |
| 微信支付 | wechatpay-java | 0.2.14 (V3) |
| OpenIM Server API | HTTP/WebSocket | 3.8.3-patch.12 |
| 阿里云 OSS | aliyun-sdk-oss | 3.18.1 |
| 富文本/Excel/Velocity | fastjson2 2.0.60 / POI 4.1.2 / Velocity 2.3 |
前端 AdminWeb
| 类别 | 依赖 | 版本 |
|---|---|---|
| 框架 | vue | 3.5.26 |
| UI | element-plus + icons | 2.13.1 / 2.3.2 |
| 状态 | pinia | 3.0.4 |
| 路由 | vue-router | 4.6.4 |
| 构建 | vite + @vitejs/plugin-vue | 6.4.1 / 5.2.4 |
| HTTP | axios | 1.13.2 |
| 富文本/图表/IM | @vueup/vue-quill / echarts / @openim/wasm-client-sdk |
开发端口约定
- 后端 dev
8082 - AdminWeb dev
8081 - MerchantWeb dev
8083 - MySQL
3306(SSH 隧道) - Redis
6379(SSH 隧道)
生产配置要点
- API 域名
api.xiedao888.cn - 阿里云 OSS bucket
xielioss(深圳) - OpenIM Server
3.8.3-patch.12,Web SDK3.8.3-patch.14 - 微信小程序:用户端 appId
wx0335c014637515d7+ 商家端wx6642b9109973617a
数据库演进体系速查
| 目录 | 风格 | 用途 |
|---|---|---|
Api/db/migration/ | Flyway 式 V{date}__name.sql | 正式增量迁移 |
Api/sql/ | 基础 SQL | 仅保留 RuoYi 系统表和 Quartz 调度表;业务库结构及数据由数据库备份维护 |
Docs/sql/ | 跨主题迁移 | db-migrate-xiedao.sql、money-to-fen(-migrate).sql |
Docs/superpowers/ddl/ | 工作流产物 | phase1-baseline.sql |
代码组织速查
Api/
├─ ruoyi-admin/.../web/controller/
│ ├─ app/ 用户端 33 个 Controller(/api/app/**)
│ ├─ merchant/ 商户端 26 个(/api/merchant/**)
│ ├─ platform/ 平台端 48 个(/api/admin/**)
│ ├─ system/ RuoYi 系统管理(/system/**)
│ ├─ monitor/ 监控(/monitor/**)
│ └─ task/ Spring @Scheduled 定时任务
├─ ruoyi-system/.../system/
│ ├─ domain/ 全部业务实体(Xd* 前缀)
│ ├─ mapper/ MyBatis Mapper 接口
│ └─ service/
│ ├─ order/ OrderStateMachine + Orchestration + 9 个 Handler
│ ├─ payment/ PaymentOrchestrator + 微信支付服务
│ └─ impl/ Service 实现
├─ ruoyi-framework/ Spring Security/JWT/AOP
├─ ruoyi-common/ 共享工具/注解/常量
├─ ruoyi-quartz/ Quartz 定时任务(sys_job 配置)
└─ ruoyi-generator/ 代码生成器业务命名约定:
- 实体前缀
Xd*区分 RuoYi 原生Sys* - 数据库表前缀(旧)
xl_—— 已迁移,保留兼容 - 金额字段统一后缀
Fen或存 Long(分单位) - 状态变更均写
*_event或*_log审计表
本文档由代码探索自动整理,可能与最新实现略有出入,建议结合代码与 git history 阅读。如发现偏差,欢迎补充修订。