index.vue 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <template>
  2. <el-input
  3. v-model="displayText"
  4. :placeholder="placeholder"
  5. :disabled="disabled"
  6. :clearable="clearable"
  7. style="width: 100%"
  8. @focus="handleFocus"
  9. @blur="handleBlur"
  10. @input="handleInput"
  11. />
  12. </template>
  13. <script setup lang="ts">
  14. import {
  15. formatMoneyDisplay,
  16. parseMoneyToNumber,
  17. sanitizeMoneyInput,
  18. } from '@/utils/money-format'
  19. defineOptions({ name: 'AmountInput' })
  20. interface Props {
  21. modelValue: number | null
  22. min?: number
  23. max?: number
  24. precision?: number
  25. placeholder?: string
  26. disabled?: boolean
  27. clearable?: boolean
  28. }
  29. const props = withDefaults(defineProps<Props>(), {
  30. min: undefined,
  31. max: undefined,
  32. precision: 2,
  33. placeholder: '',
  34. disabled: false,
  35. clearable: true,
  36. })
  37. const emit = defineEmits<{
  38. 'update:modelValue': [value: number | null]
  39. change: [value: number | null]
  40. }>()
  41. const displayText = ref('')
  42. const isFocused = ref(false)
  43. watch(
  44. () => props.modelValue,
  45. (val) => {
  46. if (!isFocused.value) {
  47. displayText.value = formatMoneyDisplay(val, props.precision)
  48. }
  49. },
  50. { immediate: true }
  51. )
  52. function handleFocus() {
  53. isFocused.value = true
  54. displayText.value = sanitizeMoneyInput(displayText.value, props.precision)
  55. }
  56. function handleInput(val: string) {
  57. displayText.value = sanitizeMoneyInput(val, props.precision)
  58. }
  59. function handleBlur() {
  60. isFocused.value = false
  61. let num = parseMoneyToNumber(displayText.value, props.precision)
  62. if (num !== null) {
  63. if (props.min !== undefined && num < props.min) num = props.min
  64. if (props.max !== undefined && num > props.max) num = props.max
  65. }
  66. emit('update:modelValue', num)
  67. emit('change', num)
  68. displayText.value = formatMoneyDisplay(num, props.precision)
  69. }
  70. </script>