mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
feat(payment): auto-fill callback URLs + complete provider config fields
- notifyUrl/returnUrl auto-fill with current domain + webhook path on create
- Default paths: /api/v1/payment/webhook/{provider} and /payment/result
- Add missing EasyPay config: cid, cidAlipay, cidWxpay (optional channel IDs)
- Stripe: show webhook URL hint with copyable endpoint below config
- Fields with defaults show placeholder text for reference
- Also apply defaults when switching provider type in dialog
This commit is contained in:
@@ -4372,6 +4372,10 @@ export default {
|
||||
field_secretKey: 'Secret Key',
|
||||
field_publishableKey: 'Publishable Key',
|
||||
field_webhookSecret: 'Webhook Secret',
|
||||
field_cid: 'Channel ID',
|
||||
field_cidAlipay: 'Alipay Channel ID',
|
||||
field_cidWxpay: 'WeChat Channel ID',
|
||||
stripeWebhookHint: 'Configure the following URL as a Webhook endpoint in Stripe Dashboard:',
|
||||
productNamePrefix: 'Product Name Prefix',
|
||||
productNameSuffix: 'Product Name Suffix',
|
||||
preview: 'Preview',
|
||||
|
||||
@@ -4545,6 +4545,10 @@ export default {
|
||||
field_secretKey: '密钥',
|
||||
field_publishableKey: '公开密钥',
|
||||
field_webhookSecret: 'Webhook 密钥',
|
||||
field_cid: '支付渠道 ID',
|
||||
field_cidAlipay: '支付宝渠道 ID',
|
||||
field_cidWxpay: '微信渠道 ID',
|
||||
stripeWebhookHint: '请在 Stripe Dashboard 中将以下地址配置为 Webhook 端点:',
|
||||
productNamePrefix: '商品名前缀',
|
||||
productNameSuffix: '商品名后缀',
|
||||
preview: '预览',
|
||||
|
||||
@@ -1830,9 +1830,16 @@
|
||||
<div v-for="field in currentProviderFields" :key="field.key">
|
||||
<label class="input-label">{{ field.label }} <span v-if="field.optional" class="text-xs text-gray-400">({{ t('common.optional') }})</span><span v-else class="text-red-500"> *</span></label>
|
||||
<textarea v-if="field.sensitive && field.key.toLowerCase().includes('key') && field.key !== 'pkey'" v-model="providerConfig[field.key]" rows="3" class="input font-mono text-xs" :required="!field.optional && !editingProvider" />
|
||||
<input v-else :type="field.sensitive ? 'password' : 'text'" v-model="providerConfig[field.key]" class="input" :required="!field.optional && !editingProvider" />
|
||||
<input v-else :type="field.sensitive ? 'password' : 'text'" v-model="providerConfig[field.key]" class="input" :required="!field.optional && !editingProvider" :placeholder="field.defaultValue || ''" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Stripe webhook URL hint -->
|
||||
<div v-if="stripeWebhookHint" class="mt-3 rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-800/50 dark:bg-blue-900/20">
|
||||
<p class="text-xs text-blue-700 dark:text-blue-300">
|
||||
{{ t('admin.settings.payment.stripeWebhookHint') }}
|
||||
</p>
|
||||
<code class="mt-1 block break-all rounded bg-blue-100 px-2 py-1 text-xs text-blue-800 dark:bg-blue-900/40 dark:text-blue-200">{{ stripeWebhookHint }}</code>
|
||||
</div>
|
||||
<div v-if="!currentProviderFields.length" class="text-sm text-gray-500 dark:text-gray-400">{{ t('admin.settings.payment.selectProviderKey') }}</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -2979,22 +2986,36 @@ interface ConfigFieldDef {
|
||||
label: string
|
||||
sensitive: boolean
|
||||
optional?: boolean
|
||||
defaultValue?: string // auto-fill value for new providers
|
||||
hint?: string // hint text shown below the field
|
||||
}
|
||||
|
||||
const baseURL = window.location.origin
|
||||
const WEBHOOK_PATHS: Record<string, string> = {
|
||||
easypay: '/api/v1/payment/webhook/easypay',
|
||||
alipay: '/api/v1/payment/webhook/alipay',
|
||||
wxpay: '/api/v1/payment/webhook/wxpay',
|
||||
stripe: '/api/v1/payment/webhook/stripe',
|
||||
}
|
||||
const RETURN_PATH = '/payment/result'
|
||||
|
||||
const PROVIDER_CONFIG_FIELDS: Record<string, ConfigFieldDef[]> = {
|
||||
easypay: [
|
||||
{ key: 'pid', label: 'PID', sensitive: false },
|
||||
{ key: 'pkey', label: 'PKey', sensitive: true },
|
||||
{ key: 'apiBase', label: '', sensitive: false },
|
||||
{ key: 'notifyUrl', label: '', sensitive: false },
|
||||
{ key: 'returnUrl', label: '', sensitive: false },
|
||||
{ key: 'notifyUrl', label: '', sensitive: false, defaultValue: baseURL + WEBHOOK_PATHS.easypay },
|
||||
{ key: 'returnUrl', label: '', sensitive: false, defaultValue: baseURL + RETURN_PATH },
|
||||
{ key: 'cid', label: '', sensitive: false, optional: true },
|
||||
{ key: 'cidAlipay', label: '', sensitive: false, optional: true },
|
||||
{ key: 'cidWxpay', label: '', sensitive: false, optional: true },
|
||||
],
|
||||
alipay: [
|
||||
{ key: 'appId', label: 'App ID', sensitive: false },
|
||||
{ key: 'privateKey', label: '', sensitive: true },
|
||||
{ key: 'publicKey', label: '', sensitive: true },
|
||||
{ key: 'notifyUrl', label: '', sensitive: false },
|
||||
{ key: 'returnUrl', label: '', sensitive: false },
|
||||
{ key: 'notifyUrl', label: '', sensitive: false, defaultValue: baseURL + WEBHOOK_PATHS.alipay },
|
||||
{ key: 'returnUrl', label: '', sensitive: false, defaultValue: baseURL + RETURN_PATH },
|
||||
],
|
||||
wxpay: [
|
||||
{ key: 'appId', label: 'App ID', sensitive: false },
|
||||
@@ -3004,7 +3025,7 @@ const PROVIDER_CONFIG_FIELDS: Record<string, ConfigFieldDef[]> = {
|
||||
{ key: 'publicKey', label: '', sensitive: true },
|
||||
{ key: 'publicKeyId', label: '', sensitive: false, optional: true },
|
||||
{ key: 'certSerial', label: '', sensitive: false, optional: true },
|
||||
{ key: 'notifyUrl', label: '', sensitive: false },
|
||||
{ key: 'notifyUrl', label: '', sensitive: false, defaultValue: baseURL + WEBHOOK_PATHS.wxpay },
|
||||
],
|
||||
stripe: [
|
||||
{ key: 'secretKey', label: '', sensitive: true },
|
||||
@@ -3013,6 +3034,13 @@ const PROVIDER_CONFIG_FIELDS: Record<string, ConfigFieldDef[]> = {
|
||||
],
|
||||
}
|
||||
|
||||
// Stripe webhook URL hint (shown below the config section)
|
||||
const stripeWebhookHint = computed(() =>
|
||||
providerForm.provider_key === 'stripe'
|
||||
? baseURL + WEBHOOK_PATHS.stripe
|
||||
: ''
|
||||
)
|
||||
|
||||
const currentProviderFields = computed(() => {
|
||||
const fields = PROVIDER_CONFIG_FIELDS[providerForm.provider_key] || []
|
||||
return fields.map(f => ({
|
||||
@@ -3081,6 +3109,9 @@ function toggleProviderSupportedType(type: string) {
|
||||
function onProviderKeyChange() {
|
||||
// Auto-select all supported types for the new provider key
|
||||
providerForm.supported_types = (PROVIDER_SUPPORTED_TYPES[providerForm.provider_key] || []).join(',')
|
||||
// Clear config and re-apply defaults
|
||||
Object.keys(providerConfig).forEach(k => delete providerConfig[k])
|
||||
applyConfigDefaults(providerForm.provider_key)
|
||||
}
|
||||
|
||||
function providerKeyLabel(key: string): string {
|
||||
@@ -3137,6 +3168,17 @@ function resetProviderForm() {
|
||||
providerForm.supported_types = (PROVIDER_SUPPORTED_TYPES[defaultKey] || []).join(',')
|
||||
providerForm.enabled = true; providerForm.refund_enabled = false
|
||||
Object.keys(providerConfig).forEach(k => delete providerConfig[k])
|
||||
// Auto-fill default values for new providers
|
||||
applyConfigDefaults(defaultKey)
|
||||
}
|
||||
|
||||
function applyConfigDefaults(providerKey: string) {
|
||||
const fields = PROVIDER_CONFIG_FIELDS[providerKey] || []
|
||||
for (const f of fields) {
|
||||
if (f.defaultValue && !providerConfig[f.key]) {
|
||||
providerConfig[f.key] = f.defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
function openCreateProvider() { editingProvider.value = null; resetProviderForm(); showProviderDialog.value = true }
|
||||
function openEditProvider(provider: ProviderInstance) {
|
||||
|
||||
Reference in New Issue
Block a user