华西海圻ELN前端工程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

223 lines
5.7 KiB

/**
* 体积单位转换
* 支持的体积单位:pL, nL, uL (μL), mL, L
*/
class VolumeConverter {
// 体积单位换算系数(以升L为基准)
unitFactors = {
'L': 1,
'mL': 1e-3, // 毫升
'μL': 1e-6, // 微升
'uL': 1e-6, // 微升(别名)
'nL': 1e-9, // 纳升
'pL': 1e-12 // 皮升
};
// 支持的单位列表
supportedUnits = ['L', 'mL', 'μL', 'uL', 'nL', 'pL'];
/**
* 规范化单位(统一别名)
*/
normalizeUnit(unit) {
const aliasMap = {
'ul': 'uL',
'Ul': 'uL',
'UL': 'uL',
'μl': 'μL',
'Μl': 'μL',
'ΜL': 'μL'
};
// 转换为标准形式
let normalized = unit;
// 处理μ符号的各种表示
if (unit.toLowerCase() === 'ul' || unit === 'μL' || unit === 'uL') {
normalized = 'μL';
}
// 其他别名处理
else if (aliasMap[unit]) {
normalized = aliasMap[unit];
}
return normalized;
}
/**
* 验证单位是否支持
*/
isSupportedUnit(unit) {
const normalizedUnit = this.normalizeUnit(unit);
return this.supportedUnits.includes(normalizedUnit);
}
/**
* 获取所有支持的单位
*/
getSupportedUnits() {
return [...this.supportedUnits];
}
/**
* 体积单位转换(核心方法)
* @param {number|string} value - 待转换的值
* @param {string} targetUnit - 目标单位
* @returns {number} 转换后的值
*/
convert(value, targetUnit) {
// 1. 解析输入值
let inputValue, inputUnit;
if (typeof value === 'string') {
const result = this.parseValue(value);
inputValue = result.value;
inputUnit = result.unit;
} else if (typeof value === 'number') {
inputValue = value;
inputUnit = ''; // 无量纲
} else {
throw new Error('输入值必须是数字或字符串');
}
const normalizedTargetUnit = this.normalizeUnit(targetUnit);
// 2. 验证目标单位
if (!this.isSupportedUnit(normalizedTargetUnit)) {
throw new Error(`不支持的单位: ${targetUnit}。支持的单位: ${this.supportedUnits.join(', ')}`);
}
// 3. 检查是否需要转换
if (!inputUnit) {
return inputValue; // 无量纲输入,直接返回
}
if (inputUnit === normalizedTargetUnit) {
return inputValue; // 相同单位,直接返回
}
// 4. 执行转换
return this._convertValue(inputValue, inputUnit, normalizedTargetUnit);
}
/**
* 解析带单位的数值字符串
*/
parseValue(valueStr) {
const str = valueStr.toString().trim();
// 支持科学计数法
const match = str.match(/^([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*([a-zA-Zμ]+)$/);
if (!match) {
throw new Error(`格式错误: ${valueStr}。正确格式如: "10mL", "5.5μL", "1.23e-6L"`);
}
const value = parseFloat(match[1]);
const rawUnit = match[2];
const unit = this.normalizeUnit(rawUnit);
// 验证单位是否支持
if (!this.isSupportedUnit(unit)) {
throw new Error(`不支持的单位: ${rawUnit}。支持的单位: ${this.supportedUnits.join(', ')}`);
}
return { value, unit };
}
/**
* 内部转换逻辑
*/
_convertValue(value, fromUnit, toUnit) {
// 统一处理μL的多种表示
const normalizedFromUnit = this.normalizeUnit(fromUnit);
const normalizedToUnit = this.normalizeUnit(toUnit);
// 获取换算系数
const fromFactor = this.unitFactors[normalizedFromUnit];
const toFactor = this.unitFactors[normalizedToUnit];
if (fromFactor === undefined || toFactor === undefined) {
throw new Error(`单位换算系数未定义: ${fromUnit}${toUnit}`);
}
// 转换公式:value * (fromFactor / toFactor)
return value * (fromFactor / toFactor);
}
/**
* 批量转换
*/
convertAll(values, targetUnit) {
if (!Array.isArray(values)) {
throw new Error('输入必须是数组');
}
return values.map(value => this.convert(value, targetUnit));
}
/**
* 格式化输出
*/
format(value, unit, precision = 6) {
const numValue = typeof value === 'string' ? parseFloat(value) : value;
if (isNaN(numValue)) {
return 'NaN';
}
// 根据数值大小选择合适的显示格式
const absValue = Math.abs(numValue);
if (absValue === 0) {
return `0 ${unit}`;
}
if (absValue < 0.001 || absValue >= 1000000) {
return `${numValue.toExponential(precision)} ${unit}`;
}
// 确定小数位数
let decimalPlaces = precision;
if (absValue < 1) {
decimalPlaces = Math.max(precision, Math.ceil(-Math.log10(absValue)) + 2);
} else if (absValue >= 100) {
decimalPlaces = Math.max(0, precision - 2);
}
return `${numValue.toFixed(decimalPlaces)} ${unit}`;
}
/**
* 获取单位换算关系
*/
getConversionFactor(fromUnit, toUnit) {
const normalizedFromUnit = this.normalizeUnit(fromUnit);
const normalizedToUnit = this.normalizeUnit(toUnit);
if (!this.isSupportedUnit(normalizedFromUnit) || !this.isSupportedUnit(normalizedToUnit)) {
throw new Error('单位不支持');
}
const fromFactor = this.unitFactors[normalizedFromUnit];
const toFactor = this.unitFactors[normalizedToUnit];
return fromFactor / toFactor;
}
/**
* 创建快捷转换方法
*/
createShortcutMethods() {``
const shortcuts = {};
this.supportedUnits.forEach(unit => {
const methodName = `to${unit.replace('μ', 'u')}`;
shortcuts[methodName] = (value) => this.convert(value, unit);
});
return shortcuts;
}
}
export const volumeConverter = new VolumeConverter();