Commit Graph

72 Commits

Author SHA1 Message Date
erio
886389939e style: format all files with Prettier 2026-03-14 03:45:37 +08:00
erio
8a5f8662d0 fix: 暗色主题下平台颜色降低亮度,按钮和文字更柔和 2026-03-14 03:09:29 +08:00
erio
8dd0d1144b feat: 页面标题/副标题更新、按钮和倍率跟随平台颜色、messages调度移到标题行、返回按钮统一
1. 标题改为"选择适合你的 充值/订阅服务",副标题改为"充值余额或者订阅套餐"
2. ChannelCard: 按钮bg、倍率数字、额度描述 跟随平台颜色
3. platform-style: 新增 button + accent 字段
4. SubscriptionPlanCard/SubscriptionConfirm: /v1/messages 调度 badge 移到标题行
5. 充值返回按钮样式与订阅确认页统一(灰色+箭头图标)
2026-03-14 02:08:14 +08:00
erio
5ce7ba3cb8 fix: tab名称改为余额充值/套餐订阅、有效期直接显示配置值、模型标签跟随平台颜色
1. MainTabs: "按量付费"→"余额充值","包月套餐"→"套餐订阅"
2. subscription-utils: 去掉所有智能转换,配置什么就显示什么(1月/30天/2周)
3. platform-style: 新增 modelTag 样式字段,每个平台独立颜色
4. ChannelCard: 模型标签颜色跟随平台(橙/绿/蓝/粉/紫)而非统一蓝色
2026-03-14 02:02:03 +08:00
erio
d8078eb38c fix: 有效期30天不再显示"包月"、我的订阅移到tab外、确认订单展示完整信息
1. subscription-utils: day=30 不再特殊处理为"包月",直接显示"30天"
2. pay page: "我的订阅"移到 tab 外部,按量付费和包月套餐下都可见
3. SubscriptionConfirm: 展示平台badge、倍率、限额grid、OpenAI messages调度信息
2026-03-14 01:57:09 +08:00
erio
aeaa09d2c1 fix: searchUsers 也修复分页响应解析(data.data.items) 2026-03-14 01:47:57 +08:00
erio
10e9189bcb fix: 修复订阅列表API响应解析和管理后台messages调度字段缺失
1. listSubscriptions 解析 data.data.items 而非 data.data(Sub2API分页格式)
2. 管理后台套餐API返回 groupAllowMessagesDispatch 和 groupDefaultMappedModel
2026-03-14 01:46:37 +08:00
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
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
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
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) 2026-03-10 18:20:36 +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
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>
2026-03-09 18:33:57 +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
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
37096de05c Merge branch 'worktree-agent-a5caa164' 2026-03-07 04:16:26 +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
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
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
d46793f072 feat: 支付宝直连 H5 端使用 wap.pay 唤起支付宝 APP
前端传递 is_mobile 参数,AlipayProvider 根据设备类型选择:
- PC: alipay.trade.page.pay (FAST_INSTANT_TRADE_PAY)
- H5: alipay.trade.wap.pay (QUICK_WAP_WAY)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:04:11 +08:00
erio
94d25ddc31 refactor: 移除 ENABLED_PAYMENT_TYPES,支付类型由 PAYMENT_PROVIDERS 自动推导
PAYMENT_PROVIDERS 配置提供商后,各 provider 的 supportedTypes 自动注册为可用支付类型,
无需再手动配置 ENABLED_PAYMENT_TYPES。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:53:47 +08:00
erio
254ead1908 refactor: 常量化订单状态 + 支付渠道/提供商分离显示 + H5自动跳转
- 新增 src/lib/constants.ts,集中管理 ORDER_STATUS / PAYMENT_TYPE / PAYMENT_PREFIX 等常量
- 后端 service/status/timeout/limits 全量替换魔法字符串为 ORDER_STATUS.*
- PaymentTypeMeta 新增 provider 字段,分离 sublabel(选择器展示)与 provider(提供商名称)
- getPaymentDisplayInfo() 返回 { channel, provider } 用于用户端/管理端展示
- 支持通过 PAYMENT_SUBLABEL_* 环境变量覆盖默认 sublabel
- PaymentQRCode: H5 支付自动跳转(含易支付微信 weixin:// scheme 兜底)
- 订单列表/详情页:显示可读的渠道名+提供商,不再暴露内部标识符

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:34:42 +08:00
erio
3829d0e52e refactor: 将支付类型硬编码抽取到 pay-utils 统一管理
- PaymentTypeMeta 新增 iconSrc、chartBar、buttonClass 字段
- 新增工具函数: getPaymentMeta、getPaymentIconSrc、
  getPaymentChannelLabel、isStripeType、isRedirectPayment 等
- PaymentQRCode: 用 meta/工具函数替换散落的颜色和类型判断
- PaymentForm: 提交按钮颜色改用 meta.buttonClass
- PaymentMethodChart: 删除重复的 TYPE_CONFIG,改用 getPaymentMeta
- stripe-popup: 按钮颜色改用 meta.buttonClass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:46:36 +08:00
erio
ad6b63dd9e fix: 修复支付宝签名时错误排除 sign_type 导致 invalid-signature
支付宝验签字符串包含 sign_type 字段,但 generateSign 错误地
将 sign_type 与 sign 一起排除。只需排除 sign,保留 sign_type。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:14:52 +08:00
erio
0763d72a89 fix: 各支付 provider 自行获取 notifyUrl/returnUrl
service.ts 不再硬编码传 EASY_PAY 的 notify/return URL,
避免官方支付宝错误使用 EasyPay 的回调地址导致签名失败。
2026-03-06 15:49:54 +08:00
erio
f53aa9e14c feat: 支持官方支付宝与易支付支付宝同时展示
- PaymentType 改为 string 类型,支持复合 key(如 alipay_direct)
- 官方支付宝注册为 alipay_direct,易支付保持 alipay/wxpay
- 前端按 PAYMENT_TYPE_META 展示标签区分(官方直连/易支付)
- 管理后台显示统一改为 getPaymentTypeLabel 通用映射
- 修复 admin/OrderTable 中 wechat 拼写错误
2026-03-06 15:33:22 +08:00
erio
01d5a0b3c4 feat: 支付宝密钥支持文件路径配置
ALIPAY_PRIVATE_KEY / ALIPAY_PUBLIC_KEY 可直接填密钥内容,
也可填文件路径,代码自动检测并读取文件。
2026-03-06 15:11:47 +08:00
erio
cba8acdd60 refactor: 微信支付命名从 Native 改为 PC扫码,统一术语
- WxpayNativeOrderParams → WxpayPcOrderParams
- createNativeOrder → createPcOrder
- 文档注释统一为「PC扫码 / H5」
2026-03-06 14:31:43 +08:00
erio
b0f1daf469 fix: 修复微信支付 Native/H5 判断逻辑,改为前端设备检测驱动
- 修复 clientIp 始终存在导致永远走 H5 的 bug,改用 isMobile 判断
- 前端通过 detectDeviceIsMobile() 传 is_mobile 给后端
- ENABLED_PAYMENT_TYPES 默认改为空,必须显式配置才启用
- 补充 .env.example 配置说明
2026-03-06 14:04:51 +08:00
erio
937f54dec2 feat: 集成微信支付直连(Native + H5)及金融级安全修复
- 新增 wxpay provider(wechatpay-node-v3 SDK),支持 Native 扫码和 H5 跳转
- 新增 /api/wxpay/notify 回调路由,AES-256-GCM 解密 + RSA 签名验证
- 修复 confirmPayment count=0 静默成功、充值失败返回 true 等 P0 问题
- 修复 notifyUrl 硬编码 easypay、回调金额覆盖订单金额等 P1 问题
- 手续费计算改用 Prisma.Decimal 精确运算,消除浮点误差
- 支付宝 provider 移除冗余 paramsForVerify,fetch 添加超时
- 补充 .env.example 配置文档和 CLAUDE.md 支付渠道说明
2026-03-06 13:57:52 +08:00
erio
0a35ba9002 style: 全量 prettier 格式化 2026-03-05 23:10:44 +08:00
erio
448d36fe2b feat: 移动端 H5 支付跳转 + 改进移动端检测
- PaymentQRCode: 移动端有 payUrl 时直接跳转支付,iframe 中新窗口打开
- detectDeviceIsMobile: 优先使用 navigator.userAgentData.mobile API
2026-03-05 16:21:12 +08:00
erio
8746f474d1 refactor: 支付宝 providerKey 改为 alipay 2026-03-05 01:52:59 +08:00