23edb74bce
- 支付系统:微信支付 mock 自动完成、NATIVE 扫码支付、JSAPI 集成 - 运营助手:Tool Calling 架构,19 个可执行工具,AI 驱动操作 - 角色管理:表格布局 + Dialog 表单 + 权限勾选 - 配置统一:config.ts 单一数据源 - API 审计:补齐 status toggle / comments 端点 - 暗黑模式硬件编码颜色全部替换为 CSS 变量
90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { PrismaService } from '../../prisma/prisma.service';
|
|
import { PaymentService } from '../payment/payment.service';
|
|
|
|
@Injectable()
|
|
export class OrdersService {
|
|
constructor(
|
|
private prisma: PrismaService,
|
|
private paymentService: PaymentService,
|
|
) {}
|
|
|
|
async create(userId: number, data: { amount: number; planType: string; payChannel?: string; tradeType?: string; openid?: string }) {
|
|
const orderNo = `YZR${Date.now()}${Math.random().toString(36).slice(2, 8).toUpperCase()}`;
|
|
|
|
const order = await this.prisma.order.create({
|
|
data: {
|
|
orderNo,
|
|
userId,
|
|
amount: data.amount,
|
|
planType: data.planType,
|
|
payChannel: data.payChannel || 'wxpay',
|
|
},
|
|
});
|
|
|
|
// If paying via WeChat, create unified order
|
|
if (data.payChannel === 'wxpay' || !data.payChannel) {
|
|
try {
|
|
const planLabels: Record<string, string> = {
|
|
MONTHLY: '宇之然AI月卡会员',
|
|
YEARLY: '宇之然AI年卡会员',
|
|
};
|
|
const payResult = await this.paymentService.createUnifiedOrder({
|
|
description: planLabels[data.planType] || '宇之然AI会员充值',
|
|
outTradeNo: orderNo,
|
|
amount: data.amount,
|
|
tradeType: (data.tradeType as 'JSAPI' | 'NATIVE' | 'MWEB') || 'NATIVE',
|
|
openid: data.openid,
|
|
});
|
|
// Mock 模式下自动完成支付闭环(NATIVE mock 无需扫码)
|
|
if (payResult?.codeUrl === 'mock://pay') {
|
|
await this.paymentService.completeMockPayment(orderNo);
|
|
}
|
|
return { order, payResult };
|
|
} catch {
|
|
return { order, payResult: null };
|
|
}
|
|
}
|
|
|
|
return { order };
|
|
}
|
|
|
|
async findByUser(userId: number, params: { page?: number; pageSize?: number }) {
|
|
const page = Number(params.page ?? 1);
|
|
const pageSize = Number(params.pageSize ?? 20);
|
|
const [items, total] = await Promise.all([
|
|
this.prisma.order.findMany({
|
|
where: { userId },
|
|
skip: (page - 1) * pageSize,
|
|
take: pageSize,
|
|
orderBy: { createdAt: 'desc' },
|
|
}),
|
|
this.prisma.order.count({ where: { userId } }),
|
|
]);
|
|
return { items, total, page, pageSize };
|
|
}
|
|
|
|
async findByOrderNo(orderNo: string) {
|
|
return this.prisma.order.findUnique({ where: { orderNo } });
|
|
}
|
|
|
|
async getCurrentSubscription(userId: number) {
|
|
const now = new Date();
|
|
return this.prisma.subscription.findFirst({
|
|
where: {
|
|
userId,
|
|
status: 'ACTIVE',
|
|
endDate: { gt: now },
|
|
},
|
|
orderBy: { endDate: 'desc' },
|
|
});
|
|
}
|
|
|
|
async getSubscriptions(userId: number) {
|
|
return this.prisma.subscription.findMany({
|
|
where: { userId },
|
|
orderBy: { createdAt: 'desc' },
|
|
});
|
|
}
|
|
}
|