feat(client): App 内在线购买/续费授权(管理员支付宝下单+到账轮询)
- 新增套餐目录 license_plans.dart(标准/高级 × 月付/年付,与官网 checkout 一致) - license 模型/仓库新增 PurchaseOrder/PurchaseStatusInfo 与下单、查单接口 - 系统设置授权面板:管理员显示「在线购买 / 续费」按钮,弹窗选套餐→ 外部浏览器打开支付宝收银台→3s 轮询到账→自动刷新授权并展示新到期日 - 用户手册(docs.md + user-manual.html)同步补充在线购买入口说明 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
@@ -64,3 +64,57 @@ class LicenseInfo {
|
||||
bool get needsAttention =>
|
||||
phase == 'grace' || phase == 'readonly' || phase == 'locked';
|
||||
}
|
||||
|
||||
/// POST /license/purchase 响应:pay 收银台跳转信息。
|
||||
class PurchaseOrder {
|
||||
final String payUrl;
|
||||
final String outTradeNo;
|
||||
final String amount; // 实付金额(pay 侧权威价,如 "2999.00")
|
||||
final String subject;
|
||||
|
||||
const PurchaseOrder({
|
||||
required this.payUrl,
|
||||
required this.outTradeNo,
|
||||
required this.amount,
|
||||
required this.subject,
|
||||
});
|
||||
|
||||
factory PurchaseOrder.fromJson(Map<String, dynamic> json) => PurchaseOrder(
|
||||
payUrl: json['pay_url'] as String? ?? '',
|
||||
outTradeNo: json['out_trade_no'] as String? ?? '',
|
||||
amount: json['amount'] as String? ?? '',
|
||||
subject: json['subject'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
/// GET /license/purchase/:otn 响应:购买单状态(到账轮询用)。
|
||||
class PurchaseStatusInfo {
|
||||
final String outTradeNo;
|
||||
final String status; // pending | paid | failed
|
||||
final String amount;
|
||||
final DateTime? paidAt;
|
||||
final DateTime? expiresAt; // 续期后的门店授权到期时间(仅 paid 时有值)
|
||||
|
||||
const PurchaseStatusInfo({
|
||||
required this.outTradeNo,
|
||||
required this.status,
|
||||
required this.amount,
|
||||
this.paidAt,
|
||||
this.expiresAt,
|
||||
});
|
||||
|
||||
bool get isPaid => status == 'paid';
|
||||
|
||||
factory PurchaseStatusInfo.fromJson(Map<String, dynamic> json) =>
|
||||
PurchaseStatusInfo(
|
||||
outTradeNo: json['out_trade_no'] as String? ?? '',
|
||||
status: json['status'] as String? ?? 'pending',
|
||||
amount: json['amount'] as String? ?? '',
|
||||
paidAt: json['paid_at'] != null
|
||||
? DateTime.tryParse(json['paid_at'] as String)
|
||||
: null,
|
||||
expiresAt: json['expires_at'] != null
|
||||
? DateTime.tryParse(json['expires_at'] as String)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user