fix price input

This commit is contained in:
2026-06-22 12:08:47 +03:30
parent c3abeeecef
commit cc5e3ce5f2
2 changed files with 49 additions and 16 deletions
@@ -32,13 +32,24 @@
</a-select> </a-select>
<a-input-number <a-input-number
v-else-if="fieldType === 'number'" v-else-if="fieldType === 'price'"
:value="numberValue" :value="priceValue"
:disabled="disabled" :disabled="disabled"
class="w-full" class="w-full"
:formatter="(v: string) => `${v}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')" :formatter="(v: string) => `${v}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
:parser="(v: string) => v.replace(/,/g, '')" :parser="(v: string) => v.replace(/,/g, '')"
@update:value="onNumberChange" @update:value="onPriceChange"
/>
<a-input
v-else-if="fieldType === 'number'"
:value="modelValue"
:disabled="disabled"
inputmode="numeric"
allow-clear
class="w-full"
@update:value="onPlainNumberChange"
@blur="emit('blur')"
/> />
<a-textarea <a-textarea
@@ -119,18 +130,36 @@ function onSelectChange(val: string | undefined) {
emit('update:value', val ?? '') emit('update:value', val ?? '')
} }
const numberValue = computed(() => { const priceValue = computed(() => {
const n = parseFloat(String(props.modelValue || '').replace(/,/g, '')) const n = parseFloat(String(props.modelValue || '').replace(/,/g, ''))
return Number.isFinite(n) ? n : undefined return Number.isFinite(n) ? n : undefined
}) })
function onNumberChange(val: number | string | null) { function onPriceChange(val: number | string | null) {
if (val === null || val === undefined || val === '') { if (val === null || val === undefined || val === '') {
emit('update:value', '') emit('update:value', '')
return return
} }
emit('update:value', String(val)) emit('update:value', String(val))
} }
function normalizePlainNumberInput(value: string): string {
const latin = value.replace(/[۰-۹]/g, (d) => String('۰۱۲۳۴۵۶۷۸۹'.indexOf(d)))
let out = ''
let hasDot = false
for (const ch of latin.replace(/,/g, '')) {
if (ch >= '0' && ch <= '9') out += ch
else if (ch === '.' && !hasDot) {
hasDot = true
out += ch
}
}
return out
}
function onPlainNumberChange(val: string) {
emit('update:value', normalizePlainNumberInput(val ?? ''))
}
</script> </script>
<style scoped> <style scoped>
@@ -1,7 +1,7 @@
import type { Const } from '@/model/configuration' import type { Const } from '@/model/configuration'
import { isStoreApp } from '@/utils/config' import { isStoreApp } from '@/utils/config'
export type SettingFieldType = 'text' | 'number' | 'switch' | 'select' | 'longtext' export type SettingFieldType = 'text' | 'number' | 'price' | 'switch' | 'select' | 'longtext'
/** کلیدهای legacy — در پنل نمایش داده نمی‌شوند */ /** کلیدهای legacy — در پنل نمایش داده نمی‌شوند */
export const HIDDEN_LEGACY_SETTING_KEYS = new Set([ export const HIDDEN_LEGACY_SETTING_KEYS = new Set([
@@ -38,7 +38,8 @@ export function isSettingVisible(key: string | undefined | null): boolean {
export const SETTING_TYPE_OPTIONS = [ export const SETTING_TYPE_OPTIONS = [
{ key: 'text', value: 'متن کوتاه' }, { key: 'text', value: 'متن کوتاه' },
{ key: 'number', value: 'عدد' }, { key: 'number', value: 'عدد / شماره' },
{ key: 'price', value: 'مبلغ (ریال)' },
{ key: 'switch', value: 'روشن/خاموش' }, { key: 'switch', value: 'روشن/خاموش' },
{ key: 'select', value: 'انتخابی' }, { key: 'select', value: 'انتخابی' },
{ key: 'longtext', value: 'متن بلند' } { key: 'longtext', value: 'متن بلند' }
@@ -52,14 +53,14 @@ const KEY_TYPE_FALLBACK: Record<string, SettingFieldType> = {
text_rule: 'longtext', text_rule: 'longtext',
text_about: 'longtext', text_about: 'longtext',
fee_service_charge_percentage: 'number', fee_service_charge_percentage: 'number',
fee_single: 'number', fee_single: 'price',
buy_fee: 'number', buy_fee: 'price',
sell_fee: 'number', sell_fee: 'price',
fee_cash: 'number', fee_cash: 'price',
fee_free: 'number', fee_free: 'number',
min_withdraw: 'number', min_withdraw: 'price',
min_first_buy: 'number', min_first_buy: 'price',
minimum_sell: 'number', minimum_sell: 'price',
gift_for_referrer: 'number', gift_for_referrer: 'number',
gift_for_referral: 'number', gift_for_referral: 'number',
referral_bonus_amount: 'text', referral_bonus_amount: 'text',
@@ -135,7 +136,7 @@ export function referralRequiredToString(checked: boolean): string {
export function resolveSettingFieldType(row: Pick<Const, 'key' | 'type'>): SettingFieldType { export function resolveSettingFieldType(row: Pick<Const, 'key' | 'type'>): SettingFieldType {
const raw = (row.type || '').trim().toLowerCase() const raw = (row.type || '').trim().toLowerCase()
if (['text', 'number', 'switch', 'select', 'longtext'].includes(raw)) { if (['text', 'number', 'price', 'switch', 'select', 'longtext'].includes(raw)) {
return raw as SettingFieldType return raw as SettingFieldType
} }
if (row.key && KEY_TYPE_FALLBACK[row.key]) { if (row.key && KEY_TYPE_FALLBACK[row.key]) {
@@ -198,9 +199,12 @@ export function formatValueForSave(
if (type === 'switch') { if (type === 'switch') {
return switchValueFromChecked(key, isSwitchOn(value) || (key === REFERRAL_REQUIRED_KEY && isReferralRequired(value))) return switchValueFromChecked(key, isSwitchOn(value) || (key === REFERRAL_REQUIRED_KEY && isReferralRequired(value)))
} }
if (type === 'number') { if (type === 'price') {
return value === '' ? '0' : String(value).replace(/,/g, '') return value === '' ? '0' : String(value).replace(/,/g, '')
} }
if (type === 'number') {
return String(value ?? '').replace(/,/g, '')
}
return value ?? '' return value ?? ''
} }