227 lines
5.6 KiB
Vue
227 lines
5.6 KiB
Vue
<template>
|
||
<div class="setting-value-field">
|
||
<a-switch
|
||
v-if="fieldType === 'switch'"
|
||
:checked="switchChecked"
|
||
:disabled="disabled"
|
||
@change="onSwitchChange"
|
||
>
|
||
<template #checkedChildren>{{ labels.on }}</template>
|
||
<template #unCheckedChildren>{{ labels.off }}</template>
|
||
</a-switch>
|
||
|
||
<MainWalletProductsField
|
||
v-else-if="isMainWalletProducts"
|
||
:model-value="modelValue"
|
||
:disabled="disabled"
|
||
@update:value="emit('update:value', $event)"
|
||
/>
|
||
|
||
<ZaarboxPriceKeyField
|
||
v-else-if="isZaarboxPriceKey"
|
||
:model-value="modelValue"
|
||
:disabled="disabled"
|
||
@update:value="emit('update:value', $event)"
|
||
/>
|
||
|
||
<a-select
|
||
v-else-if="fieldType === 'select'"
|
||
:value="modelValue || undefined"
|
||
:disabled="disabled"
|
||
allow-clear
|
||
placeholder="انتخاب کنید"
|
||
class="w-full"
|
||
@update:value="onSelectChange"
|
||
>
|
||
<a-select-option v-for="opt in selectItems" :key="opt.key" :value="opt.key">
|
||
{{ opt.value }}
|
||
</a-select-option>
|
||
</a-select>
|
||
|
||
<a-select
|
||
v-else-if="fieldType === 'multiselect'"
|
||
:value="multiSelectValue"
|
||
:disabled="disabled"
|
||
mode="multiple"
|
||
allow-clear
|
||
placeholder="انتخاب کنید"
|
||
class="w-full"
|
||
@update:value="onMultiSelectChange"
|
||
>
|
||
<a-select-option v-for="opt in selectItems" :key="opt.key" :value="opt.key">
|
||
{{ opt.value }}
|
||
</a-select-option>
|
||
</a-select>
|
||
|
||
<a-time-picker
|
||
v-else-if="fieldType === 'time'"
|
||
:value="modelValue || undefined"
|
||
:disabled="disabled"
|
||
class="w-full"
|
||
format="HH:mm"
|
||
value-format="HH:mm:ss"
|
||
:minute-step="5"
|
||
placeholder="انتخاب ساعت"
|
||
@update:value="onTimeChange"
|
||
/>
|
||
|
||
<a-input-number
|
||
v-else-if="fieldType === 'price'"
|
||
:value="priceValue"
|
||
:disabled="disabled"
|
||
class="w-full"
|
||
:formatter="(v: string) => `${v}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
|
||
:parser="(v: string) => v.replace(/,/g, '')"
|
||
@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
|
||
v-else-if="fieldType === 'longtext'"
|
||
:value="modelValue"
|
||
:disabled="disabled"
|
||
:rows="rows"
|
||
class="w-full font-mono text-sm"
|
||
@update:value="emit('update:value', $event)"
|
||
@blur="emit('blur')"
|
||
/>
|
||
|
||
<a-input
|
||
v-else
|
||
:value="modelValue"
|
||
:disabled="disabled"
|
||
allow-clear
|
||
@update:value="emit('update:value', $event)"
|
||
@blur="emit('blur')"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import MainWalletProductsField from './MainWalletProductsField.vue'
|
||
import ZaarboxPriceKeyField from './ZaarboxPriceKeyField.vue'
|
||
import {
|
||
parseSelectOptions,
|
||
resolveSettingFieldType,
|
||
resolveSwitchChecked,
|
||
switchLabels,
|
||
switchValueFromChecked,
|
||
type SettingFieldType
|
||
} from './settingTypes'
|
||
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
modelValue: string
|
||
settingKey?: string
|
||
settingType?: string
|
||
description?: string
|
||
disabled?: boolean
|
||
rows?: number
|
||
}>(),
|
||
{ disabled: false, rows: 10 }
|
||
)
|
||
|
||
const emit = defineEmits<{
|
||
'update:value': [value: string]
|
||
blur: []
|
||
}>()
|
||
|
||
const fieldType = computed<SettingFieldType>(() =>
|
||
resolveSettingFieldType({
|
||
key: props.settingKey,
|
||
type: props.settingType
|
||
})
|
||
)
|
||
|
||
const isZaarboxPriceKey = computed(() => props.settingKey === 'zaarbox_price_key')
|
||
const isMainWalletProducts = computed(() => props.settingKey === 'main_wallet_products')
|
||
|
||
const selectItems = computed(() =>
|
||
parseSelectOptions({
|
||
key: props.settingKey,
|
||
description: props.description,
|
||
type: props.settingType
|
||
})
|
||
)
|
||
|
||
const labels = computed(() => switchLabels(props.settingKey))
|
||
|
||
const switchChecked = computed(() => resolveSwitchChecked(props.settingKey, props.modelValue))
|
||
|
||
function onSwitchChange(checked: boolean) {
|
||
emit('update:value', switchValueFromChecked(props.settingKey, checked))
|
||
}
|
||
|
||
function onSelectChange(val: string | undefined) {
|
||
emit('update:value', val ?? '')
|
||
}
|
||
|
||
const multiSelectValue = computed<string[]>(() =>
|
||
String(props.modelValue || '')
|
||
.split(',')
|
||
.map((s) => s.trim())
|
||
.filter((s) => s !== '')
|
||
)
|
||
|
||
function onMultiSelectChange(val: string[] | undefined) {
|
||
const list = Array.isArray(val) ? val.map((s) => s.trim()).filter((s) => s !== '') : []
|
||
emit('update:value', list.join(','))
|
||
}
|
||
|
||
function onTimeChange(val: string | string[] | undefined) {
|
||
const v = Array.isArray(val) ? val[0] : val
|
||
emit('update:value', v ?? '')
|
||
emit('blur')
|
||
}
|
||
|
||
const priceValue = computed(() => {
|
||
const n = parseFloat(String(props.modelValue || '').replace(/,/g, ''))
|
||
return Number.isFinite(n) ? n : undefined
|
||
})
|
||
|
||
function onPriceChange(val: number | string | null) {
|
||
if (val === null || val === undefined || val === '') {
|
||
emit('update:value', '')
|
||
return
|
||
}
|
||
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>
|
||
|
||
<style scoped>
|
||
.setting-value-field {
|
||
width: 100%;
|
||
}
|
||
.setting-value-field :deep(.ant-input-number) {
|
||
width: 100%;
|
||
}
|
||
</style>
|