273 lines
7.1 KiB
Vue
273 lines
7.1 KiB
Vue
<template>
|
|
<view class="unit-converter">
|
|
<!-- 数值输入框 -->
|
|
<input v-model="inputValue" type="number" @input="handleInputChange" class="input-field" :style="{ width: width + 'px' }" />
|
|
<!-- 单位标签 -->
|
|
<text @click="toggleUnit" @dblclick="openUnitSelector" class="unit-label" :style="{ color: 'blue' }">
|
|
{{ displayUnitName }}
|
|
</text>
|
|
<!-- 单位选择弹出窗口 -->
|
|
<!-- uni-popup 弹窗 -->
|
|
<uni-popup ref="unitSelectorPopup" type="bottom" :show="showUnitSelector" @close="onPopupClose">
|
|
<view class="unit-selector">
|
|
<view v-for="unit in filteredUnitList" :key="unit.id" @click="selectUnit(unit)" class="unit-option">
|
|
{{ showEnglishOnly ? unit.unitName.split('(')[0] : unit.unitName }}
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { listConversion } from '@/api/system/conversion.js';
|
|
|
|
export default {
|
|
props: {
|
|
// 单位类型
|
|
unitType: {
|
|
type: String,
|
|
default: 'length'
|
|
},
|
|
// 是否只显示英文部分
|
|
showEnglishOnly: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
// 当前单位名称
|
|
unitName: {
|
|
type: String,
|
|
required: false,
|
|
default: ''
|
|
},
|
|
// 当前数值
|
|
value: {
|
|
type: Number,
|
|
required: true
|
|
},
|
|
// 小数点位数
|
|
decimalPlaces: {
|
|
type: Number,
|
|
default: 2
|
|
},
|
|
width: {
|
|
type: Number,
|
|
required: false,
|
|
default: 80
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
inputValue: this.value, // 输入的数值
|
|
currentUnit: null, // 当前单位
|
|
unitList: [], // 单位列表
|
|
showUnitSelector: false // 是否显示单位选择窗口
|
|
};
|
|
},
|
|
onLoad() {
|
|
// 在页面加载时添加全局点击事件监听器
|
|
uni.$on('globalClick', this.handleClickOutside);
|
|
},
|
|
onUnload() {
|
|
// 在页面卸载时移除全局点击事件监听器
|
|
uni.$off('globalClick', this.handleClickOutside);
|
|
},
|
|
computed: {
|
|
// 显示的单位名称
|
|
displayUnitName() {
|
|
if (!this.currentUnit) return '';
|
|
return this.showEnglishOnly ? this.currentUnit.unitName.split('(')[0] : this.currentUnit.unitName;
|
|
},
|
|
// 过滤后的单位列表(排除当前单位)
|
|
filteredUnitList() {
|
|
return this.unitList.filter((unit) => unit.unitName !== this.currentUnit?.unitName);
|
|
}
|
|
},
|
|
watch: {
|
|
// 监听 unitType 变化,重新加载单位列表
|
|
unitType: {
|
|
immediate: true,
|
|
handler(newVal) {
|
|
this.loadUnitList(newVal);
|
|
}
|
|
},
|
|
// 监听 unitName 变化,更新当前单位
|
|
unitName: {
|
|
immediate: true,
|
|
handler(newVal) {
|
|
console.log(newVal);
|
|
this.currentUnit = this.unitList.find((unit) => unit.unitName == newVal);
|
|
}
|
|
},
|
|
// 监听 value 变化,更新输入框的值
|
|
value: {
|
|
immediate: true,
|
|
handler(newVal) {
|
|
this.inputValue = newVal;
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
// 处理全局点击事件
|
|
handleClickOutside(event) {
|
|
if (this.$refs.unitSelector && !this.$refs.unitSelector.contains(event.target)) {
|
|
this.showUnitSelector = false;
|
|
}
|
|
},
|
|
// 切换单位选择器的显示状态
|
|
toggleUnitSelector() {
|
|
this.showUnitSelector = !this.showUnitSelector;
|
|
},
|
|
// 加载单位列表
|
|
async loadUnitList(unitType) {
|
|
try {
|
|
const response = await listConversion({ pageSize: 100, unitType: unitType });
|
|
console.log(response);
|
|
this.unitList = response.rows;
|
|
if (this.unitName == '') {
|
|
// 处理默认基准单位
|
|
this.currentUnit = this.unitList.find((unit) => unit.baseUnit == 1);
|
|
console.log(this.currentUnit);
|
|
} else {
|
|
this.currentUnit = this.unitList.find((unit) => unit.unitName == this.unitName);
|
|
console.log(this.currentUnit);
|
|
if (this.currentUnit === undefined) {
|
|
this.currentUnit = this.unitList.find((unit) => unit.baseUnit === 1);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load unit list:', error);
|
|
}
|
|
},
|
|
// 处理输入框变化
|
|
handleInputChange() {
|
|
this.$emit('input', this.inputValue); // 将输入值同步到父组件
|
|
this.convertAndEmit();
|
|
},
|
|
// 切换单位
|
|
toggleUnit() {
|
|
const currentIndex = this.unitList.indexOf(this.currentUnit);
|
|
const nextIndex = (currentIndex + 1) % this.unitList.length;
|
|
let oldUnit = this.currentUnit;
|
|
let newUnit = this.unitList[nextIndex];
|
|
this.currentUnit = newUnit;
|
|
// console.log('切换单位', currentIndex, nextIndex, this.currentUnit);
|
|
this.convertAndEmit(oldUnit, newUnit);
|
|
},
|
|
// 打开单位选择窗口
|
|
openUnitSelector() {
|
|
this.showUnitSelector = true;
|
|
},
|
|
// 选择单位
|
|
selectUnit(unit) {
|
|
console.log('所选择的单位', unit);
|
|
let oldUnit = this.currentUnit;
|
|
let newUnit = unit;
|
|
this.currentUnit = unit;
|
|
this.showUnitSelector = false;
|
|
this.convertAndEmit(oldUnit, newUnit);
|
|
},
|
|
// 换算并提交结果
|
|
convertAndEmit(oldUnit, newUnit) {
|
|
if (!newUnit) return;
|
|
// 获取基准单位
|
|
const baseUnit = this.unitList.find((unit) => unit.baseUnit === 1);
|
|
if (!baseUnit) return;
|
|
// 将输入值转换为基准单位的值
|
|
const baseValue = this.inputValue / oldUnit.conversionFactor;
|
|
// 将基准单位的值转换为新单位的值
|
|
const newValue = baseValue * newUnit.conversionFactor;
|
|
|
|
console.log('转换值', newUnit.unitName, this.inputValue, baseValue, newValue);
|
|
|
|
let roundedValue;
|
|
if (newUnit.unitName === 'ly(光年)') {
|
|
// 对于光年,使用科学计数法显示结果
|
|
roundedValue = newValue.toExponential();
|
|
} else {
|
|
roundedValue = this.roundToDecimalPlaces(newValue);
|
|
}
|
|
|
|
// 提交结果给父组件
|
|
this.$emit('conversion', {
|
|
initialValue: this.inputValue,
|
|
newValue: roundedValue,
|
|
oldUnit: oldUnit.unitName,
|
|
newUnit: newUnit.unitName
|
|
});
|
|
|
|
this.inputValue = parseFloat(roundedValue);
|
|
|
|
// 更新父组件的 unitName
|
|
this.$emit('update:unitName', this.currentUnit.unitName);
|
|
},
|
|
// 四舍六入五留双
|
|
// 按照四舍六入五留双处理结果 conversionFactor
|
|
roundToDecimalPlaces(value) {
|
|
const multiplier = Math.pow(10, this.decimalPlaces);
|
|
const val = value * multiplier;
|
|
const intVal = Math.trunc(val);
|
|
const decimalPart = val - intVal;
|
|
if (decimalPart < 0.5) {
|
|
return intVal / multiplier;
|
|
} else if (decimalPart > 0.5) {
|
|
return (intVal + 1) / multiplier;
|
|
} else {
|
|
return intVal % 2 === 0 ? intVal / multiplier : (intVal + 1) / multiplier;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.unit-converter {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
position: relative;
|
|
}
|
|
|
|
.input-field {
|
|
padding: 2px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.unit-label {
|
|
cursor: pointer;
|
|
font-weight: bold;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.unit-selector {
|
|
/* 设置容器的最大高度,当内容超出这个高度时会出现滚动条 */
|
|
max-height: 200px;
|
|
/* 超出内容时显示纵向滚动条 */
|
|
overflow-y: auto;
|
|
/* 横向内容不溢出,隐藏多余部分 */
|
|
overflow-x: hidden;
|
|
/* 其他样式保持不变 */
|
|
position: absolute;
|
|
z-index: 1000;
|
|
background-color: white;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
padding: 2px 0;
|
|
min-width: 100px;
|
|
list-style-type: none;
|
|
margin: 0;
|
|
}
|
|
|
|
.unit-option {
|
|
padding: 2px 10px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.unit-option:hover {
|
|
background-color: #f0f0f0;
|
|
}
|
|
</style>
|