Newer
Older
xc-business-system / src / commonMethods / useScientificNotation.ts
// // 引入 BigNumber 库,用于处理高精度数字计算
// import BigNumber from 'bignumber.js'
// // 引入自定义的四舍五入方法
// import { useRound } from '@/commonMethods/useRound'

// /**
//  * 转换科学计数法
//  * @param value 待转换的小数,可以是数字类型或字符串类型
//  * @param notationDigit 科学计数法中尾数部分保留的小数位数(四舍五入),例如 1.2344444e-5 -> 1.234e-5
//  * @param numberDigit 非科学计数法时保留的小数位数(四舍五入)
//  * @param standard 转换为科学计数法的标准,小于这个数才会进行转换
//  * @returns 转换后的科学计数法字符串,如果不满足转换条件则返回原数字的字符串形式
//  */
// export function useScientificNotation(value: number | string, notationDigit = 2, numberDigit = 2, standard = 0.001) {
//   // 打印未处理的数据,方便调试
//   console.log(value, '未处理数据')

//   // 如果传入的值为空,直接返回空字符串
//   if (!value) {
//     return ''
//   }

//   // 如果传入的值为 0,直接返回字符串 '0'
//   if (value === 0) {
//     return '0'
//   }

//   // 使用 BigNumber 处理传入的值,并将其转换为字符串形式
//   var res = (BigNumber(value)).toString()

//   // 检查结果字符串中是否包含科学计数法的标识 'E' 或 'e'
//   if (res.includes('E') || res.includes('e')) {
//     // 将 'E' 统一替换为 'e'
//     res = res.replace('E', 'e')
//     // 如果本身就是科学计数法,对尾数部分进行四舍五入处理
//     // 先将字符串按 'e' 分割,对前面的尾数部分使用 useRound 方法进行四舍五入,再拼接上指数部分
//     return `${useRound(res.split('e')[0], notationDigit)}e${res.split('e')[1]}`
//   }

//   // 比较传入的值和转换标准的大小,如果小于标准值则进行后续处理
//   if (BigNumber(value).comparedTo(standard).toString() === '-1') {
//     // 检查结果字符串中是否包含小数点,只处理小数情况
//     if (res.includes('.')) {
//       // 找到小数点在字符串中的索引位置
//       const pointIndex = res.indexOf('.')

//       // 检查结果字符串中是否包含负号,判断是否为负数
//       if (res.includes('-')) {
//         // 如果小数点后的位数小于 4,不进行转换,直接返回原字符串
//         if (res.length - 1 - pointIndex < 4) {
//           return res
//         }
//         // 如果负数的整数部分大于 0
//         if (Number(res[1]) > 0) {
//           // 如果 numberDigit 未定义或者为 0,不进行转换,直接返回原字符串
//           if (!String(numberDigit) || String(numberDigit) === '0') {
//             return res
//           }
//           else {
//             // 否则对原数值进行四舍五入处理
//             return useRound(value, numberDigit)
//           }
//         }
//       }

//       // 用于记录第一个非零小数位的索引
//       let digitsIndex = 0
//       // 从小数点后的位置开始遍历字符串,找到第一个非零数字的索引
//       for (let i = pointIndex + 1; i < res.length; i++) {
//         if (Number(res[i]) > 0) {
//           digitsIndex = i
//           break
//         }
//       }

//       // 如果没有找到非零小数位,不进行转换,直接返回原字符串
//       if (digitsIndex === 0) {
//         return res
//       }

//       // 提取非零小数位及后面的数字,进行四舍五入处理
//       const digitsNumber = useRound(`${res[digitsIndex]}.${res.substring(digitsIndex + 1, res.length)}`, notationDigit)
//       // 拼接最终的科学计数法字符串,考虑正负号和指数部分
//       return `${res[0] === '-' ? '-' : ''}${digitsNumber}e-${digitsIndex - pointIndex}`
//     }
//     else {
//       // 如果不是小数,不进行转换,直接返回原字符串
//       return res
//     }
//   }
//   else {
//     console.log('--------------------');

//     // 如果不小于转换标准,不进行转换,直接返回原字符串
//     return res
//   }
// }

/**
 * 根据自定义规则将输入值转换为科学计数法或按要求保留有效数字,若已是科学计数法则直接返回
 * @param {unknown} value - 输入的值,可以是任意类型
 * @param {number} integerDigits - 判断是否转换为科学计数法的整数部分最小位数
 * @param {number} decimalDigits - 判断是否转换为科学计数法的小数部分最小位数
 * @returns {number | string} - 若满足转换条件则返回科学计数法字符串,按要求保留有效数字,否则返回原数字或无法转换时返回原输入
 */
export function useScientificNotation(value: unknown, integerDigits = 6, decimalDigits = 4): number | string {
  console.log('接收到的需要处理的数据', value)

  // 先将传入的值转换为字符串形式,方便后续判断是否为科学计数法
  const valueStr = String(value)

  // 判断是否已经是科学计数法(包含 'e' 或 'E')
  if (valueStr.includes('e') || valueStr.includes('E')) {
    return valueStr
  }

  let num: number | string
  // 判断传入的值是否已经是数字类型
  if (typeof value === 'number') {
    // 如果是数字类型,直接赋值给 num
    num = value
  }
  else {
    // 如果不是数字类型,尝试将其转换为数字
    num = Number(value)
    // 检查转换后的结果是否为 NaN(非数字)
    if (isNaN(num)) {
      // 如果是 NaN,说明无法转换为数字,直接返回原输入值
      return value as string
    }
  }

  // 当数值 > 1 或者 < -1 时,保留小数后 2 位有效数字
  if (num >= 1 || num <= -1) {
    num = parseFloat(num.toFixed(2))
  }

  // 当数值为 0.** 或者 -0.** 时,保留小数点后除 0 外的 3 位有效数字,转科学计数法,不管几位都要转
  if (num > -1 && num < 1 && num !== 0) {
    const numStr = num.toString()
    let nonZeroIndex = 0
    // 找到小数点后第一个非零数字的位置
    for (let i = numStr.indexOf('.') + 1; i < numStr.length; i++) {
      if (numStr[i] !== '0') {
        nonZeroIndex = i
        break
      }
    }
    // 计算需要保留的小数位数
    const precision = nonZeroIndex + 3 - (numStr.indexOf('.') + 1)
    num = parseFloat(num.toFixed(precision))
    num = num.toExponential(2)
  }

  // // 将数字转换为字符串,方便后续拆分整数部分和小数部分
  // const numStr = num.toString()
  // let integerPart: string
  // let decimalPart: string
  // // 检查数字字符串中是否包含小数点
  // if (numStr.includes('.')) {
  //   // 如果包含小数点,使用 split 方法按小数点分割字符串,并分别赋值给整数部分和小数部分
  //   [integerPart, decimalPart] = numStr.split('.')
  // }
  // else {
  //   // 如果不包含小数点,说明是整数,将整个字符串赋值给整数部分,小数部分为空字符串
  //   integerPart = numStr
  //   decimalPart = ''
  // }
  // console.log('------------------------integerPart', integerPart)

  // // 检查整数部分的长度是否大于等于指定的整数位数 或者 小数部分的长度是否大于等于指定的小数位数
  // if (integerPart.length >= integerDigits || decimalPart.length >= decimalDigits) {
  // // 如果满足条件,将数字转换为科学计数法表示的字符串并返回,保留 2 位小数
  // console.log('进行科学技术法的转换', num.toExponential(2))
  // return num.toExponential(2)
  // }
  // 如果不满足条件,直接返回原数字
  return num
}