useFieldValueTransform.js 5.31 KB
/**
 * 字段值转换 Composable
 *
 * @description 封装字段值转换逻辑,提供统一的转换 API
 * @module composables/useFieldValueTransform
 * @author Claude Code
 * @created 2026-02-14
 */

import { computed } from 'vue'
import {
  fenToYuan,
  yuanToFen,
  transformFieldValue,
  batchTransformFields,
  reverseTransformFields
} from '@/utils/planFieldTransformers'
import { PLAN_FIELD_DEFINITIONS, TRANSFORM_TYPES } from '@/config/plan-fields'

/**
 * 使用字段值转换
 *
 * @description 提供字段值的双向转换能力
 * @param {Object} formData - 表单数据
 * @param {Object} fieldDefinitions - 字段定义(来自 PLAN_FIELD_DEFINITIONS)
 * @returns {Object} 转换方法和计算属性
 *
 * @example
 * const { yuanFormData, fenFormData, toYuan, toFen, reset } = useFieldValueTransform(formData, fieldDefinitions)
 *
 * // 元转分(用于显示)
 * toYuan('annual_premium', 10000)  // => '10000.00' (分)
 *
 * // 分转元(用于提交)
 * toFen('annual_premium', 1000)  // => 10000 (元)
 */
// eslint-disable-next-line react-hooks/rules-of-hooks
export function useFieldValueTransform(formData, fieldDefinitions) {
  /**
   * 转换为分值(用于显示)
   *
   * @description 将表单中的值统一转换为分值显示
   * @param {string} fieldKey - 字段名称
   * @param {*} value - 原始值(可能是元或分)
   * @returns {*} 转换后的分值
   *
   * @example
   * toYuan('annual_premium', 10000)  // => '10000.00' (分字符串,10000元×100=1000000分)
   * toYuan('annual_premium', 10000)  // => 10000 (分整数,API存储的是分)
   */
  const toYuan = (fieldKey, value) => {
    const definition = PLAN_FIELD_DEFINITIONS[fieldKey]
    if (!definition) return value

    const { transform } = definition
    // 如果字段定义了 fen_to_yuan,表示API存的是分,需要转为元显示
    if (transform === TRANSFORM_TYPES.FEN_TO_YUAN) {
      // API存的是分(整数),转为元显示(带两位小数)
      return fenToYuan(value)
    }

    // 默认返回原值(元值直接显示)
    return value
  }

  /**
   * 转换为分值(用于提交)
   *
   * @description 将表单中的值统一转换为分值提交
   * @param {string} fieldKey - 字段名称
   * @param {*} value - 原始值(可能是元或分)
   * @returns {*} 转换后的分值
   *
   * @example
   * toFen('annual_premium', '100.00')  // => 10000 (分值整数,元值×100)
   * toFen('withdrawal_period', 3)  // => 3 (直接是元)
   */
  const toFen = (fieldKey, value) => {
    const definition = PLAN_FIELD_DEFINITIONS[fieldKey]
    if (!definition) return value

    const { transform } = definition
    // 如果字段定义了 fen_to_yuan,表示API存的是分,需要转为元显示
    // 所以提交时,元→分转换(×100)
    if (transform === TRANSFORM_TYPES.FEN_TO_YUAN) {
      // 元值转分值:10000 → 1000000(API存分值)
      const numValue = parseFloat(value)
      if (!Number.isNaN(numValue)) {
        return Math.round(numValue * 100)
      }
      return value
    }

    // 默认返回原值(分值直接提交)
    return value
  }

  /**
   * 批量转换为分值(用于初始化表单显示)
   *
   * @description 将表单数据(元值)转换为分值格式(带两位小数)用于显示
   * @param {Object} formData - 表单数据
   * @returns {Object} 分值格式的数据
   */
  const batchToYuanFunc = (formData) => {
    // 遍历所有字段,转换为元值显示格式
    const result = {}
    for (const [key, value] of Object.entries(formData)) {
      const definition = PLAN_FIELD_DEFINITIONS[key]
      if (!definition) {
        result[key] = value
        continue
      }

      // 如果字段定义了 fen_to_yuan,表示 API 存的是分,需要转为元显示
      if (definition.transform === TRANSFORM_TYPES.FEN_TO_YUAN) {
        result[key] = fenToYuan(value)
      } else {
        result[key] = value
      }
    }
    return result
  }

  /**
   * 批量转换为分值(用于提交 API)
   *
   * @description 将表单的元值数据批量转换为分值整数
   * @param {Object} yuanData - 元值数据
   * @returns {Object} 分值数据
   */
  const batchToFenFunc = (yuanData) => {
    const result = {}
    for (const [key, value] of Object.entries(yuanData)) {
      const definition = PLAN_FIELD_DEFINITIONS[key]
      if (!definition) {
        result[key] = value
        continue
      }

      // 元值转分值:×100
      if (definition.transform === TRANSFORM_TYPES.FEN_TO_YUAN) {
        const numValue = parseFloat(value)
        if (!Number.isNaN(numValue)) {
          result[key] = Math.round(numValue * 100)
        } else {
          result[key] = value
        }
      } else {
        result[key] = value
      }
    }
    return result
  }

  // 计算属性:表单显示数据(元值转分值显示)
  const displayData = computed(() => {
    return batchToYuanFunc(formData.value)
  })

  // 计算属性:API 提交数据(元值转分值)
  const submitData = computed(() => {
    return batchToFenFunc(formData.value)
  })

  return {
    toYuan,
    toFen,
    batchToFen: batchToFenFunc, // 批量转换元→分
    displayData, // 计算属性:表单显示数据(元值转分值显示)
    submitData  // 计算属性:API 提交数据(元值转分值)
  }
}