diff --git a/assets/admin/src/schema/sections/payment/gateway.js b/assets/admin/src/schema/sections/payment/gateway.js index 53fd11df..86fca069 100644 --- a/assets/admin/src/schema/sections/payment/gateway.js +++ b/assets/admin/src/schema/sections/payment/gateway.js @@ -282,7 +282,7 @@ export const gatewaySchema = { }, { key: 'paypal_client_id', label: 'Client ID', type: 'input', default: '' }, { key: 'paypal_client_secret', label: 'Client Secret', type: 'input', default: '' }, - { key: 'paypal_currency', label: '结算货币', type: 'select', default: 'USD', options: currencyOptions }, + { key: 'paypal_currency', label: '结算货币', type: 'select', case_insensitive: true, default: 'USD', options: currencyOptions }, { key: 'paypal_rates', label: '货币汇率', type: 'input', default: '0.14', help: '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137' }, { key: 'paypal_sandbox', label: '沙盒调试模式', type: 'switch', default: false, help: '沙箱模式(Sandbox)是PayPal支付的测试环境。开启后请使用沙箱环境生成的收款账户和付款账户进行测试。' }, ], @@ -306,7 +306,7 @@ export const gatewaySchema = { { key: 'stripe_secret_key', label: '私钥Secret Key', type: 'input', default: '', help: 'Stripe Dashboard → Developers → API keys → Secret key' }, { key: 'stripe_publishable_key', label: 'Publishable Key', type: 'input', default: '' }, { key: 'stripe_webhook_secret', label: '签名密钥Webhook Secret', type: 'input', default: '', help: 'Developers → Webhooks → 端点 → Signing secret(whsec_ 开头)' }, - { key: 'stripe_currency', label: '结算货币', type: 'select', default: 'USD', options: currencyOptions }, + { key: 'stripe_currency', label: '结算货币', type: 'select', case_insensitive: true, default: 'USD', options: currencyOptions }, { key: 'stripe_rates', label: '货币汇率', type: 'input', default: '0.14', help: '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137' }, { key: 'stripe_test_mode', label: '测试模式', type: 'switch', default: false, help: '如果使用的测试开放模式,则请使用 sk_test_ 测试密钥与 Stripe 测试卡进行配置' }, ], diff --git a/src/Admin/Schema/SchemaPayment.php b/src/Admin/Schema/SchemaPayment.php index 1e788ff7..7d1504c4 100644 --- a/src/Admin/Schema/SchemaPayment.php +++ b/src/Admin/Schema/SchemaPayment.php @@ -469,7 +469,7 @@ class SchemaPayment { ['key' => 'paypal_notice', 'label' => '', 'type' => 'content', 'ui_only' => true, 'content' => ''], ['key' => 'paypal_client_id', 'label' => 'Client ID', 'type' => 'input', 'default' => ''], ['key' => 'paypal_client_secret', 'label' => 'Client Secret', 'type' => 'input', 'default' => ''], - ['key' => 'paypal_currency', 'label' => '结算货币', 'type' => 'select', 'default' => 'USD', 'options' => self::currency_options()], + ['key' => 'paypal_currency', 'label' => '结算货币', 'type' => 'select', 'case_insensitive' => true, 'default' => 'USD', 'options' => self::currency_options()], ['key' => 'paypal_rates', 'label' => '货币汇率', 'type' => 'input', 'default' => '0.14', 'help' => '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137'], ['key' => 'paypal_sandbox', 'label' => '沙盒调试模式', 'type' => 'switch', 'default' => false, 'help' => '沙箱模式(Sandbox)是PayPal支付的测试环境。开启后请使用沙箱环境生成的收款账户和付款账户进行测试。'], ]], @@ -478,7 +478,7 @@ class SchemaPayment { ['key' => 'stripe_secret_key', 'label' => '私钥Secret Key', 'type' => 'input', 'default' => '', 'help' => 'Stripe Dashboard → Developers → API keys → Secret key'], ['key' => 'stripe_publishable_key', 'label' => 'Publishable Key', 'type' => 'input', 'default' => ''], ['key' => 'stripe_webhook_secret', 'label' => '签名密钥Webhook Secret', 'type' => 'input', 'default' => '', 'help' => 'Developers → Webhooks → 端点 → Signing secret(whsec_ 开头)'], - ['key' => 'stripe_currency', 'label' => '结算货币', 'type' => 'select', 'default' => 'USD', 'options' => self::currency_options()], + ['key' => 'stripe_currency', 'label' => '结算货币', 'type' => 'select', 'case_insensitive' => true, 'default' => 'USD', 'options' => self::currency_options()], ['key' => 'stripe_rates', 'label' => '货币汇率', 'type' => 'input', 'default' => '0.14', 'help' => '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137'], ['key' => 'stripe_test_mode', 'label' => '测试模式', 'type' => 'switch', 'default' => false, 'help' => '如果使用的测试开放模式,则请使用 sk_test_ 测试密钥与 Stripe 测试卡进行配置'], ]], diff --git a/src/Admin/SchemaProvider.php b/src/Admin/SchemaProvider.php index a58d8085..7bd633d7 100644 --- a/src/Admin/SchemaProvider.php +++ b/src/Admin/SchemaProvider.php @@ -237,12 +237,14 @@ class SchemaProvider { // (legacy / SPA may still use type=select multiple). if (!empty($field['multiple']) && is_array($value)) { foreach ($value as $item) { - if (!in_array($item, $valid_values, true)) { + if (!in_array($item, $valid_values, true) + && (empty($field['case_insensitive']) || $this->normalize_case_insensitive_option($item, (array) $field['options']) === null)) { $errors[] = sprintf('%s has an invalid value', $field['label'] ?? $key); break; } } - } elseif (!in_array($value, $valid_values, true)) { + } elseif (!in_array($value, $valid_values, true) + && (empty($field['case_insensitive']) || $this->normalize_case_insensitive_option($value, (array) $field['options']) === null)) { $errors[] = sprintf('%s has an invalid value', $field['label'] ?? $key); } } @@ -545,6 +547,12 @@ class SchemaProvider { if ($has_stored) { $data[$field['key']] = $stored[$field['key']]; } + // 大小写不敏感字段:存储值归一化为选项规范写法;匹配不到回退默认, + // 避免旧自由文本值(如小写货币代码)导致枚举校验失败。 + if (!empty($field['case_insensitive']) && in_array($field_type, ['select', 'radio'], true) && !empty($field['options'])) { + $normalized = $this->normalize_case_insensitive_option($data[$field['key']] ?? '', (array) $field['options']); + $data[$field['key']] = $normalized !== null ? $normalized : ($field['default'] ?? ($data[$field['key']] ?? '')); + } if (($field['sanitize_type'] ?? '') === 'money_decimal' && array_key_exists($field['key'], $data)) { $normalized = $this->normalize_money_decimal($data[$field['key']]); if ($normalized !== '') { @@ -855,6 +863,27 @@ class SchemaProvider { } } + /** + * 对大小写不敏感字段(case_insensitive),把值归一化为选项中的规范写法; + * 匹配不到返回 null。 + * + * @param mixed $value + * @param array $options + */ + private function normalize_case_insensitive_option($value, array $options): ?string { + if (!is_string($value) || $value === '') { + return null; + } + $lower = strtolower(trim($value)); + foreach ($options as $opt) { + $opt_value = is_array($opt) ? ($opt['value'] ?? null) : $opt; + if (is_string($opt_value) && strtolower($opt_value) === $lower) { + return $opt_value; + } + } + return null; + } + private function sanitize_field_value($value, array $field) { if (!empty($field['captcha_provider'])) { return function_exists('aksrt_captcha_sanitize_provider_config') @@ -874,6 +903,12 @@ class SchemaProvider { return $this->sanitize_value($value, 'attachment_ids'); } + if (in_array($type, ['select', 'radio'], true) && !empty($field['case_insensitive']) && !empty($field['options'])) { + // 旧自由文本值(如小写货币代码)归一化为选项规范写法。 + $normalized = $this->normalize_case_insensitive_option($value, (array) $field['options']); + return $normalized !== null ? $normalized : (string) ($field['default'] ?? ''); + } + if (in_array($type, ['fieldset', 'accordion'], true)) { return $this->sanitize_object_fields($value, (array) ($field['fields'] ?? [])); }