主要更新: 1. 按H5网页端完全重构匹配功能(match页面) - 4种匹配类型: 创业合伙/资源对接/导师顾问/团队招募 - 资源对接等类型弹出手机号/微信号输入框 - 去掉重新匹配按钮,改为返回按钮 2. 修复所有卡片对齐和宽度问题 - 目录页附录卡片居中 - 首页阅读进度卡片满宽度 - 我的页面菜单卡片对齐 - 推广中心分享卡片统一宽度 3. 修复目录页图标和文字对齐 - section-icon固定40rpx宽高 - section-title与图标垂直居中 4. 更新真实完整文章标题(62篇) - 从book目录读取真实markdown文件名 - 替换之前的简化标题 5. 新增文章数据API - /api/db/chapters - 获取完整书籍结构 - 支持按ID获取单篇文章内容
290 lines
6.3 KiB
TypeScript
290 lines
6.3 KiB
TypeScript
/**
|
|
* 通用支付模块类型定义 (Universal Payment Module Types)
|
|
* 基于 Universal_Payment_Module v4.0 设计
|
|
*
|
|
* 作者: 卡若
|
|
* 版本: v4.0
|
|
*/
|
|
|
|
// 支付平台枚举
|
|
export type PaymentPlatform = 'alipay' | 'wechat' | 'paypal' | 'stripe' | 'usdt' | 'coin';
|
|
|
|
// 支付网关类型
|
|
export type PaymentGateway =
|
|
| 'alipay_web' | 'alipay_wap' | 'alipay_qr'
|
|
| 'wechat_native' | 'wechat_jsapi' | 'wechat_h5' | 'wechat_app'
|
|
| 'paypal' | 'stripe' | 'usdt' | 'coin';
|
|
|
|
// 订单状态
|
|
export type OrderStatus = 'created' | 'paying' | 'paid' | 'closed' | 'refunded';
|
|
|
|
// 交易状态
|
|
export type TradeStatus = 'paying' | 'paid' | 'closed' | 'refunded';
|
|
|
|
// 交易类型
|
|
export type TradeType = 'purchase' | 'recharge';
|
|
|
|
// 支付结果类型
|
|
export type PaymentResultType = 'url' | 'qrcode' | 'json' | 'address' | 'direct';
|
|
|
|
// 货币类型
|
|
export type Currency = 'CNY' | 'USD' | 'EUR' | 'USDT';
|
|
|
|
/**
|
|
* 创建订单请求参数
|
|
*/
|
|
export interface CreateOrderParams {
|
|
userId: string;
|
|
title: string;
|
|
amount: number; // 金额(元)
|
|
currency?: Currency;
|
|
productId?: string;
|
|
productType?: 'section' | 'fullbook' | 'membership' | 'vip';
|
|
extraParams?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* 订单信息
|
|
*/
|
|
export interface Order {
|
|
sn: string; // 订单号
|
|
userId: string;
|
|
title: string;
|
|
priceAmount: number; // 原价(分)
|
|
payAmount: number; // 应付金额(分)
|
|
currency: Currency;
|
|
status: OrderStatus;
|
|
productId?: string;
|
|
productType?: string;
|
|
extraData?: Record<string, unknown>;
|
|
paidAt?: Date;
|
|
closedAt?: Date;
|
|
expiredAt?: Date;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
}
|
|
|
|
/**
|
|
* 发起支付请求参数
|
|
*/
|
|
export interface CheckoutParams {
|
|
orderSn: string;
|
|
gateway: PaymentGateway;
|
|
returnUrl?: string;
|
|
openid?: string; // 微信JSAPI需要
|
|
coinAmount?: number; // 虚拟币抵扣
|
|
}
|
|
|
|
/**
|
|
* 创建交易请求数据
|
|
*/
|
|
export interface CreateTradeData {
|
|
goodsTitle: string;
|
|
goodsDetail?: string;
|
|
tradeSn: string;
|
|
orderSn: string;
|
|
amount: number; // 金额(分)
|
|
notifyUrl: string;
|
|
returnUrl?: string;
|
|
platformType?: string; // web/wap/jsapi/native/h5/app
|
|
createIp?: string;
|
|
openId?: string;
|
|
attach?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* 支付交易结果
|
|
*/
|
|
export interface TradeResult {
|
|
type: PaymentResultType;
|
|
payload: string | Record<string, string>;
|
|
tradeSn: string;
|
|
expiration?: number; // 过期时间(秒)
|
|
amount?: number;
|
|
coinDeducted?: number;
|
|
prepayId?: string; // 微信预支付ID
|
|
}
|
|
|
|
/**
|
|
* 回调解析结果
|
|
*/
|
|
export interface NotifyResult {
|
|
status: 'paying' | 'paid' | 'closed' | 'refunded' | 'failed';
|
|
tradeSn: string;
|
|
platformSn: string;
|
|
payAmount: number; // 分
|
|
payTime: Date;
|
|
currency: Currency;
|
|
attach?: Record<string, unknown>;
|
|
rawData?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* 交易流水
|
|
*/
|
|
export interface PayTrade {
|
|
id?: string;
|
|
tradeSn: string;
|
|
orderSn: string;
|
|
userId: string;
|
|
title: string;
|
|
amount: number; // 分
|
|
cashAmount: number; // 现金支付金额(分)
|
|
coinAmount: number; // 虚拟币抵扣金额
|
|
currency: Currency;
|
|
platform: PaymentPlatform;
|
|
platformType?: string;
|
|
platformSn?: string;
|
|
platformCreatedParams?: Record<string, unknown>;
|
|
platformCreatedResult?: Record<string, unknown>;
|
|
status: TradeStatus;
|
|
type: TradeType;
|
|
payTime?: Date;
|
|
notifyData?: Record<string, unknown>;
|
|
sellerId?: string;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
}
|
|
|
|
/**
|
|
* 退款记录
|
|
*/
|
|
export interface Refund {
|
|
id?: string;
|
|
refundSn: string;
|
|
tradeSn: string;
|
|
orderSn: string;
|
|
amount: number; // 分
|
|
reason?: string;
|
|
status: 'pending' | 'processing' | 'success' | 'failed';
|
|
platformRefundSn?: string;
|
|
refundedAt?: Date;
|
|
operatorId?: string;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
}
|
|
|
|
/**
|
|
* 支付网关配置
|
|
*/
|
|
export interface GatewayConfig {
|
|
enabled: boolean;
|
|
mode: 'sandbox' | 'production';
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* 支付宝配置
|
|
*/
|
|
export interface AlipayConfig extends GatewayConfig {
|
|
appId: string;
|
|
pid: string;
|
|
sellerEmail?: string;
|
|
privateKey?: string;
|
|
publicKey?: string;
|
|
md5Key?: string;
|
|
}
|
|
|
|
/**
|
|
* 微信支付配置
|
|
*/
|
|
export interface WechatConfig extends GatewayConfig {
|
|
appId: string;
|
|
appSecret?: string;
|
|
serviceAppId?: string; // 服务号AppID
|
|
serviceSecret?: string;
|
|
mchId: string;
|
|
mchKey: string;
|
|
certPath?: string;
|
|
keyPath?: string;
|
|
}
|
|
|
|
/**
|
|
* 统一响应格式
|
|
*/
|
|
export interface PaymentResponse<T = unknown> {
|
|
code: number;
|
|
message: string;
|
|
data: T | null;
|
|
}
|
|
|
|
/**
|
|
* 支付方式信息
|
|
*/
|
|
export interface PaymentMethod {
|
|
gateway: PaymentGateway;
|
|
name: string;
|
|
icon: string;
|
|
enabled: boolean;
|
|
available: boolean; // 当前环境是否可用
|
|
}
|
|
|
|
/**
|
|
* 支付异常
|
|
*/
|
|
export class PaymentException extends Error {
|
|
constructor(message: string, public code?: string) {
|
|
super(message);
|
|
this.name = 'PaymentException';
|
|
}
|
|
}
|
|
|
|
export class SignatureError extends PaymentException {
|
|
constructor(message = '签名验证失败') {
|
|
super(message, 'SIGNATURE_ERROR');
|
|
this.name = 'SignatureError';
|
|
}
|
|
}
|
|
|
|
export class AmountMismatchError extends PaymentException {
|
|
constructor(message = '金额不匹配') {
|
|
super(message, 'AMOUNT_MISMATCH');
|
|
this.name = 'AmountMismatchError';
|
|
}
|
|
}
|
|
|
|
export class GatewayNotFoundError extends PaymentException {
|
|
constructor(gateway: string) {
|
|
super(`不支持的支付网关: ${gateway}`, 'GATEWAY_NOT_FOUND');
|
|
this.name = 'GatewayNotFoundError';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 工具函数:元转分
|
|
*/
|
|
export function yuanToFen(yuan: number): number {
|
|
return Math.round(yuan * 100);
|
|
}
|
|
|
|
/**
|
|
* 工具函数:分转元
|
|
*/
|
|
export function fenToYuan(fen: number): number {
|
|
return Math.round(fen) / 100;
|
|
}
|
|
|
|
/**
|
|
* 生成订单号
|
|
* 格式: YYYYMMDD + 6位随机数
|
|
*/
|
|
export function generateOrderSn(prefix = ''): string {
|
|
const date = new Date();
|
|
const dateStr = date.toISOString().slice(0, 10).replace(/-/g, '');
|
|
const random = Math.floor(Math.random() * 1000000).toString().padStart(6, '0');
|
|
return `${prefix}${dateStr}${random}`;
|
|
}
|
|
|
|
/**
|
|
* 生成交易流水号
|
|
* 格式: T + YYYYMMDDHHMMSS + 5位随机数
|
|
*/
|
|
export function generateTradeSn(prefix = 'T'): string {
|
|
const now = new Date();
|
|
const timestamp = now.toISOString()
|
|
.replace(/[-:T]/g, '')
|
|
.slice(0, 14);
|
|
const random = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
|
|
return `${prefix}${timestamp}${random}`;
|
|
}
|