feat(全局):增加 number-range-input 组件
parent
08511191f7
commit
3135b28211
|
|
@ -0,0 +1,39 @@
|
|||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
|
||||
import { markRaw } from 'vue';
|
||||
|
||||
import NumberRangeInput from './number-range-input.vue';
|
||||
|
||||
export { default as NumberRangeInput } from './number-range-input.vue';
|
||||
|
||||
export type NumberRangeValue = [number | undefined, number | undefined];
|
||||
|
||||
function splitNumberRange(minFieldName: string, maxFieldName: string) {
|
||||
return (
|
||||
value: NumberRangeValue | undefined,
|
||||
setValue: (fieldName: string, value: number | undefined) => void,
|
||||
) => {
|
||||
setValue(minFieldName, value?.[0]);
|
||||
setValue(maxFieldName, value?.[1]);
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export function buildNumberRangeSchema(
|
||||
label: string,
|
||||
fieldName: string,
|
||||
minFieldName: string,
|
||||
maxFieldName: string,
|
||||
precision: number,
|
||||
): VbenFormSchema {
|
||||
return {
|
||||
component: markRaw(NumberRangeInput),
|
||||
componentProps: {
|
||||
min: 0,
|
||||
precision,
|
||||
},
|
||||
fieldName,
|
||||
label,
|
||||
valueFormat: splitNumberRange(minFieldName, maxFieldName),
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<script lang="ts" setup>
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
|
||||
type NumberRangeValue = [number | undefined, number | undefined];
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
maxPlaceholder?: string;
|
||||
min?: number;
|
||||
minPlaceholder?: string;
|
||||
precision?: number;
|
||||
value?: NumberRangeValue;
|
||||
}>(),
|
||||
{
|
||||
maxPlaceholder: '最大值',
|
||||
min: undefined,
|
||||
minPlaceholder: '最小值',
|
||||
precision: 2,
|
||||
value: undefined,
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:value': [value: NumberRangeValue | undefined];
|
||||
}>();
|
||||
|
||||
function normalizeValue(value: unknown) {
|
||||
if (typeof value === 'number') {
|
||||
return Number.isFinite(value) ? value : undefined;
|
||||
}
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
const numberValue = Number(value);
|
||||
return Number.isFinite(numberValue) ? numberValue : undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function updateValue(index: 0 | 1, value: unknown) {
|
||||
const next: NumberRangeValue = [
|
||||
props.value?.[0] ?? undefined,
|
||||
props.value?.[1] ?? undefined,
|
||||
];
|
||||
next[index] = normalizeValue(value);
|
||||
emit(
|
||||
'update:value',
|
||||
next[0] === undefined && next[1] === undefined ? undefined : next,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full items-center gap-2">
|
||||
<InputNumber
|
||||
:controls="false"
|
||||
:min="min"
|
||||
:placeholder="minPlaceholder"
|
||||
:precision="precision"
|
||||
:value="value?.[0]"
|
||||
class="min-w-0 flex-1"
|
||||
@update:value="updateValue(0, $event)"
|
||||
/>
|
||||
<span class="shrink-0 text-muted-foreground">至</span>
|
||||
<InputNumber
|
||||
:controls="false"
|
||||
:min="min"
|
||||
:placeholder="maxPlaceholder"
|
||||
:precision="precision"
|
||||
:value="value?.[1]"
|
||||
class="min-w-0 flex-1"
|
||||
@update:value="updateValue(1, $event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
|
||||
import { markRaw } from 'vue';
|
||||
|
||||
import NumberRangeInput from './number-range-input.vue';
|
||||
|
||||
export { default as NumberRangeInput } from './number-range-input.vue';
|
||||
|
||||
export type NumberRangeValue = [number | undefined, number | undefined];
|
||||
|
||||
function splitNumberRange(minFieldName: string, maxFieldName: string) {
|
||||
return (
|
||||
value: NumberRangeValue | undefined,
|
||||
setValue: (fieldName: string, value: number | undefined) => void,
|
||||
) => {
|
||||
setValue(minFieldName, value?.[0]);
|
||||
setValue(maxFieldName, value?.[1]);
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export function buildNumberRangeSchema(
|
||||
label: string,
|
||||
fieldName: string,
|
||||
minFieldName: string,
|
||||
maxFieldName: string,
|
||||
precision: number,
|
||||
): VbenFormSchema {
|
||||
return {
|
||||
component: markRaw(NumberRangeInput),
|
||||
componentProps: {
|
||||
min: 0,
|
||||
precision,
|
||||
},
|
||||
fieldName,
|
||||
label,
|
||||
valueFormat: splitNumberRange(minFieldName, maxFieldName),
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<script lang="ts" setup>
|
||||
import { ElInputNumber } from 'element-plus';
|
||||
|
||||
type NumberRangeValue = [number | undefined, number | undefined];
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
maxPlaceholder?: string;
|
||||
min?: number;
|
||||
minPlaceholder?: string;
|
||||
modelValue?: NumberRangeValue;
|
||||
precision?: number;
|
||||
}>(),
|
||||
{
|
||||
maxPlaceholder: '最大值',
|
||||
min: undefined,
|
||||
minPlaceholder: '最小值',
|
||||
modelValue: undefined,
|
||||
precision: 2,
|
||||
},
|
||||
);
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: NumberRangeValue | undefined];
|
||||
}>();
|
||||
|
||||
function normalizeValue(value: unknown) {
|
||||
if (typeof value === 'number') {
|
||||
return Number.isFinite(value) ? value : undefined;
|
||||
}
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
const numberValue = Number(value);
|
||||
return Number.isFinite(numberValue) ? numberValue : undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function updateValue(index: 0 | 1, value: unknown) {
|
||||
const next: NumberRangeValue = [
|
||||
props.modelValue?.[0] ?? undefined,
|
||||
props.modelValue?.[1] ?? undefined,
|
||||
];
|
||||
next[index] = normalizeValue(value);
|
||||
emit(
|
||||
'update:modelValue',
|
||||
next[0] === undefined && next[1] === undefined ? undefined : next,
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex w-full items-center gap-2">
|
||||
<ElInputNumber
|
||||
:controls="false"
|
||||
:min="min"
|
||||
:model-value="modelValue?.[0]"
|
||||
:placeholder="minPlaceholder"
|
||||
:precision="precision"
|
||||
class="min-w-0 flex-1"
|
||||
@update:model-value="updateValue(0, $event)"
|
||||
/>
|
||||
<span class="shrink-0 text-muted-foreground">至</span>
|
||||
<ElInputNumber
|
||||
:controls="false"
|
||||
:min="min"
|
||||
:model-value="modelValue?.[1]"
|
||||
:placeholder="maxPlaceholder"
|
||||
:precision="precision"
|
||||
class="min-w-0 flex-1"
|
||||
@update:model-value="updateValue(1, $event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
Loading…
Reference in New Issue