Преглед изворни кода

新增用户查询订单功能,更新相关DTO和支付服务逻辑以支持用户通过订单号查询订单状态,同时优化收入记录查询逻辑以支持用户ID的过滤。

wuyi пре 3 месеци
родитељ
комит
02876a33df

+ 17 - 1
src/controllers/payment.controller.ts

@@ -1,6 +1,11 @@
 import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
 import { PaymentService } from '../services/payment.service'
-import { CreatePaymentParams, PaymentNotifyParams, CreatePaymentOrderParams } from '../dto/payment.dto'
+import {
+  CreatePaymentParams,
+  PaymentNotifyParams,
+  CreatePaymentOrderParams,
+  UserQueryOrderParams
+} from '../dto/payment.dto'
 
 export class PaymentController {
   private paymentService: PaymentService
@@ -67,4 +72,15 @@ export class PaymentController {
       return reply.code(500).send('Failed to query payment order')
     }
   }
+
+  async userQueryOrder(request: FastifyRequest<{ Querystring: UserQueryOrderParams }>, reply: FastifyReply) {
+    try {
+      const user = request.user
+      const { orderNo } = request.query
+      const result = await this.paymentService.userQueryOrder(user.id, orderNo)
+      return reply.send(result)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
 }

+ 10 - 0
src/dto/payment.dto.ts

@@ -63,3 +63,13 @@ export interface PaymentQueryResponse {
   money: string
   type: 'alipay' | 'wxpay'
 }
+
+export interface UserQueryOrderParams {
+  orderNo?: string
+}
+
+export interface UserQueryOrderResponse {
+  orderNo: string
+  msg: string
+  status: 0 | 1
+}

+ 9 - 1
src/routes/payment.routes.ts

@@ -1,6 +1,7 @@
 import { FastifyInstance } from 'fastify'
 import { PaymentController } from '../controllers/payment.controller'
-import { CreatePaymentParams, PaymentNotifyParams, CreatePaymentOrderParams } from '../dto/payment.dto'
+import { PaymentNotifyParams, CreatePaymentOrderParams, UserQueryOrderParams } from '../dto/payment.dto'
+import { authenticate } from '../middlewares/auth.middleware'
 
 export default async function paymentRoutes(fastify: FastifyInstance) {
   const paymentController = new PaymentController(fastify)
@@ -16,4 +17,11 @@ export default async function paymentRoutes(fastify: FastifyInstance) {
 
   // 查询订单
   fastify.get('/query', paymentController.queryOrder.bind(paymentController))
+
+  // 用户查询订单
+  fastify.get<{ Querystring: UserQueryOrderParams }>(
+    '/user/query',
+    { onRequest: [authenticate] },
+    paymentController.userQueryOrder.bind(paymentController)
+  )
 }

+ 19 - 2
src/services/income-records.service.ts

@@ -101,14 +101,31 @@ export class IncomeRecordsService {
     }
   }
 
-  async findByOrderNo(orderNo: string): Promise<IncomeRecords | null> {
-    const record = await this.incomeRecordsRepository.findOne({ where: { orderNo } })
+  async findByOrderNo(orderNo: string, userId?: number): Promise<IncomeRecords | null> {
+    const where: any = { orderNo }
+    if (userId) {
+      where.userId = userId
+    }
+    const record = await this.incomeRecordsRepository.findOne({ where })
     if (!record) {
       return null
     }
     return record
   }
 
+  async findRecentByUserId(userId: number, since: Date): Promise<IncomeRecords | null> {
+    const record = await this.incomeRecordsRepository.findOne({
+      where: {
+        userId,
+        createdAt: Between(since, new Date())
+      },
+      order: {
+        createdAt: 'DESC'
+      }
+    })
+    return record
+  }
+
   async update(data: UpdateIncomeRecordBody): Promise<IncomeRecords> {
     const { id, ...updateData } = data
     await this.incomeRecordsRepository.update(id, updateData)

+ 70 - 2
src/services/payment.service.ts

@@ -6,7 +6,8 @@ import {
   PaymentQueryParams,
   PaymentQueryResponse,
   CreatePaymentOrderParams,
-  CreatePaymentOrderResponse
+  CreatePaymentOrderResponse,
+  UserQueryOrderResponse
 } from '../dto/payment.dto'
 import axios from 'axios'
 import crypto from 'crypto'
@@ -174,7 +175,7 @@ export class PaymentService {
         type: 'alipay',
         out_trade_no,
         notify_url: `https://9g15.vip/api/payment/notify`,
-        return_url: `https://yz1df.cc/account`,
+        return_url: `https://yz1df.cc/account?pay=true`,
         name: `${params.type} 订单`,
         money: price,
         client_ip: params.ip
@@ -274,6 +275,73 @@ export class PaymentService {
     }
   }
 
+  async userQueryOrder(userId: number, orderNo?: string): Promise<UserQueryOrderResponse> {
+    const responseData: UserQueryOrderResponse = {
+      orderNo: orderNo || '',
+      msg: '',
+      status: 0
+    }
+
+    try {
+      let targetOrderNo = orderNo
+      let incomeRecord
+
+      if (!orderNo) {
+        // 查询用户最近12小时内的订单
+        const twelveHoursAgo = new Date(Date.now() - 12 * 60 * 60 * 1000)
+        const recentRecord = await this.incomeRecordsService.findRecentByUserId(userId, twelveHoursAgo)
+
+        if (!recentRecord) {
+          responseData.msg = '没有找到最近的订单'
+          return responseData
+        }
+
+        targetOrderNo = recentRecord.orderNo
+        incomeRecord = recentRecord
+        responseData.orderNo = targetOrderNo
+      } else {
+        incomeRecord = await this.incomeRecordsService.findByOrderNo(orderNo, userId)
+        if (!incomeRecord) {
+          responseData.msg = '没有找到订单'
+          return responseData
+        }
+      }
+
+      if (!targetOrderNo) {
+        responseData.msg = '订单号无效'
+        return responseData
+      }
+
+      const result = await this.queryOrder({ out_trade_no: targetOrderNo })
+      if (result.code !== 1) {
+        responseData.msg = '没有找到支付订单'
+        return responseData
+      }
+
+      if (result.status !== 1) {
+        responseData.msg = '订单未支付'
+        return responseData
+      } else {
+        if (incomeRecord.status === false) {
+          await this.incomeRecordsService.update({
+            id: incomeRecord.id,
+            status: true
+          })
+          responseData.msg = '订单支付成功'
+          responseData.status = 1
+        } else {
+          responseData.msg = '订单已支付'
+          responseData.status = 1
+        }
+      }
+    } catch (error) {
+      this.app.log.error('Failed to query user order:', error)
+      responseData.msg = '查询订单失败'
+    }
+
+    return responseData
+  }
+
   private getVipLevelByOrderType(orderType: OrderType): VipLevel {
     return PaymentService.ORDER_TYPE_TO_VIP_LEVEL_MAP[orderType] ?? VipLevel.FREE
   }