Files
his/openhis-ui-vue3/src/components/TableLayout/NumberInput.vue
zhangfei 9c3e603b94 Fix Bug #443: 手术计费:点击签发耗材时异常报错
当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。
在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值,
与NurseBillingAppService中的处理方式保持一致。
2026-05-08 09:14:18 +08:00

137 lines
3.1 KiB
Vue
Executable File

<template>
<el-input
:model-value="displayValue"
:placeholder="placeholder"
:disabled="disabled"
:clearable="clearable"
@input="handleInput"
@blur="handleBlur"
@change="handleChange"
>
<template v-if="suffix" #suffix>{{ suffix }}</template>
</el-input>
</template>
<script setup>
import {computed} from 'vue';
const props = defineProps({
modelValue: [Number, String],
placeholder: String,
disabled: Boolean,
clearable: {
type: Boolean,
default: true,
},
suffix: String,
precision: Number, // 小数位数
min: Number,
max: Number,
});
const emit = defineEmits(['update:modelValue', 'blur', 'change']);
const displayValue = computed(() => {
if (props.modelValue === null || props.modelValue === undefined || props.modelValue === '') {
return '';
}
return String(props.modelValue);
});
const handleInput = (value) => {
// 只允许数字、小数点和负号
let newValue = value.replace(/[^\d.-]/g, '');
// 只允许一个小数点
const parts = newValue.split('.');
if (parts.length > 2) {
newValue = parts[0] + '.' + parts.slice(1).join('');
}
// 只允许一个负号,且必须在开头
if (newValue.indexOf('-') > 0) {
newValue = newValue.replace(/-/g, '');
}
if (newValue.startsWith('-') && newValue.split('-').length > 2) {
newValue = '-' + newValue.replace(/-/g, '');
}
// 如果为空,直接返回空字符串
if (newValue === '' || newValue === '-') {
emit('update:modelValue', '');
return;
}
// 转换为数字
const numValue = parseFloat(newValue);
if (isNaN(numValue)) {
emit('update:modelValue', '');
return;
}
// 限制最小值
if (props.min !== undefined && numValue < props.min) {
newValue = String(props.min);
}
// 限制最大值
if (props.max !== undefined && numValue > props.max) {
newValue = String(props.max);
}
// 处理精度
if (props.precision !== undefined && newValue.includes('.')) {
const parts = newValue.split('.');
if (parts[1] && parts[1].length > props.precision) {
parts[1] = parts[1].substring(0, props.precision);
newValue = parts.join('.');
}
}
emit('update:modelValue', newValue);
};
const handleBlur = (event) => {
const value = event.target.value;
if (value === '' || value === '-') {
emit('update:modelValue', '');
emit('blur', event);
return;
}
const numValue = parseFloat(value);
if (isNaN(numValue)) {
emit('update:modelValue', '');
emit('blur', event);
return;
}
// 应用精度
let finalValue = numValue;
if (props.precision !== undefined) {
finalValue = parseFloat(numValue.toFixed(props.precision));
}
// 限制范围
if (props.min !== undefined && finalValue < props.min) {
finalValue = props.min;
}
if (props.max !== undefined && finalValue > props.max) {
finalValue = props.max;
}
emit('update:modelValue', String(finalValue));
emit('blur', event);
};
const handleChange = (value) => {
emit('change', value);
};
</script>
<style scoped lang="scss">
:deep(.el-input__inner) {
text-align: left;
}
</style>