revert: remove fork-only changes from release sync

Revert payment/wechat, sora/claude-max cleanup, fork-only migrations,
and cosmetic changes that were brought in by the release sync commit.
Keep only channel-monitor related improvements:
- PublicSettingsInjectionPayload named struct with drift test
- ChannelMonitorRunner graceful shutdown in wire
- image_output_price in SupportedModelChip
- Simplified buildSelfNavItems in AppSidebar
- Gateway WARN logs for 503 branches
This commit is contained in:
erio
2026-04-23 21:40:58 +08:00
parent a3ea8ecac5
commit 67518a59ac
71 changed files with 1792 additions and 1396 deletions

View File

@@ -1665,6 +1665,8 @@ export default {
failedToLoadApiKeys: 'Failed to load user API keys',
emailRequired: 'Please enter email',
concurrencyMin: 'Concurrency must be at least 1',
soraStorageQuota: 'Sora Storage Quota',
soraStorageQuotaHint: 'In GB, 0 means use group or system default quota',
amountRequired: 'Please enter a valid amount',
insufficientBalance: 'Insufficient balance',
deleteConfirm: "Are you sure you want to delete '{email}'? This action cannot be undone.",
@@ -1997,6 +1999,14 @@ export default {
enabled: 'Enabled',
disabled: 'Disabled'
},
claudeMaxSimulation: {
title: 'Claude Max Usage Simulation',
tooltip:
'When enabled, for Claude models without upstream cache-write usage, the system deterministically maps tokens to a small input plus 1h cache creation while keeping total tokens unchanged.',
enabled: 'Enabled (simulate 1h cache)',
disabled: 'Disabled',
hint: 'Only token categories in usage billing logs are adjusted. No per-request mapping state is persisted.'
},
supportedScopes: {
title: 'Supported Model Families',
tooltip: 'Select the model families this group supports. Unchecked families will not be routed to this group.',
@@ -2630,7 +2640,7 @@ export default {
resetQuota: 'Reset Quota',
quotaLimit: 'Quota Limit',
quotaLimitPlaceholder: '0 means unlimited',
quotaLimitHint: 'Set daily/weekly/total spending limits (USD). Changing limits won\'t reset usage.',
quotaLimitHint: 'Set daily/weekly/total spending limits (USD). Anthropic API key accounts can also configure client affinity. Changing limits won\'t reset usage.',
quotaLimitToggle: 'Enable Quota Limit',
quotaLimitToggleHint: 'When enabled, account will be paused when usage reaches the set limit',
quotaDailyLimit: 'Daily Limit',
@@ -2834,7 +2844,7 @@ export default {
// Quota control (Anthropic OAuth/SetupToken only)
quotaControl: {
title: 'Quota Control',
hint: 'Configure cost windows, session limits and other scheduling controls.',
hint: 'Configure cost window, session limits, client affinity and other scheduling controls.',
windowCost: {
label: '5h Window Cost Limit',
hint: 'Limit account cost usage within the 5-hour window',
@@ -2880,7 +2890,7 @@ export default {
label: 'TLS Fingerprint Simulation',
hint: 'Simulate Node.js/Claude Code client TLS fingerprint',
defaultProfile: 'Built-in Default',
randomProfile: 'Random',
randomProfile: 'Random'
},
sessionIdMasking: {
label: 'Session ID Masking',
@@ -2897,7 +2907,25 @@ export default {
hint: 'Forward requests to a custom relay service. Proxy URL will be passed as a query parameter.',
urlHint: 'Relay service URL (e.g., https://relay.example.com)',
},
clientAffinity: {
label: 'Client Affinity Scheduling',
hint: 'When enabled, new sessions prefer accounts previously used by this client to reduce account switching'
}
},
affinityNoClients: 'No affinity clients',
affinityClients: '{count} affinity clients:',
affinitySection: 'Client Affinity',
affinitySectionHint: 'Control how clients are distributed across accounts. Configure zone thresholds to balance load.',
affinityToggle: 'Enable Client Affinity',
affinityToggleHint: 'New sessions prefer accounts previously used by this client',
affinityBase: 'Base Limit (Green Zone)',
affinityBasePlaceholder: 'Empty = no limit',
affinityBaseHint: 'Max clients in green zone (full priority scheduling)',
affinityBaseOffHint: 'No green zone limit. All clients receive full priority scheduling.',
affinityBuffer: 'Buffer (Yellow Zone)',
affinityBufferPlaceholder: 'e.g. 3',
affinityBufferHint: 'Additional clients allowed in the yellow zone (degraded priority)',
affinityBufferInfinite: 'Unlimited',
expired: 'Expired',
proxy: 'Proxy',
noProxy: 'No Proxy',
@@ -4919,6 +4947,12 @@ export default {
integrationDoc: 'Payment Integration Docs',
integrationDocHint: 'Covers endpoint specs, idempotency semantics, and code samples'
},
soraClient: {
title: 'Sora Client',
description: 'Control whether to show the Sora client entry in the sidebar',
enabled: 'Enable Sora Client',
enabledHint: 'When enabled, the Sora entry will be shown in the sidebar for users to access Sora features'
},
customMenu: {
title: 'Custom Menu Pages',
description: 'Add custom iframe pages to the sidebar navigation. Each page can be visible to regular users or administrators.',
@@ -5010,6 +5044,8 @@ export default {
field_certSerial: 'Certificate Serial',
field_h5AppName: 'H5 App Name',
field_h5AppUrl: 'H5 App URL',
wxpayConfigHint: 'WeChat Pay usually only needs App ID. Fill MP App ID, H5 App Name, and H5 App URL only when your Official Account or H5 flow specifically requires them.',
wxpayAdvancedOptions: 'WeChat Pay Advanced Options',
field_secretKey: 'Secret Key',
field_publishableKey: 'Publishable Key',
field_webhookSecret: 'Webhook Secret',
@@ -5040,6 +5076,37 @@ export default {
providerKey: 'Provider Type',
selectProviderKey: 'Select Provider Type',
providerConfig: 'Credentials',
paymentGuideTrigger: 'View payment guide',
guideOpenLabel: 'Enable: ',
guideCallLabel: 'Call: ',
guideFallbackLabel: 'Fallback: ',
alipayGuideSummary: 'Desktop prefers QR precreate and falls back to cashier; mobile prefers WAP checkout.',
alipayGuideFaceToFaceTitle: 'Face-to-face / QR Payment',
alipayGuideFaceToFaceOpen: 'Enable face-to-face or QR payment capability.',
alipayGuideFaceToFaceCall: 'Desktop orders call alipay.trade.precreate first and render the QR code directly.',
alipayGuideFaceToFaceFallback: 'If unavailable or failed, the flow falls back to website checkout automatically.',
alipayGuidePagePayTitle: 'Website Payment',
alipayGuidePagePayOpen: 'Enable website payment.',
alipayGuidePagePayCall: 'When face-to-face is unavailable on desktop, the flow calls alipay.trade.page.pay and still renders the returned link as a QR code.',
alipayGuidePagePayFallback: 'The cashier link stays available so users can reopen the checkout page manually.',
alipayGuideWapTitle: 'WAP Payment',
alipayGuideWapOpen: 'Enable mobile website payment.',
alipayGuideWapCall: 'Mobile orders call alipay.trade.wap.pay first and jump to Alipay checkout.',
alipayGuideWapFallback: 'If mobile payment is unavailable or fails, the frontend switches to QR payment and shows a notice.',
wxpayGuideSummary: 'Desktop prefers Native QR; mobile routes to JSAPI or H5 based on browser context.',
wxpayGuideNote: 'The current form defaults to one shared App ID, which fits the common single-subject web, mobile, and Official Account setup.',
wxpayGuideNativeTitle: 'Native / QR Payment',
wxpayGuideNativeOpen: 'Enable Native or QR payment capability.',
wxpayGuideNativeCall: 'Desktop orders use Native by default and the frontend renders the QR payload.',
wxpayGuideNativeFallback: 'Mobile flows also fall back here when JSAPI or H5 cannot be used.',
wxpayGuideJsapiTitle: 'JSAPI / Official Account',
wxpayGuideJsapiOpen: 'Enable Official Account payment and ensure the browser is inside WeChat with an available OpenID.',
wxpayGuideJsapiCall: 'Inside WeChat, the app calls JSAPI after authorization and launches WeChat Pay directly.',
wxpayGuideJsapiFallback: 'If configuration is missing, the bridge is unavailable, or launch fails, the flow falls back to QR payment.',
wxpayGuideH5Title: 'H5 Payment',
wxpayGuideH5Open: 'Enable H5 payment.',
wxpayGuideH5Call: 'On mobile browsers outside WeChat, the app calls H5 payment when a client IP is available.',
wxpayGuideH5Fallback: 'If H5 is unavailable or order creation fails, the flow falls back to QR payment.',
noProviders: 'No provider instances configured',
supportedTypes: 'Supported Payment Types',
supportedTypesHint: 'Comma-separated, e.g. alipay,wxpay',
@@ -5138,6 +5205,98 @@ export default {
securityWarning: 'Warning: This key provides full admin access. Keep it secure.',
usage: 'Usage: Add to request header - x-api-key: <your-admin-api-key>'
},
soraS3: {
title: 'Sora Storage',
description: 'Manage Sora media storage profiles with S3 and Google Drive support',
newProfile: 'New Profile',
reloadProfiles: 'Reload Profiles',
empty: 'No storage profiles yet, create one first',
createTitle: 'Create Storage Profile',
editTitle: 'Edit Storage Profile',
selectProvider: 'Select Storage Type',
providerS3Desc: 'S3-compatible object storage',
providerGDriveDesc: 'Google Drive cloud storage',
profileID: 'Profile ID',
profileName: 'Profile Name',
setActive: 'Set as active after creation',
saveProfile: 'Save Profile',
activateProfile: 'Activate',
profileCreated: 'Storage profile created',
profileSaved: 'Storage profile saved',
profileDeleted: 'Storage profile deleted',
profileActivated: 'Active storage profile switched',
profileIDRequired: 'Profile ID is required',
profileNameRequired: 'Profile name is required',
profileSelectRequired: 'Please select a profile first',
endpointRequired: 'S3 endpoint is required when enabled',
bucketRequired: 'Bucket is required when enabled',
accessKeyRequired: 'Access Key ID is required when enabled',
deleteConfirm: 'Delete storage profile {profileID}?',
columns: {
profile: 'Profile',
profileId: 'Profile ID',
name: 'Name',
provider: 'Type',
active: 'Active',
endpoint: 'Endpoint',
bucket: 'Bucket',
storagePath: 'Storage Path',
capacityUsage: 'Capacity / Used',
capacityUnlimited: 'Unlimited',
videoCount: 'Videos',
videoCompleted: 'completed',
videoInProgress: 'in progress',
quota: 'Default Quota',
updatedAt: 'Updated At',
actions: 'Actions',
rootFolder: 'Root folder',
testInTable: 'Test',
testingInTable: 'Testing...',
testTimeout: 'Test timed out (15s)'
},
enabled: 'Enable Storage',
enabledHint: 'When enabled, Sora generated media files will be automatically uploaded',
endpoint: 'S3 Endpoint',
region: 'Region',
bucket: 'Bucket',
prefix: 'Object Prefix',
accessKeyId: 'Access Key ID',
secretAccessKey: 'Secret Access Key',
secretConfigured: '(Configured, leave blank to keep)',
cdnUrl: 'CDN URL',
cdnUrlHint: 'Optional. When configured, files are accessed via CDN URL',
forcePathStyle: 'Force Path Style',
defaultQuota: 'Default Storage Quota',
defaultQuotaHint: 'Default quota when not specified at user or group level. 0 means unlimited',
testConnection: 'Test Connection',
testing: 'Testing...',
testSuccess: 'Connection test successful',
testFailed: 'Connection test failed',
saved: 'Storage settings saved successfully',
saveFailed: 'Failed to save storage settings',
gdrive: {
authType: 'Authentication Method',
serviceAccount: 'Service Account',
clientId: 'Client ID',
clientSecret: 'Client Secret',
clientSecretConfigured: '(Configured, leave blank to keep)',
refreshToken: 'Refresh Token',
refreshTokenConfigured: '(Configured, leave blank to keep)',
serviceAccountJson: 'Service Account JSON',
serviceAccountConfigured: '(Configured, leave blank to keep)',
folderId: 'Folder ID (optional)',
authorize: 'Authorize Google Drive',
authorizeHint: 'Get Refresh Token via OAuth2',
oauthFieldsRequired: 'Please fill in Client ID and Client Secret first',
oauthSuccess: 'Google Drive authorization successful',
oauthFailed: 'Google Drive authorization failed',
closeWindow: 'This window will close automatically',
processing: 'Processing authorization...',
testStorage: 'Test Storage',
testSuccess: 'Google Drive storage test passed (upload, access, delete all OK)',
testFailed: 'Google Drive storage test failed'
}
},
overloadCooldown: {
title: '529 Overload Cooldown',
description: 'Configure account scheduling pause strategy when upstream returns 529 (overloaded)',
@@ -5804,6 +5963,7 @@ export default {
wechatOpenInWeChatHint: 'Open the current page inside WeChat, or switch to desktop WeChat QR payment.',
wechatScanOnDesktopHint: 'On desktop, use WeChat Scan to pay; on mobile, reopen the current page inside WeChat.',
wechatSwitchBrowserHint: 'Switch to desktop WeChat QR payment, or reopen this page in an external browser and retry.',
mobilePaymentFallbackToQr: 'This merchant has not enabled mobile payment. The flow has been switched to QR payment automatically.',
alipayDesktopUnavailable: 'The desktop Alipay flow could not generate a QR code.',
alipayDesktopQrHint: 'Desktop Alipay should render a QR code. Refresh and retry, or make sure the payment page was not blocked.',
alipayMobileUnavailable: 'This page could not hand off to Alipay.',

View File

@@ -1729,6 +1729,8 @@ export default {
failedToAdjust: '调整失败',
emailRequired: '请输入邮箱',
concurrencyMin: '并发数不能小于1',
soraStorageQuota: 'Sora 存储配额',
soraStorageQuotaHint: '单位 GB0 表示使用分组或系统默认配额',
amountRequired: '请输入有效金额',
insufficientBalance: '余额不足',
setAllowedGroups: '设置允许分组',
@@ -2985,7 +2987,7 @@ export default {
// Quota control (Anthropic OAuth/SetupToken only)
quotaControl: {
title: '配额控制',
hint: '配置费用窗口、会话限制等调度控制。',
hint: '配置费用窗口、会话限制、客户端亲和等调度控制。',
windowCost: {
label: '5h窗口费用控制',
hint: '限制账号在5小时窗口内的费用使用',
@@ -3031,7 +3033,7 @@ export default {
label: 'TLS 指纹模拟',
hint: '模拟 Node.js/Claude Code 客户端的 TLS 指纹',
defaultProfile: '内置默认',
randomProfile: '随机',
randomProfile: '随机'
},
sessionIdMasking: {
label: '会话 ID 伪装',
@@ -3048,7 +3050,25 @@ export default {
hint: '启用后将请求转发到自定义中继服务,代理地址将作为 URL 参数传递给中继服务',
urlHint: '中继服务地址(如 https://relay.example.com',
},
clientAffinity: {
label: '客户端亲和调度',
hint: '启用后,新会话会优先调度到该客户端之前使用过的账号,避免频繁切换账号'
}
},
affinityNoClients: '无亲和客户端',
affinityClients: '{count} 个亲和客户端:',
affinitySection: '客户端亲和',
affinitySectionHint: '控制客户端在账号间的分布。通过配置区域阈值来平衡负载。',
affinityToggle: '启用客户端亲和',
affinityToggleHint: '新会话优先调度到该客户端之前使用过的账号',
affinityBase: '基础限额(绿区)',
affinityBasePlaceholder: '留空表示不限制',
affinityBaseHint: '绿区最大客户端数量(完整优先级调度)',
affinityBaseOffHint: '未开启绿区限制,所有客户端均享受完整优先级调度',
affinityBuffer: '缓冲区(黄区)',
affinityBufferPlaceholder: '例如 3',
affinityBufferHint: '黄区允许的额外客户端数量(降级优先级调度)',
affinityBufferInfinite: '不限制',
expired: '已过期',
proxy: '代理',
noProxy: '无代理',
@@ -5091,6 +5111,12 @@ export default {
integrationDoc: '支付集成文档',
integrationDocHint: '包含接口说明、幂等语义及示例代码'
},
soraClient: {
title: 'Sora 客户端',
description: '控制是否在侧边栏展示 Sora 客户端入口',
enabled: '启用 Sora 客户端',
enabledHint: '开启后,侧边栏将显示 Sora 入口,用户可访问 Sora 功能'
},
customMenu: {
title: '自定义菜单页面',
description: '添加自定义 iframe 页面到侧边栏导航。每个页面可以设置为普通用户或管理员可见。',
@@ -5182,6 +5208,8 @@ export default {
field_certSerial: '证书序列号',
field_h5AppName: 'H5 应用名称',
field_h5AppUrl: 'H5 应用地址',
wxpayConfigHint: '微信支付通常只需要填写 App ID。公众号 App ID、H5 应用名称、H5 应用地址仅在公众号支付或 H5 场景有特殊要求时再填写。',
wxpayAdvancedOptions: '微信支付高级可选项',
field_secretKey: '密钥',
field_publishableKey: '公开密钥',
field_webhookSecret: 'Webhook 密钥',
@@ -5212,6 +5240,37 @@ export default {
providerKey: '服务商类型',
selectProviderKey: '选择服务商类型',
providerConfig: '凭证配置',
paymentGuideTrigger: '查看支付方式说明',
guideOpenLabel: '开通:',
guideCallLabel: '调用:',
guideFallbackLabel: '降级:',
alipayGuideSummary: '桌面优先扫码单,失败再走收银台;移动优先手机网站支付。',
alipayGuideFaceToFaceTitle: '当面付 / 扫码支付',
alipayGuideFaceToFaceOpen: '需开通当面付或扫码支付能力。',
alipayGuideFaceToFaceCall: '桌面端下单时优先调用 alipay.trade.precreate前台直接渲染二维码。',
alipayGuideFaceToFaceFallback: '接口不可用或返回失败时,自动降级到电脑网站支付。',
alipayGuidePagePayTitle: '电脑网站支付',
alipayGuidePagePayOpen: '需开通电脑网站支付。',
alipayGuidePagePayCall: '桌面端当面付不可用时调用 alipay.trade.page.pay并继续把返回链接渲染成二维码。',
alipayGuidePagePayFallback: '同时保留打开收银台入口,用户可手动重新拉起支付页。',
alipayGuideWapTitle: '手机网站支付',
alipayGuideWapOpen: '需开通手机网站支付。',
alipayGuideWapCall: '移动端优先调用 alipay.trade.wap.pay跳转支付宝收银台。',
alipayGuideWapFallback: '未开通或返回异常时,前端自动改走扫码支付并提示未开通移动支付。',
wxpayGuideSummary: '桌面优先 Native 扫码,移动端按浏览器环境走 JSAPI 或 H5。',
wxpayGuideNote: '当前表单默认共用一个 App ID适合同主体下统一配置网页、移动和公众号场景。',
wxpayGuideNativeTitle: 'Native / 扫码支付',
wxpayGuideNativeOpen: '需开通 Native 或扫码支付能力。',
wxpayGuideNativeCall: '桌面端默认调用 Native下发二维码内容给前台渲染。',
wxpayGuideNativeFallback: '移动端无法走 JSAPI 或 H5 时,也会自动回退到这里。',
wxpayGuideJsapiTitle: 'JSAPI / 公众号支付',
wxpayGuideJsapiOpen: '需开通公众号支付,并保证当前浏览器在微信内且能拿到 OpenID。',
wxpayGuideJsapiCall: '微信内浏览器完成授权后调用 JSAPI直接拉起微信支付。',
wxpayGuideJsapiFallback: '未配置、Bridge 不可用或拉起失败时,自动改走扫码支付。',
wxpayGuideH5Title: 'H5 支付',
wxpayGuideH5Open: '需开通 H5 支付。',
wxpayGuideH5Call: '移动端非微信浏览器且有客户端 IP 时调用 H5 支付,跳转微信收银台。',
wxpayGuideH5Fallback: '未开通 H5 或下单失败时,自动改走扫码支付。',
noProviders: '暂无服务商实例',
supportedTypes: '支持的支付方式',
supportedTypesHint: '逗号分隔,如 alipay,wxpay',
@@ -5309,6 +5368,98 @@ export default {
securityWarning: '警告:此密钥拥有完整的管理员权限,请妥善保管。',
usage: '使用方法:在请求头中添加 x-api-key: <your-admin-api-key>'
},
soraS3: {
title: 'Sora 存储配置',
description: '以多配置列表管理 Sora 媒体存储,支持 S3 和 Google Drive',
newProfile: '新建配置',
reloadProfiles: '刷新列表',
empty: '暂无存储配置,请先创建',
createTitle: '新建存储配置',
editTitle: '编辑存储配置',
selectProvider: '选择存储类型',
providerS3Desc: 'S3 兼容对象存储',
providerGDriveDesc: 'Google Drive 云盘',
profileID: '配置 ID',
profileName: '配置名称',
setActive: '创建后设为生效',
saveProfile: '保存配置',
activateProfile: '设为生效',
profileCreated: '存储配置创建成功',
profileSaved: '存储配置保存成功',
profileDeleted: '存储配置删除成功',
profileActivated: '生效配置已切换',
profileIDRequired: '请填写配置 ID',
profileNameRequired: '请填写配置名称',
profileSelectRequired: '请先选择配置',
endpointRequired: '启用时必须填写 S3 端点',
bucketRequired: '启用时必须填写存储桶',
accessKeyRequired: '启用时必须填写 Access Key ID',
deleteConfirm: '确定删除存储配置 {profileID} 吗?',
columns: {
profile: '配置',
profileId: 'Profile ID',
name: '名称',
provider: '存储类型',
active: '生效状态',
endpoint: '端点',
bucket: '存储桶',
storagePath: '存储路径',
capacityUsage: '容量 / 已用',
capacityUnlimited: '无限制',
videoCount: '视频数',
videoCompleted: '完成',
videoInProgress: '进行中',
quota: '默认配额',
updatedAt: '更新时间',
actions: '操作',
rootFolder: '根目录',
testInTable: '测试',
testingInTable: '测试中...',
testTimeout: '测试超时15秒'
},
enabled: '启用存储',
enabledHint: '启用后Sora 生成的媒体文件将自动上传到存储',
endpoint: 'S3 端点',
region: '区域',
bucket: '存储桶',
prefix: '对象前缀',
accessKeyId: 'Access Key ID',
secretAccessKey: 'Secret Access Key',
secretConfigured: '(已配置,留空保持不变)',
cdnUrl: 'CDN URL',
cdnUrlHint: '可选,配置后使用 CDN URL 访问文件',
forcePathStyle: '强制路径风格Path Style',
defaultQuota: '默认存储配额',
defaultQuotaHint: '未在用户或分组级别指定配额时的默认值0 表示无限制',
testConnection: '测试连接',
testing: '测试中...',
testSuccess: '连接测试成功',
testFailed: '连接测试失败',
saved: '存储设置保存成功',
saveFailed: '保存存储设置失败',
gdrive: {
authType: '认证方式',
serviceAccount: '服务账号',
clientId: 'Client ID',
clientSecret: 'Client Secret',
clientSecretConfigured: '(已配置,留空保持不变)',
refreshToken: 'Refresh Token',
refreshTokenConfigured: '(已配置,留空保持不变)',
serviceAccountJson: '服务账号 JSON',
serviceAccountConfigured: '(已配置,留空保持不变)',
folderId: 'Folder ID可选',
authorize: '授权 Google Drive',
authorizeHint: '通过 OAuth2 获取 Refresh Token',
oauthFieldsRequired: '请先填写 Client ID 和 Client Secret',
oauthSuccess: 'Google Drive 授权成功',
oauthFailed: 'Google Drive 授权失败',
closeWindow: '此窗口将自动关闭',
processing: '正在处理授权...',
testStorage: '测试存储',
testSuccess: 'Google Drive 存储测试成功(上传、访问、删除均正常)',
testFailed: 'Google Drive 存储测试失败'
}
},
overloadCooldown: {
title: '529 过载冷却',
description: '配置上游返回 529过载时的账号调度暂停策略',
@@ -6000,6 +6151,7 @@ export default {
wechatOpenInWeChatHint: '请复制当前页面链接到微信内打开,或直接改用电脑端微信扫码支付。',
wechatScanOnDesktopHint: '电脑端请直接使用微信扫一扫完成支付;移动端请在微信内打开当前页面。',
wechatSwitchBrowserHint: '请改用电脑端微信扫码,或在外部浏览器重新打开本页后再试。',
mobilePaymentFallbackToQr: '当前商户未开通移动支付,已自动切换为扫码支付。',
alipayDesktopUnavailable: '当前支付宝桌面支付未成功生成二维码。',
alipayDesktopQrHint: '电脑端支付宝应展示扫码单,请刷新后重试,或确认浏览器未拦截当前支付页。',
alipayMobileUnavailable: '当前页面未成功跳转到支付宝。',