Files
basic/apps/example/src/views/plugin_example/currency.input.vue
T
Hooray 749c55edbc refactor!: 重构多个子包
- 移除 unbuild --stub 模式
- faToast -> useFaToast
2026-05-17 03:54:49 +08:00

255 lines
9.4 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import type { CurrencyInputOptions } from 'vue-currency-input'
import { createReusableTemplate, useClipboard } from '@vueuse/core'
import { useCurrencyInput } from 'vue-currency-input'
import Alert from './components/alert.vue'
import Command from './components/command.vue'
const Option = createReusableTemplate<{
$slots: {
default: any
switch: any
}
label: string
description?: string
}>()
const localeEnabled = ref(false)
const locale = ref('zh-ZH')
const locales = ref(['de-DE', 'de-CH', 'en-US', 'en-IN', 'nl-NL', 'sv-SE', 'fr-FR', 'es-ES', 'pt-PT', 'pt-BR', 'zh-ZH', 'ja-JP', 'ar-SA', 'fa-IR', 'bg-BG'])
const currency = ref('CNY')
const currencies = ref(['EUR', 'USD', 'GBP', 'BRL', 'INR', 'CNY', 'JPY', 'SAR', 'IRR', 'BGN'])
const currencyDisplay = ref('symbol')
const currencyDisplays = ref([
{ value: 'symbol', label: 'Symbol' },
{ value: 'narrowSymbol', label: 'Narrow symbol' },
{ value: 'code', label: 'Code' },
{ value: 'name', label: 'Name' },
{ value: 'hidden', label: 'Hidden' },
])
const accountingSign = ref(false)
const useGrouping = ref(true)
const hideCurrencySymbolOnFocus = ref(true)
const hideGroupingSeparatorOnFocus = ref(true)
const hideNegligibleDecimalDigitsOnFocus = ref(true)
const hideNegligibleDecimalDigitsOnFocusEnabled = ref(true)
const valueRangeEnabled = ref(false)
const minValue = ref(undefined)
const maxValue = ref(undefined)
const precisionEnabled = ref(false)
const precisionRangeEnabled = ref(false)
const precisionRangeValue = ref([2, 5])
function range(from: number, to: number) {
return Array.from({ length: to - from }, (_, i) => from + i)
}
const precision = ref(2)
const precisionOptions = computed(() => range(1, 16))
const valueScalingEnabled = ref(false)
const valueScaling = ref('precision')
const valueScalingOptions = ref([
{ value: 'precision', label: 'Precision' },
{ value: 'thousands', label: 'Thousands' },
{ value: 'millions', label: 'Millions' },
{ value: 'billions', label: 'Billions' },
])
const autoDecimalDigits = ref(false)
watch(autoDecimalDigits, (value) => {
hideNegligibleDecimalDigitsOnFocusEnabled.value = !value
hideNegligibleDecimalDigitsOnFocus.value = !value
})
const options = computed(() => {
return {
locale: localeEnabled.value ? locale.value : undefined,
currency: currency.value,
currencyDisplay: currencyDisplay.value,
valueRange: valueRangeEnabled.value
? {
min: minValue.value === '' ? undefined : minValue.value,
max: maxValue.value === '' ? undefined : maxValue.value,
}
: undefined,
precision: precisionEnabled.value
? precisionRangeEnabled.value
? { min: precisionRangeValue.value[0], max: precisionRangeValue.value[1] }
: precision.value
: undefined,
hideCurrencySymbolOnFocus: hideCurrencySymbolOnFocus.value,
hideGroupingSeparatorOnFocus: hideGroupingSeparatorOnFocus.value,
hideNegligibleDecimalDigitsOnFocus: hideNegligibleDecimalDigitsOnFocus.value,
autoDecimalDigits: autoDecimalDigits.value,
valueScaling: valueScalingEnabled.value ? valueScaling.value : undefined,
useGrouping: useGrouping.value,
accountingSign: accountingSign.value,
}
})
// @ts-expect-error inputRef
const { inputRef, setValue, setOptions, numberValue, formattedValue } = useCurrencyInput(options.value as CurrencyInputOptions)
watch(options, (value) => {
setOptions(value as CurrencyInputOptions)
})
watch(numberValue, (val) => {
setValue(val)
}, {
immediate: true,
})
onMounted(() => {
numberValue.value = 1234.5
})
const { copy, copied, isSupported } = useClipboard()
watch(copied, (val) => {
if (val) {
useFaToast().success('复制成功', {
position: 'top-center',
})
}
})
function handleCopy() {
copy(JSON.stringify(options.value, null, 2))
}
function open(url: string) {
window.open(url, '_blank')
}
</script>
<template>
<div>
<Option.define v-slot="{ $slots, label, description }">
<section class="mb-6 min-w-0">
<div class="mb-2 flex items-center justify-between">
<span class="text-xl font-medium">{{ label }}</span>
<Component :is="$slots.switch" />
</div>
<div v-if="description" class="text-sm mb-2 opacity-30">
{{ description }}
</div>
<Component :is="$slots.default" />
</section>
</Option.define>
<Alert />
<FaPageHeader title="货币格式输入">
<template #description>
<Command text="pnpm add vue-currency-input" />
</template>
<FaButton variant="outline" size="icon" @click="open('https://github.com/dm4t2/vue-currency-input')">
<FaIcon name="i-simple-icons:github" />
</FaButton>
</FaPageHeader>
<FaPageMain>
<div class="gap-y-4 grid items-center md-gap-x-8 md-grid-cols-2">
<ElInput ref="inputRef" v-model="formattedValue" />
<div>
数值:<code class="ml-2">{{ numberValue != null ? numberValue : 'null' }}</code>
</div>
</div>
</FaPageMain>
<FaPageMain title="选项">
<template #title>
<div class="flex items-center justify-between">
选项
<ElButton v-if="isSupported" size="small" @click="handleCopy">
复制选项
</ElButton>
</div>
</template>
<div class="gap-x-8 grid grid-cols-1 md-grid-cols-2">
<div>
<Option.reuse label="地理位置">
<template #switch>
<ElSwitch v-model="localeEnabled" />
</template>
<ElSelect v-model="locale" :disabled="!localeEnabled">
<ElOption v-for="item in locales" :key="item" :value="item" :label="item" />
</ElSelect>
</Option.reuse>
<Option.reuse label="货币">
<ElSelect v-model="currency">
<ElOption v-for="item in currencies" :key="item" :value="item" :label="item" />
</ElSelect>
</Option.reuse>
<Option.reuse label="货币显示" description="如何在格式化中显示货币">
<ElSelect v-model="currencyDisplay">
<ElOption v-for="item in currencyDisplays" :key="item.value" :value="item.value" :label="item.label" />
</ElSelect>
</Option.reuse>
<Option.reuse label="会计标志" description="是否使用会计符号格式化">
<template #switch>
<ElSwitch v-model="accountingSign" />
</template>
</Option.reuse>
<Option.reuse label="使用分组" description="是否使用分组分隔符,如千/万/千万分隔符">
<template #switch>
<ElSwitch v-model="useGrouping" />
</template>
</Option.reuse>
<Option.reuse label="无干扰输入" description="对焦时隐藏格式的不同部分,以方便输入">
<div>
<ElCheckbox v-model="hideCurrencySymbolOnFocus" label="隐藏货币符号" />
</div>
<div>
<ElCheckbox v-model="hideGroupingSeparatorOnFocus" label="隐藏分组分隔符" />
</div>
<div>
<ElCheckbox v-model="hideNegligibleDecimalDigitsOnFocus" :disabled="!hideNegligibleDecimalDigitsOnFocusEnabled" label="隐藏可忽略的小数位数" />
</div>
</Option.reuse>
</div>
<div>
<Option.reuse label="数值范围" description="验证在模糊时触发,并在超出范围时自动设置相应的阈值">
<template #switch>
<ElSwitch v-model="valueRangeEnabled" />
</template>
<div class="flex items-center space-x-4">
<ElInputNumber v-model="minValue" :disabled="!valueRangeEnabled" placeholder="最小值" class="flex-1" />
<span class="text-center">to</span>
<ElInputNumber v-model="maxValue" :disabled="!valueRangeEnabled" placeholder="最大值" class="flex-1" />
</div>
</Option.reuse>
<Option.reuse label="精确度" description="覆盖显示的小数位数,仅适用于支持小数位的货币">
<template #switch>
<ElSwitch v-model="precisionEnabled" />
</template>
<div>
<ElCheckbox v-model="precisionRangeEnabled" :disabled="!precisionEnabled" label="使用范围" />
<ElSlider v-if="precisionRangeEnabled" v-model="precisionRangeValue" range show-stops :min="1" :max="15" />
<ElSelect v-else v-model="precision" :disabled="!precisionEnabled">
<ElOption v-for="item in precisionOptions" :key="item" :value="item" :label="item" />
</ElSelect>
</div>
</Option.reuse>
<Option.reuse label="数值缩放" description="对输出值进行缩放">
<template #switch>
<ElSwitch v-model="valueScalingEnabled" />
</template>
<ElSelect v-model="valueScaling" :disabled="!valueScalingEnabled">
<ElOption v-for="item in valueScalingOptions" :key="item.value" :value="item.value" :label="item.label" />
</ElSelect>
</Option.reuse>
<Option.reuse label="自动小数位" description="是否自动插入小数符号,将最后输入的数字作为小数位">
<template #switch>
<ElSwitch v-model="autoDecimalDigits" />
</template>
</Option.reuse>
</div>
</div>
</FaPageMain>
</div>
</template>