mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-30 08:22:34 +00:00
feat(payment): 订阅套餐支持币种标注,区分 $ 符号对应币种
后台配置与用户端展示的套餐价格统一使用 $ 符号,而实际扣款币种随 支付渠道配置漂移(如 Stripe 配置 NZD 时按新西兰元扣款),用户易 误认为美元。本次为套餐新增可选的展示性币种标注: - SubscriptionPlan 新增 currency 字段(ISO 4217 三字母码,默认空) - 空值不展示任何标注,存量套餐行为完全不变 - 非空值复用 payment.NormalizePaymentCurrency 校验并规范化为大写 - 后台套餐编辑弹窗新增可选币种输入,列表价格列展示币种小字 - 用户端套餐卡片价格与划线原价旁展示币种小字 - 纯展示性质,不影响任何支付/扣款逻辑 Closes #4315 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
cf6aa1a5c3
commit
2bbdd47002
@@ -30,6 +30,7 @@
|
||||
<template #cell-price="{ value, row }">
|
||||
<div class="text-sm">
|
||||
<span class="font-medium text-gray-900 dark:text-white">${{ (value ?? 0).toFixed(2) }}</span>
|
||||
<span v-if="row.currency" class="ml-1 text-xs text-gray-400">{{ row.currency }}</span>
|
||||
<span v-if="row.original_price" class="ml-1 text-xs text-gray-400 line-through">${{ row.original_price.toFixed(2) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -53,6 +53,11 @@
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div><label class="input-label">{{ t('payment.admin.sortOrder') }}</label><input v-model.number="planForm.sort_order" type="number" min="0" class="input" /></div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('payment.admin.currency') }}</label>
|
||||
<input v-model="planForm.currency" type="text" maxlength="3" class="input uppercase" :placeholder="t('payment.admin.currencyPlaceholder')" />
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">{{ t('payment.admin.currencyHint') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('payment.admin.features') }}</label>
|
||||
@@ -117,7 +122,7 @@ const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const saving = ref(false)
|
||||
const planForm = reactive({ name: '', group_id: null as number | null, description: '', price: 0, original_price: 0, validity_days: 30, validity_unit: 'days', sort_order: 0, for_sale: true })
|
||||
const planForm = reactive({ name: '', group_id: null as number | null, description: '', price: 0, original_price: 0, currency: '', validity_days: 30, validity_unit: 'days', sort_order: 0, for_sale: true })
|
||||
const planFeaturesText = ref('')
|
||||
|
||||
const validityUnitOptions = computed(() => [
|
||||
@@ -170,10 +175,10 @@ const subscriptionCnyPreview = computed(() => {
|
||||
watch(() => props.show, (visible) => {
|
||||
if (!visible) return
|
||||
if (props.plan) {
|
||||
Object.assign(planForm, { name: props.plan.name, group_id: props.plan.group_id, description: props.plan.description, price: props.plan.price, original_price: props.plan.original_price || 0, validity_days: props.plan.validity_days, validity_unit: props.plan.validity_unit || 'days', sort_order: props.plan.sort_order || 0, for_sale: props.plan.for_sale })
|
||||
Object.assign(planForm, { name: props.plan.name, group_id: props.plan.group_id, description: props.plan.description, price: props.plan.price, original_price: props.plan.original_price || 0, currency: props.plan.currency || '', validity_days: props.plan.validity_days, validity_unit: props.plan.validity_unit || 'days', sort_order: props.plan.sort_order || 0, for_sale: props.plan.for_sale })
|
||||
planFeaturesText.value = (props.plan.features || []).join('\n')
|
||||
} else {
|
||||
Object.assign(planForm, { name: '', group_id: null, description: '', price: 0, original_price: 0, validity_days: 30, validity_unit: 'days', sort_order: 0, for_sale: true })
|
||||
Object.assign(planForm, { name: '', group_id: null, description: '', price: 0, original_price: 0, currency: '', validity_days: 30, validity_unit: 'days', sort_order: 0, for_sale: true })
|
||||
planFeaturesText.value = ''
|
||||
}
|
||||
})
|
||||
@@ -187,6 +192,7 @@ function buildPlanPayload() {
|
||||
description: planForm.description,
|
||||
price: planForm.price,
|
||||
original_price: planForm.original_price || 0,
|
||||
currency: planForm.currency.trim().toUpperCase(),
|
||||
validity_days: planForm.validity_days,
|
||||
validity_unit: planForm.validity_unit,
|
||||
sort_order: planForm.sort_order,
|
||||
|
||||
Reference in New Issue
Block a user