2026-08-08 11:20:26 +03:30
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { computed } from 'vue'
|
2026-08-08 13:27:31 +03:30
|
|
|
|
import {
|
|
|
|
|
|
fromGroupedInput,
|
|
|
|
|
|
rialToToman,
|
|
|
|
|
|
toGroupedDisplay,
|
|
|
|
|
|
tomanToRial,
|
|
|
|
|
|
} from '@/utils/money'
|
2026-08-08 11:20:26 +03:30
|
|
|
|
|
2026-08-08 13:27:31 +03:30
|
|
|
|
/**
|
|
|
|
|
|
* Money field bound to **rial** storage values (API/DB).
|
|
|
|
|
|
* User types and sees **toman** (÷10 / ×10 at the edges).
|
2026-08-08 14:12:30 +03:30
|
|
|
|
* With `nullable`, empty input emits `null` (for optional thresholds).
|
2026-08-08 13:27:31 +03:30
|
|
|
|
*/
|
2026-08-08 11:20:26 +03:30
|
|
|
|
const props = withDefaults(
|
|
|
|
|
|
defineProps<{
|
|
|
|
|
|
value: number | null | undefined
|
|
|
|
|
|
size?: 'large' | 'middle' | 'small'
|
|
|
|
|
|
placeholder?: string
|
|
|
|
|
|
allowNegative?: boolean
|
|
|
|
|
|
disabled?: boolean
|
2026-08-08 14:12:30 +03:30
|
|
|
|
nullable?: boolean
|
2026-08-08 11:20:26 +03:30
|
|
|
|
}>(),
|
|
|
|
|
|
{
|
|
|
|
|
|
size: 'large',
|
|
|
|
|
|
placeholder: '',
|
|
|
|
|
|
allowNegative: false,
|
|
|
|
|
|
disabled: false,
|
2026-08-08 14:12:30 +03:30
|
|
|
|
nullable: false,
|
2026-08-08 11:20:26 +03:30
|
|
|
|
},
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
2026-08-08 14:12:30 +03:30
|
|
|
|
(e: 'update:value', value: number | null): void
|
2026-08-08 11:20:26 +03:30
|
|
|
|
}>()
|
|
|
|
|
|
|
2026-08-08 14:12:30 +03:30
|
|
|
|
const display = computed(() => {
|
|
|
|
|
|
if (props.nullable && (props.value == null || props.value === undefined)) return ''
|
|
|
|
|
|
return toGroupedDisplay(rialToToman(props.value ?? 0))
|
|
|
|
|
|
})
|
2026-08-08 11:20:26 +03:30
|
|
|
|
|
|
|
|
|
|
function onInput(raw: string | number) {
|
2026-08-08 14:12:30 +03:30
|
|
|
|
const text = String(raw ?? '').trim()
|
|
|
|
|
|
if (props.nullable && !text) {
|
|
|
|
|
|
emit('update:value', null)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const toman = fromGroupedInput(text, props.allowNegative)
|
2026-08-08 13:27:31 +03:30
|
|
|
|
emit('update:value', tomanToRial(toman))
|
2026-08-08 11:20:26 +03:30
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
class="money-input"
|
|
|
|
|
|
dir="ltr"
|
|
|
|
|
|
:size="size"
|
|
|
|
|
|
:placeholder="placeholder"
|
|
|
|
|
|
:disabled="disabled"
|
|
|
|
|
|
:value="display"
|
2026-08-08 14:12:30 +03:30
|
|
|
|
allow-clear
|
2026-08-08 11:20:26 +03:30
|
|
|
|
@update:value="onInput"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.money-input {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.money-input :deep(input) {
|
|
|
|
|
|
font-variant-numeric: tabular-nums;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
direction: ltr;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|