Commit Graph

134 Commits

Author SHA1 Message Date
erio
1218b31461 feat: 订阅套餐展示优化、平台图标、默认月、用户订阅查询
- 新建共享平台样式模块 platform-style.ts,含各平台 SVG 图标 + 彩色 badge
- SubscriptionPlanCard 重设计:平台图标 badge、倍率/限额 grid 展示、OpenAI messages 调度信息
- UserSubscriptions 显示 group_name + 平台 badge
- ChannelCard 复用共享平台样式模块
- 管理后台:新建套餐默认 1 月、去掉模型展示、平台图标 badge、OpenAI 信息
- 管理后台用户订阅 tab 默认查询所有订阅(user_id 可选)
- Sub2API client 新增 listSubscriptions 函数
- API 返回 allowMessagesDispatch / defaultMappedModel / group_name / platform
2026-03-14 01:23:21 +08:00
erio
10e3e445ed fix: EasyPay支付回调缺少access_token导致结果页显示"凭证缺失"
EasyPay provider未将动态returnUrl传递给底层client,
导致return_url使用静态环境变量,不含order_id和access_token参数。
2026-03-14 01:07:33 +08:00
erio
ce223f09d8 fix: 所有支付入口关闭时正确显示"入口未开放"提示
当没有可用支付方式(未配置或被禁用)且没有订阅套餐时,
显示"充值/订阅 入口未开放"提示,而不是空的订阅UI
2026-03-14 00:54:05 +08:00
erio
405fab8c8d fix: Dockerfile ADMIN_TOKEN dummy value too short for zod validation 2026-03-14 00:47:21 +08:00
erio
6c61c3f877 feat: 订阅管理增强、商品名称配置、余额充值开关
- R1: 用户订阅搜索改为模糊关键词(邮箱/用户名/备注/APIKey)
- R2: "分组状态"列名改为"Sub2API 状态"
- R3: 订阅套餐可配置支付商品名称(productName)
- R4: 订阅订单校验 subscription_type 必须为 subscription
- R5: 渠道管理配置余额充值商品名前缀/后缀
- R6: 渠道管理可关闭余额充值,前端隐藏入口,API 拒绝
- R7: 所有入口关闭时显示"入口被管理员关闭"提示
- fix: easy-pay client 测试 mock 方式修复(vi.fn + 参数快照)
2026-03-14 00:43:00 +08:00
erio
1bb11ee32b feat: 金额上限校验、订阅详情展示优化、支付商品名称区分
- 硬编码 MAX_AMOUNT=99999999.99,所有金额输入(API+前端)统一校验上限
- 管理后台订阅列表改为卡片布局,Sub2API 分组信息嵌套只读展示(平台/倍率/限额/模型)
- 用户端套餐卡片和确认页展示平台、倍率、用量限制
- 订阅订单支付商品名改为 "Sub2API 订阅 {分组名}",余额充值保持原格式
2026-03-13 23:40:23 +08:00
erio
ca03a501f2 fix: 全面安全审计修复
安全加固:
- 系统配置 API 增加写入 key 白名单,防止任意配置注入
- ADMIN_TOKEN 最小长度要求 16 字符
- 补充安全响应头(X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
- /api/users/[id] 和 /api/limits 增加 token 鉴权
- console.error 敏感信息脱敏(config route)
- 敏感值 mask 修复短值完全隐藏

输入校验:
- admin 渠道接口校验 rate_multiplier > 0、sort_order >= 0、name 非空
- admin 订阅套餐接口校验 price > 0、validity_days > 0、sort_order >= 0

金额精度:
- feeRate 字段精度从 Decimal(5,2) 提升到 Decimal(5,4)
- calculatePayAmount 返回 string 避免 Number 中间转换精度丢失
- 支付宝查询订单增加金额有效性校验(isFinite && > 0)

UI 统一:
- 订阅管理「售卖」列改为 toggle switch 开关(与渠道管理一致)
- 表单中 checkbox 改为 toggle switch
- 列名统一为「启用售卖」,支持直接点击切换
2026-03-13 23:03:01 +08:00
erio
38156bd4ef fix: 订阅套餐 API features 字段序列化及返回格式修复
- POST/PUT 写入前 JSON.stringify(features),修复数组写入 TEXT 列报错
- GET/POST/PUT 返回时统一字段映射(validDays/enabled/groupName/features 数组)
2026-03-13 22:30:20 +08:00
erio
bc9ae8370c fix: /admin 直接显示数据概览,去掉管理首页导航项 2026-03-13 22:15:19 +08:00
erio
b1c90d4b04 refactor: /admin 聚合入口(数据概览优先),订单管理移至 /admin/orders 2026-03-13 22:08:14 +08:00
erio
41f7059585 revert: 去掉总览入口,/admin 直接显示订单管理 2026-03-13 22:03:06 +08:00
erio
1399cd277b refactor: /admin 改为聚合入口页面,订单管理移至 /admin/orders
- 新建 /admin/orders 页面(原 /admin 订单管理内容)
- /admin 重写为卡片式导航入口(订单/数据/渠道/订阅)
- 导航栏新增"总览"项,更新所有交叉引用链接
- README 管理后台章节同步更新
2026-03-13 21:54:37 +08:00
erio
687336cfd8 feat: 套餐有效期支持日/周/月单位,订阅履约改用兑换码流程,UI层次感优化
- Prisma: SubscriptionPlan 新增 validityUnit 字段 (day/week/month)
- 新增 subscription-utils.ts 计算实际天数及格式化显示
- Sub2API client createAndRedeem 支持 subscription 类型 (group_id, validity_days)
- 订阅履约从 assignSubscription 改为 createAndRedeem,在 Sub2API 留痕
- 订单创建动态计算天数(月单位按自然月差值)
- 管理后台表单支持有效期数值+单位下拉
- 前端 ChannelCard 渠道卡片视觉层次优化(模型标签渐变、倍率突出、闪电图标)
- 按量付费 banner 改为渐变背景+底部倍率说明标签
- 帮助/客服信息区块添加到充值、订阅、支付全流程页面
- 移除系统配置独立页面入口,subscriptions API 返回用户信息
2026-03-13 21:19:22 +08:00
erio
9096271307 fix: 禁止所有模态框点击外部关闭,防止数据丢失
移除 channels 编辑/同步、TopUpModal、OrderDetail、RefundDialog
四处模态框 backdrop 上的 onClick 关闭行为及 stopPropagation,
用户只能通过显式关闭按钮或取消按钮关闭弹窗。

同时新增支付宝直连和微信支付直连接入文档。
2026-03-13 19:51:20 +08:00
erio
eafb7e49fa feat: 渠道展示、订阅套餐、系统配置全功能
- 新增 Channel / SubscriptionPlan / SystemConfig 三个数据模型
- Order 模型扩展支持订阅订单(order_type, plan_id, subscription_group_id)
- Sub2API client 新增分组查询、订阅分配/续期、用户订阅查询
- 订单服务支持订阅履约流程(CAS 锁 + 分组消失安全处理)
- 管理后台:渠道管理、订阅套餐管理、系统配置、Sub2API 分组同步
- 用户页面:双 Tab UI(按量付费/包月订阅)、渠道卡片、充值弹窗、订阅确认
- PaymentForm 支持 fixedAmount 固定金额模式
- 订单状态 API 返回 failedReason 用于订阅异常展示
- 数据库迁移脚本
2026-03-13 19:06:25 +08:00
erio
9f621713c3 style: 统一代码格式 (prettier) v1.9.1 2026-03-10 18:20:36 +08:00
erio
abff49222b fix: 修复 OrderStatus ref 赋值导致 ESLint react-hooks/refs 报错
将 onStateChangeRef.current 赋值从渲染阶段移入 useEffect
2026-03-10 18:18:58 +08:00
erio
1cb82d8fd7 fix: 消除 buildOrderStatusUrl 重复定义,修复轮询回调引用稳定性
- 将 buildOrderStatusUrl 提取到 status-url.ts(客户端安全模块),
  删除 OrderStatus/PaymentQRCode/result 三处重复定义
- OrderStatus.tsx 轮询 effect 使用 useRef 保存 onStateChange,
  避免非 memoized 回调导致定时器不断重建
- result/page.tsx 增加 accessToken 最小长度校验,
  避免无效参数触发无意义的 API 请求
2026-03-10 14:31:26 +08:00
eriol touwa
d6973256a7 Merge pull request #7 from daguimu/feat/alipay-shortlink-notify-fixes
fix: harden alipay direct pay flow
2026-03-10 14:27:06 +08:00
daguimu
8b10bc3bd5 fix: harden alipay direct pay flow 2026-03-10 11:52:37 +08:00
erio
2492031e13 feat: 全站多语言支持 (i18n),lang=en 显示英文,其余默认中文
新增 src/lib/locale.ts 作为统一多语言入口,覆盖前台支付链路、
管理后台、API/服务层错误文案,共 35 个文件。URL 参数 lang 全链路透传,
包括 Stripe return_url、页面跳转、layout html lang 属性等。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v1.8.0
2026-03-09 18:33:57 +08:00
erio
5cebe85079 fix: 用户端订单列表只显示支付渠道,不显示提供商
管理后台仍保留提供商信息显示
2026-03-09 11:32:50 +08:00
erio
5fb16f0ccf fix: 暗色模式下支付方式选中时文字与背景色冲突不可见 2026-03-09 10:12:05 +08:00
erio
43e116a4f2 Revert "fix: 各支付渠道默认单笔限额从 1000 提升至 100000,每日限额改为不限"
This reverts commit e1788437c9.
2026-03-08 00:06:23 +08:00
erio
e1788437c9 fix: 各支付渠道默认单笔限额从 1000 提升至 100000,每日限额改为不限
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 00:03:01 +08:00
erio
2df040e9b9 docs: 更新 EASY_PAY_RETURN_URL 为 /pay/result
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 17:01:12 +08:00
erio
8a465ae625 feat: 支付结果页增加 5 秒倒计时自动返回和手动返回按钮
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 16:55:49 +08:00
erio
1d19fc86ee fix: Dockerfile 构建时注入 dummy 环境变量避免预渲染报错
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:31:36 +08:00
erio
f50a180ec4 fix: 微信支付回调验签 PEM 格式自动补全,Stripe webhook 失败重试
- wxpay client: 添加 formatPublicKey() 自动包裹 PEM 头尾,修复裸 base64 公钥导致的 DECODER routines::unsupported 错误
- stripe webhook: 处理失败时返回 500 让 Stripe 重试
- 修正支付宝测试用例与实际代码对齐

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:27:38 +08:00
erio
698df1ee47 Merge branch 'worktree-agent-afaec22d' 2026-03-07 04:16:38 +08:00
erio
37096de05c Merge branch 'worktree-agent-a5caa164' 2026-03-07 04:16:26 +08:00
erio
d43b04cb5c fix: 前端暗色模式补全、Unicode 可读化、UI 优化 12 项
- PaymentQRCode 13 处 Unicode 转义替换为可读中文
- RefundDialog 完整暗色模式 + Escape 键关闭
- PayResult 页面添加暗色模式支持
- OrderStatus 使用 dark prop 调整样式
- PaymentForm 选中态暗色对比度修复
- OrderDetail 英文标签改中文 + Escape 键
- Pay 页面错误提示暗色适配
- 倒计时最后 60 秒脉动提醒
- 全局 CSS 添加中文字体栈
- MobileOrderList HTML 实体替换

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:16:01 +08:00
erio
ac0772b0f4 fix: API 路由安全加固与架构优化 — 认证、错误处理、Registry 统一
- /api/user 添加 token 认证,防止用户枚举
- Admin token 支持 Authorization header
- /api/orders/my 区分认证失败和服务端错误
- Admin orders userId/date 参数校验
- Decimal 字段统一 Number() 转换
- 抽取 handleApiError/extractHeaders 工具函数
- Webhook 路由改用 Registry 获取 Provider
- PaymentRegistry lazy init 自动初始化

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:15:54 +08:00
erio
4b013370b9 fix: 后端资金安全修复 — 金额覆盖、过期订单、退款原子性等 9 项
- confirmPayment 不再覆盖 amount,实付金额写入 payAmount
- EXPIRED 订单增加 5 分钟宽限窗口
- 退款流程先扣余额再退款,失败可回滚
- 支付宝签名过滤 sign_type
- executeRecharge 使用 CAS 更新
- createOrder rechargeCode 事务保护
- EasyPay/Sub2API client 添加 10s 超时
- db.ts 统一从 getEnv() 获取 DATABASE_URL
- 添加 paymentType+paidAt 复合索引

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:15:48 +08:00
erio
a5e07edda6 fix: PC 端易支付优先显示二维码;订单页移除 user_id 依赖改用 token
- PaymentQRCode: PC 端有 qrCode 时不跳转,优先展示二维码
- /pay/orders: 移除 user_id 参数,统一通过 token 认证

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v1.7.0
2026-03-07 01:59:43 +08:00
erio
7627066549 fix: 官方支付未配置时 notify 路由静默返回成功,避免错误日志
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:07:56 +08:00
erio
387bc96fc9 feat: 创建订单必须通过 token 认证,移除 user_id 参数
- POST /api/orders 改为通过 token 解析用户身份,移除 user_id
- 前端不再从 URL 读取 user_id,完全依赖 token
- 前端提交前检查 pending 订单数量,超过 3 个禁止提交并提示
- 后端 createOrder 保留 MAX_PENDING_ORDERS=3 的服务端校验
- PaymentForm 增加 pendingBlocked 状态提示和按钮禁用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:05:12 +08:00
erio
e846cc1cce feat: sublabel 智能显示 — 仅同名渠道冲突时自动标记
- 默认去掉所有渠道的 sublabel
- 当多个启用渠道有相同显示名(如支付宝+支付宝)时,
  自动用 provider 名标记区分
- 用户手动配置的 PAYMENT_SUBLABEL_* 优先级最高
- 管理后台 getPaymentTypeLabel 自动检测同名并区分

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:58:10 +08:00
erio
bdf2577f28 fix: 支付安全审核修复(支付宝+微信)
支付宝:
- 回调增加 app_id 校验,防止跨商户通知
- 回调增加 sign_type 过滤,仅接受 RSA2
- 退款增加 out_request_no 保证幂等
- 金额解析增加精度保护
- timestamp 改用 CST 时区

微信:
- 自行实现 AES-GCM 解密替代库的 decipher_gcm(修复 AuthTag 未验证)
- WXPAY_PUBLIC_KEY_ID 改为必填
- serial 匹配检查改为强制
- 时间戳校验移到签名验证之前
- nonce 改用 crypto.randomBytes
- publicKey 不允许空 Buffer fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:57:55 +08:00
erio
5253bc8d35 fix: 支付宝 H5 下单失败时 fallback 到 PC 页面支付
与微信支付保持一致的 fallback 策略。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:40:09 +08:00
erio
e2a6895bb7 fix: H5 fallback 仅在 NO_AUTH 时触发,其他错误正常抛出
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:35:23 +08:00
erio
0c6c6e0ea6 fix: 微信 H5 支付未开通时 fallback 到 Native 扫码
移动端尝试 H5 下单失败时自动降级为 Native 二维码模式,
避免因 H5 权限未开通导致支付不可用。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:34:57 +08:00
erio
918750047a Revert "fix: 微信支付暂时统一使用 Native 扫码模式"
This reverts commit ef1078279a.
2026-03-06 22:32:53 +08:00
erio
ef1078279a fix: 微信支付暂时统一使用 Native 扫码模式
H5 支付需要在微信商户平台单独开通权限,当前未开通会报
NO_AUTH 错误。暂时移动端也走 Native 二维码,待 H5 权限
开通后再恢复。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:32:13 +08:00
erio
225f2e0c5a fix: 微信支付回调验签改用公钥直接验证
wechatpay-node-v3 的 verifySign 会尝试拉取平台证书,
但我们使用的是微信支付公钥模式,不需要平台证书。
改用 crypto.createVerify 直接用公钥做 RSA-SHA256 验签。
同时增加 serial 与 WXPAY_PUBLIC_KEY_ID 的匹配校验。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:25:58 +08:00
erio
96962ec38e fix: 微信支付密钥支持文件路径自动解析
在 getEnv() 中对 WXPAY_PRIVATE_KEY 和 WXPAY_PUBLIC_KEY 调用
resolveKeyValue(),与支付宝保持一致,支持通过文件路径配置密钥。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:10:50 +08:00
erio
137a780269 refactor: 简化支付展示逻辑 - 有 payUrl 直接跳转,有 qrCode 显示二维码
移除 isRedirectPayment / mobileRedirectUrl 等支付类型判断,
前端只根据后端返回的字段决定行为:
- payUrl → 自动跳转,无需确认
- qrCode → 展示二维码 + 中心图标
- clientSecret → Stripe 嵌入式表单

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:13:06 +08:00
erio
7be0614c7d fix: wxpay_direct supportedTypes 修正,避免与易支付 wxpay 冲突
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:05:21 +08:00
erio
7cab333213 merge: 合并 wxpay_direct 微信支付直连分支
解决冲突:保留 main 的常量化/provider 字段/ENABLED_PAYMENT_TYPES 移除,
合并 worktree 的微信支付直连实现、notifyUrl/returnUrl 传递、签名验证优化。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:00:16 +08:00
erio
e72325140b style: 移动端支付方式选择器改为两列网格布局
避免三个选项挤在一行,移动端使用 grid-cols-2,PC 端保持 flex 等宽一行。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:54:28 +08:00