<template>
  <el-form
    ref="formRef"
    :model="localModel"
    :rules="formRules"
    label-width="auto"
    v-bind="$attrs"
    :validate-on-rule-change="false"
  >
    <el-row :gutter="20">
      <el-col v-for="item in visibleConfig" :key="item.prop" :span="item.span || 6">
        <el-form-item
          :label="item.label"
          :prop="item.prop"
          :class="{ 'search-form-item': isSearch }"
          :label-position="item.labelPosition || 'top'"
        >
          <!-- Input -->
          <el-input
            v-if="item.type === 'input'"
            v-model="localModel[item.prop]"
            :placeholder="item.placeholder || `请输入${item.label}`"
            :clearable="true"
            :disabled="item.disabled"
            @input="val => handleNumberInput(val, item)"
            @change="val => handleModelChange(val, item)"
            :formatter="
              value => (item.inputType ? `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',') : value)
            "
            :parser="value => value.replace(/\$\s?|(,*)/g, '')"
          />

          <!-- Select (支持 dictType / api / options) -->
          <el-select
            v-else-if="item.type === 'select'"
            v-model="localModel[item.prop]"
            :multiple="!!item.multiple"
            :placeholder="item.placeholder || `请选择${item.label}`"
            :clearable="true"
            filterable
            :disabled="item.disabled"
            :loading="remoteLoading[item.prop] || false"
            @change="val => handleModelChange(val, item)"
            @focus="() => loadRemoteOptions(item)"
            @filter-change="keyword => handleFilterChange(keyword, item)"
          >
            <el-option
              v-for="opt in getSelectOptions(item)"
              :key="opt.value"
              :label="opt.label"
              :value="opt.value"
            />
          </el-select>
          <!-- Date -->
          <el-date-picker
            v-else-if="item.type === 'date'"
            v-model="localModel[item.prop]"
            type="date"
            :placeholder="`选择${item.label}`"
            :disabled="item.disabled"
            :value-format="item.valueFormat || 'YYYY-MM-DD'"
            style="width: 100%"
            :disabled-date="getDisabledDateFn(item)"
            @change="val => handleModelChange(val, item)"
          />
          <!-- Month -->
          <el-date-picker
            v-else-if="item.type === 'month'"
            v-model="localModel[item.prop]"
            type="month"
            :placeholder="`选择${item.label}`"
            :value-format="item.valueFormat || 'YYYY-MM'"
            style="width: 100%"
            :disabled="item.disabled"
            :disabled-date="getDisabledDateFn(item)"
            @change="val => handleModelChange(val, item)"
          />

          <!-- Daterange -->
          <el-date-picker
            v-else-if="item.type === 'daterange'"
            v-model="localModel[item.prop]"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            :value-format="item.valueFormat || 'YYYY-MM-DD'"
            :disabled="item.disabled"
            :disabled-date="getDisabledDateFn(item)"
            style="width: 100%"
            @change="val => handleModelChange(val, item)"
          />

          <!-- Checkbox Group -->
          <el-checkbox-group
            v-else-if="item.type === 'checkbox-group'"
            v-model="localModel[item.prop]"
            :disabled="item.disabled"
            @change="val => handleModelChange(val, item)"
          >
            <el-checkbox v-for="opt in getSelectOptions(item)" :key="opt.value" :label="opt.value">
              {{ opt.label }}
            </el-checkbox>
          </el-checkbox-group>
          <!-- textarea -->
          <el-input
            v-else-if="item.type === 'textarea'"
            v-model="localModel[item.prop]"
            style="width: 240px"
            autosize
            :disabled="item.disabled"
            type="textarea"
            placeholder="请输入"
            :clearable="true"
            @change="val => handleModelChange(val, item)"
          />
          <!-- Upload 回显值得时候数据格式至少是[{url: '必须要传', name: 'name不是必须的根据需要传值'}]-->
          <el-upload
            v-else-if="item.type === 'upload'"
            v-model:file-list="localModel[item.prop]"
            :action="item.action"
            :headers="item.headers"
            :multiple="!!item.multiple"
            :limit="item.limit || (item.multiple ? 999 : 1)"
            :accept="item.accept"
            :list-type="item.listType || 'text'"
            :disabled="item.disabled"
            :auto-upload="true"
            :show-file-list="item.showFileList"
            :on-exceed="handleExceed"
            :before-upload="file => beforeUpload(file, item)"
            :on-success="(res, file, fileList) => handleUploadSuccess(res, file, fileList, item)"
            :on-error="(err, file, fileList) => handleUploadError(err, file, fileList, item)"
            :on-remove="(file, fileList) => handleUploadRemove(file, fileList, item)"
          >
            <el-icon class="iconStyle" :size="20" v-if="item.uploadType === 'image'">
              <Upload />
            </el-icon>
            <el-button
              v-else
              size="small"
              type="primary"
              :link="item.link"
              :disabled="item.disabled"
            >
              {{ '点击上传文件' }}
            </el-button>
            <template #tip v-if="item.maxSize || item.accept">
              <div class="el-upload__tip">
                <span v-if="item.maxSize">大小不超过 {{ formatFileSize(item.maxSize) }}</span>
                <span v-if="item.accept">支持格式：{{ item.accept }}</span>
              </div>
            </template>
          </el-upload>
          <span v-else>不支持的类型: {{ item.type }}</span>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>

<script setup>
import { ref, watch, onMounted, nextTick, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Upload } from '@element-plus/icons-vue'
// 🔑 引入你的字典方法
import useDictStore from '@/store/modules/dict'
import { getDicts } from '@/api/system/dict/data'
import request from '@/utils/request'
import dayjs from 'dayjs'
// ==================== 上传文件 ====================
// 文件大小格式化
function formatFileSize(bytes) {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
function beforeUpload(file, item) {
  // 检查文件大小
  if (item.maxSize && file.size > item.maxSize) {
    ElMessage.error(`文件 ${file.name} 超出大小限制（最大 ${formatFileSize(item.maxSize)}）`)
    return false
  }

  // 检查类型（accept 已由浏览器限制，但可二次校验）
  if (item.accept) {
    const allowed = item.accept.split(',').map(ext => ext.trim().toLowerCase())
    const fileExt = '.' + file.name.split('.').pop().toLowerCase()
    if (!allowed.includes(fileExt)) {
      ElMessage.error(`文件类型不支持，仅支持：${item.accept}`)
      return false
    }
  }

  return true
}
function handleUploadSuccess(response, file, fileList, item) {
  // 假设你的后端返回格式：{ code: 200, data: { url: '...', name: 'xxx.pdf' } }
  // 你可以通过 item.responseMap 自定义映射，这里先用通用方式

  const data = response.data || response
  const url = data.url || data.fileUrl || data.path
  const name = data.name || data.fileName || file.name

  if (!url) {
    ElMessage.error('上传成功但未返回文件地址')
    return
  }

  // 找到刚上传的文件（通过 uid），替换其 url
  const targetFile = fileList.find(f => f.uid === file.uid)
  if (targetFile) {
    targetFile.url = url
    targetFile.name = name
  }

  // 触发 model 更新
  handleModelChange([...fileList], item)
  ElMessage.success(`文件 ${file.name} 上传成功`)

  // console.log('上传成功', item)
}
function handleExceed(files, fileList) {
  ElMessage.warning('超出文件数量限制')
}

function handleUploadError(error, file, fileList, item) {
  ElMessage.error(`文件 ${file.name} 上传失败`)
  console.error('Upload error:', error)
}

function handleUploadRemove(file, fileList, item) {
  // 用户删除文件时，同步更新 model
  handleModelChange([...fileList], item)
}
// ==================== 工具函数：深拷贝配置（保留函数） ====================
function deepCloneConfig(obj) {
  if (obj === null || typeof obj !== 'object') return obj
  if (Array.isArray(obj)) return obj.map(deepCloneConfig)
  const cloned = {}
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      const val = obj[key]
      cloned[key] = typeof val === 'function' ? val : deepCloneConfig(val)
    }
  }
  return cloned
}
function parseToDate(str) {
  if (!str) return null
  if (str === 'today') {
    return dayjs().startOf('day')
  }
  if (typeof str === 'string') {
    const d = dayjs(str)
    return d.isValid() ? d.startOf('day') : null
  }
  if (str instanceof Date) {
    return dayjs(str).startOf('day')
  }
  return null
}
// ==================== 生成 disabledDate 函数 ====================
function getDisabledDateFn(item) {
  const { minDate, maxDate } = item

  // 如果都没有限制，返回 null（不禁用任何日期）
  if (minDate == null && maxDate == null) {
    return () => false
  }

  return date => {
    const currentDate = dayjs(date).startOf('day')
    let minD = null
    let maxD = null

    // 解析最小日期
    if (minDate != null) {
      if (typeof minDate === 'function') {
        const val = minDate(localModel.value)
        minD = parseToDate(val)
      } else {
        minD = parseToDate(minDate)
      }
    }

    // 解析最大日期
    if (maxDate != null) {
      if (typeof maxDate === 'function') {
        const val = maxDate(localModel.value)
        maxD = parseToDate(val)
      } else {
        maxD = parseToDate(maxDate)
      }
    }

    // 判断是否被禁用
    if (minD && currentDate.isBefore(minD)) {
      return true
    }
    if (maxD && currentDate.isAfter(maxD)) {
      return true
    }
    return false
  }
}
// ==================== Props & Emits ====================
const props = defineProps({
  modelValue: { type: Object, default: () => ({}) },
  config: { type: Array, default: () => [] },
  isSearch: { type: Boolean, default: false }
})

const emit = defineEmits(['update:modelValue', 'update', 'selectChange', 'uploadSuccess'])

// ==================== Refs ====================
const formRef = ref(null)
// 使用 shallowRef 避免深层响应式（表单通常扁平）
const localModel = ref({ ...props.modelValue })
// 记录哪些字段的字典已加载
const dictLoaded = ref(new Set())
const internalConfig = ref([])
const remoteOptions = ref({}) // { prop: [options] }
const remoteLoading = ref({}) // { prop: boolean }

// ==================== 条件显隐 & 规则 ====================
const visibleConfig = computed(() => {
  return internalConfig.value.filter(item => {
    if (typeof item.visible === 'function') {
      return item.visible(localModel.value)
    }
    return true
  })
})

const formRules = computed(() => {
  const rules = {}
  visibleConfig.value.forEach(item => {
    if (item.rules) rules[item.prop] = item.rules
  })
  return rules
})

// 1. 外部 modelValue 变化时，安全同步（仅当内容不同时）
// 监听 config 变化（支持动态 config）
watch(
  () => props.config,
  newConfig => {
    if (!newConfig || newConfig.length === 0) return

    internalConfig.value = deepCloneConfig(newConfig)

    // 构建初始模型
    const initialModel = {}
    for (const item of internalConfig.value) {
      const key = item.prop
      // 优先用父传值，否则用默认值
      if (props.modelValue?.[key] !== undefined) {
        initialModel[key] = props.modelValue[key]
      } else if (item.multiple || ['checkbox-group', 'daterange'].includes(item.type)) {
        initialModel[key] = item.defaultValue ?? []
      } else {
        initialModel[key] = item.defaultValue ?? ''
      }
    }

    // ✅ 在这里同步 modelValue（包括 extra 字段）
    localModel.value = syncModelFromProps(props.modelValue, internalConfig.value)
    console.log('子组件监测config变化', localModel.value)
  },
  { immediate: true }
)
// console.log('🚀 子组件 props.modelValue 初始值:', props.modelValue)

// 监听 modelValue（用于后续外部更新）
watch(
  () => props.modelValue,
  newVal => {
    if (!newVal || !internalConfig.value) return
    // ✅ 同样使用 sync 函数
    localModel.value = syncModelFromProps(newVal, internalConfig.value)
    console.log('子组件监测 modelValue 变化:', localModel.value)
  },
  { deep: true }
)

// 提取同步逻辑
function syncModelFromProps(newModelValue, newConfig) {
  if (!newModelValue || !newConfig) return {}

  const synced = {}
  // 1. 同步主字段
  for (const item of newConfig) {
    const key = item.prop
    if (newModelValue.hasOwnProperty(key)) {
      synced[key] = newModelValue[key]
    } else if (item.multiple || ['checkbox-group', 'daterange'].includes(item.type)) {
      synced[key] = item.defaultValue ?? []
    } else {
      synced[key] = item.defaultValue ?? ''
    }
  }
  // 2. 同步 extra 字段（通过 options 反查）
  for (const item of newConfig) {
    const extraMap = item.onChangeExtraFields
    if (!extraMap || typeof extraMap !== 'object') continue

    const prop = item.prop
    const idValue = newModelValue[prop] // e.g. 2

    let sourceObj = null

    // 情况1: 如果 newModelValue[prop] 本身就是对象 → 直接用（兼容旧逻辑）
    if (idValue && typeof idValue === 'object') {
      sourceObj = idValue
    }
    // 情况2: 如果是 primitive（string/number），且有 options → 反查
    else if (Array.isArray(item.options) && idValue !== undefined && idValue !== null) {
      // 默认用 option.value 匹配，可配置 valueKey
      const valueKey = item.valueKey || 'value'
      sourceObj = item.options.find(opt => opt[valueKey] === idValue)
    }

    // 如果找到了 sourceObj，就提取 extra 字段
    if (sourceObj && typeof sourceObj === 'object') {
      for (const [targetKey, subPath] of Object.entries(extraMap)) {
        const val = getNestedValue(sourceObj, subPath)
        if (val !== undefined) {
          synced[targetKey] = val
        }
      }
    }
  }

  // 3. 保留 localModel 中的 extra 字段（仅当 newModelValue 中没有对应的 sourceField 时）
  for (const item of newConfig) {
    const sourceField = item.prop
    const extraMap = item.onChangeExtraFields
    if (!extraMap || typeof extraMap !== 'object') continue

    // 如果 newModelValue 中没有 sourceField，说明没有重新计算
    if (newModelValue[sourceField] === undefined) {
      // 那么保留 localModel 中对应的 extra 字段
      for (const [targetKey, subPath] of Object.entries(extraMap)) {
        if (localModel.value.hasOwnProperty(targetKey)) {
          synced[targetKey] = localModel.value[targetKey]
        }
      }
    }
  }

  // 4. 保留 newModelValue 中已有的 extra 字段和其他额外字段
  for (const key in newModelValue) {
    // 如果已经同步过了（比如主字段或第2步写入的extra），跳过
    if (synced.hasOwnProperty(key)) continue

    // 判断是否是某个 extra 目标字段
    const isExtraTarget = newConfig.some(
      item => item.onChangeExtraFields && item.onChangeExtraFields.hasOwnProperty(key)
    )

    // 如果是 extra 字段，且 newModelValue 里有值 → 保留它！
    if (isExtraTarget) {
      synced[key] = newModelValue[key]
    }
    // 如果不是 extra，也不是主字段 → 也保留（兼容 hidden 字段等）
    else if (!newConfig.some(item => item.prop === key)) {
      synced[key] = newModelValue[key]
    }
  }
  console.log('🚀 子组件 进行modelvalue处理:', synced)
  return synced
}
function getNestedValue(obj, path) {
  return path.split('.').reduce((current, key) => current?.[key], obj)
}
// 当字典加载完成时，触发同步
function markDictLoaded(prop) {
  dictLoaded.value.add(prop)
  // 尝试同步该字段
  if (props.modelValue?.[prop] !== undefined) {
    localModel.value[prop] = props.modelValue[prop]
  }
}
// 2. 用户操作导致 localModel 变化时，emit（防抖可选）

function handleModelChange(value, item) {
  console.group('用户操作导致 localModel 变化时，emit（防抖可选）')

  const newModel = { ...localModel.value, [item.prop]: value }

  if (item?.type === 'select' && item.onChangeExtraFields) {
    const options = getSelectOptions(item)
    // console.log('可用 options:', options)
    const opt = options.find(o => o.value === value)
    // console.log('匹配的 opt:', opt)
    if (opt?.raw) {
      for (const [targetProp, sourceKey] of Object.entries(item.onChangeExtraFields)) {
        const extraValue = opt.raw[sourceKey]
        newModel[targetProp] = extraValue
        // console.log(`✅ 设置 ${targetProp} =`, extraValue)
      }
    }
  }
  localModel.value = newModel
  console.log('子组件用户操作后，modelvalue值==', newModel)
  nextTick(() => {
    if (!isEqualShallow(props.modelValue, newModel)) {
      console.log('如果新旧值不一样，反馈给父组件', newModel)
      emit('update:modelValue', newModel)
    } else {
      console.log('🚫 跳过 emit：认为相等')
    }
  })
  if (item.type === 'select') {
    console.log('如果是select类型，反馈给父组件', item.prop, value, item)
    emit('selectChange', item.prop, value, item)
  } else if (item.type == 'upload') {
    // 传给父组件最新的上传值newModel
    emit('uploadSuccess', item.prop, newModel)
  }
  console.groupEnd()
}
// 辅助函数：浅比较两个对象
function isEqualShallow(a, b) {
  const keysA = Object.keys(a)
  const keysB = Object.keys(b)
  if (keysA.length !== keysB.length) return false
  for (let key of keysA) {
    if (a[key] !== b[key]) return false
  }
  return true
}

// ==================== 加载字典选项 ====================
async function loadDictOptions(dictType) {
  const dictStore = useDictStore()
  let options = dictStore.getDict(dictType)

  if (options && options.length > 0) {
    return options
  }

  try {
    const resp = await getDicts(dictType)
    options = resp.data.map(p => ({
      label: p.itemLabel,
      value: p.itemValue,
      raw: p
    }))
    dictStore.setDict(dictType, options)
    return options
  } catch (err) {
    console.error(`加载字典 ${dictType} 失败`, err)
    ElMessage.error(`字典 ${dictType} 加载失败`)
    return []
  }
}

// ==================== 初始化 ====================
onMounted(async () => {
  internalConfig.value = deepCloneConfig(props.config)

  const initialData = {}
  const dictTypePromises = []
  const apiPromises = [] // ← 新增：收集 api 加载 promise
  for (const item of internalConfig.value) {
    const key = item.prop
    if (localModel.value[key] == null) {
      if (item.multiple) {
        initialData[key] = item.defaultValue ?? []
      } else if (['checkbox-group', 'daterange'].includes(item.type)) {
        initialData[key] = item.defaultValue ?? []
      } else {
        initialData[key] = item.defaultValue ?? ''
      }
    }

    // 预加载 dictType
    if (item.type === 'select' && item.dictType) {
      dictTypePromises.push(
        loadDictOptions(item.dictType).then(opts => {
          remoteOptions.value[key] = opts
          markDictLoaded(key) // ← 立即标记已加载
        })
      )
    } // 预加载 api（远程接口）← 关键新增！
    else if (item.type === 'select' && item.api) {
      apiPromises.push(
        loadRemoteOptionsForInit(item) // ← 专门用于初始化的加载函数
      )
    } else if (item.type === 'select' && item.options) {
      remoteOptions.value[key] = [...item.options]
      markDictLoaded(key)
    }
    // api 类型：延迟加载（focus 时）
  }

  if (Object.keys(initialData).length > 0) {
    localModel.value = { ...localModel.value, ...initialData }
  }

  // 等待所有字典加载完成
  await Promise.allSettled(dictTypePromises)
})

// ==================== 获取 select 选项 ====================
function getSelectOptions(item) {
  const key = item.prop
  // 字典选项
  if (item.dictType || item.api) {
    // 字典选项
    return (remoteOptions.value[key] || []).map(opt => ({
      value: opt.value,
      label: opt.label,
      raw: opt.raw // ← 必须存 raw
    }))
  } else if (item.options) {
    // 静态选项s
    return item.options.map(opt => ({
      value: opt.value,
      label: opt.label,
      raw: opt.raw // 保留原始
    }))
  }
  return []
}
async function loadRemoteOptionsForInit(item) {
  const { prop, api, requestParams } = item
  try {
    // 构造请求体：只传 requestParams，不传 keyword
    const payload = {
      ...(typeof requestParams === 'function' ? requestParams() : requestParams || {})
    }

    const res = await request({
      url: api,
      method: 'post',
      data: payload
    })

    const list =
      typeof item.transform === 'function'
        ? item.transform(res)
        : res.data?.records || res.data || []

    // 建议：统一转成字符串（或根据 item.valueType 判断）
    const newOptions = list.map(i => ({
      value: String(i[item.valueKey || 'value']), // ← 强制转字符串
      label: i[item.labelKey || 'label'],
      raw: i
    }))

    remoteOptions.value[prop] = newOptions
    markDictLoaded(prop) // ← 关键：标记已加载
  } catch (err) {
    ElMessage.error(`预加载 ${item.label} 失败`)
    remoteOptions.value[prop] = []
  }
}
// ==================== 加载远程 API 选项（首次 focus 时加载，无搜索词） ====================
async function loadRemoteOptions(item) {
  const { prop, api, requestParams, keywordField, debounceWait, ...rest } = item
  if (!api) return

  try {
    remoteLoading.value[prop] = true

    // 构造请求体：合并 requestParams + 分页（默认第一页）
    const payload = {
      ...(typeof requestParams === 'function' ? requestParams() : requestParams || {})
      // 注意：此时无 keyword，所以不加 keywordField
    }

    const res = await request({
      url: api,
      method: 'post', // ← 改为 POST
      data: payload // ← 参数放 body
    })

    const list =
      typeof item.transform === 'function'
        ? item.transform(res)
        : res.data?.records || res.data || []

    // 建议：统一转成字符串（或根据 item.valueType 判断）
    const newOptions = list.map(i => ({
      value: String(i[item.valueKey || 'value']), // ← 强制转字符串
      label: i[item.labelKey || 'label'],
      raw: i
    }))
    remoteOptions.value[prop] = newOptions
    // ✅ 关键：标记该字段字典已加载
    markDictLoaded(prop)
  } catch (err) {
    ElMessage.error(`加载 ${item.label} 失败`)
    remoteOptions.value[prop] = []
  } finally {
    remoteLoading.value[prop] = false
  }
}

// ==================== 远程搜索（带关键词，防抖） ====================
let searchTimeout = null
function handleFilterChange(keyword, item) {
  const { prop, api, requestParams, keywordField = 'keyword', debounceWait = 300 } = item
  if (!api) return

  clearTimeout(searchTimeout)
  searchTimeout = setTimeout(async () => {
    try {
      remoteLoading.value[prop] = true

      // 构造请求体：requestParams + 分页 + 动态关键词字段
      const payload = {
        ...(typeof requestParams === 'function' ? requestParams() : requestParams || {}),
        [keywordField]: keyword // ← 动态字段名，如 name / companyName
      }

      const res = await request({
        url: api,
        method: 'post', // ← POST 请求
        data: payload // ← body 传参
      })

      const list =
        typeof item.transform === 'function'
          ? item.transform(res)
          : res.data?.records || res.data || []

      remoteOptions.value[prop] = list.map(i => ({
        value: i[item.valueKey || 'value'],
        label: i[item.labelKey || 'label'],
        raw: i // ← 保存完整对象
      }))
    } catch (err) {
      ElMessage.error(`搜索 ${item.label} 失败`)
    } finally {
      remoteLoading.value[prop] = false
    }
  }, debounceWait)
}

// ==================== 数字输入处理 ====================
// function handleNumberInput(value, item) {
//   const { inputType = 'text', decimalDigits = 2, prop } = item
//   if (!prop) return

//   let result = String(value ?? '').trim()

//   if (inputType === 'integer') {
//     // 只保留数字
//     result = result.replace(/[^\d]/g, '')
//   } else if (inputType === 'decimal') {
//     // 1. 只保留数字和小数点
//     result = result.replace(/[^\d.]/g, '')

//     // 2. 去掉开头的小数点（不允许 ".5" → 改为 "0.5" 更好，但这里先简单处理）
//     if (result.startsWith('.')) {
//       result = '0.' + result.slice(1)
//     }

//     // 3. 保证最多一个小数点
//     const parts = result.split('.')
//     if (parts.length > 2) {
//       result = parts[0] + '.' + parts.slice(1).join('')
//     }

//     // 4. 限制小数位数（但保留结尾的小数点！）
//     if (result.includes('.')) {
//       const [intPart, decPart] = result.split('.')
//       // 如果小数部分超过限制，截断
//       if (decPart.length > decimalDigits) {
//         result = intPart + '.' + decPart.slice(0, decimalDigits)
//       }
//       // ✅ 不再删除结尾的 '.'
//     }
//   }

//   // 防止重复赋值（可选优化）
//   if (localModel.value[prop] !== result) {
//     localModel.value = { ...localModel.value, [prop]: result }
//   }
// }
function handleNumberInput(value, item) {
  const { inputType = 'text', decimalDigits = 2, prop } = item
  if (!prop) return

  let result = String(value ?? '').trim()

  if (inputType === 'integer') {
    // 只保留数字和负号
    result = result.replace(/[^-\d]/g, '')

    // 如果有多个负号或者负号不在开头，则移除多余的负号
    if ((result.match(/-/g) || []).length > 1) {
      result = result.replace(/-/g, '').replace(/^/, '-') // 仅保留一个负号在最前面
    }
  } else if (inputType === 'decimalNumber') {
    // 可以输入正数，负数，小数
    // 1. 只保留数字、小数点和负号
    result = result.replace(/[^-\d.]/g, '')

    // 2. 处理负号：确保最多只有一个负号且必须在开头
    if ((result.match(/-/g) || []).length > 1) {
      result = result.replace(/-/g, '') // 移除所有负号
      if (result.startsWith('-')) {
        result = '-' + result.slice(1) // 确保负号在最前面
      } else {
        result = '-' + result // 如果原本没有负号但需要保留数值，可以省略此步骤
      }
    }

    // 3. 去掉开头的小数点（不允许 ".5" → 改为 "0.5" 更好）
    if (result.startsWith('.')) {
      result = '0' + result
    } else if (result.startsWith('-.')) {
      result = '-0' + result.slice(2)
    }

    // 4. 保证最多一个小数点
    const parts = result.split('.')
    if (parts.length > 2) {
      result = parts[0] + '.' + parts.slice(1).join('')
    }

    // 5. 限制小数位数（但保留结尾的小数点！）
    if (result.includes('.')) {
      const [intPart, decPart] = result.split('.')
      // 如果小数部分超过限制，截断
      if (decPart.length > decimalDigits) {
        result = intPart + '.' + decPart.slice(0, decimalDigits)
      }
      // ✅ 不再删除结尾的 '.'
    }
  } else if (inputType === 'decimal') {
    // 可以输入正整数和小数
    // 1. 只保留数字和小数点
    result = result.replace(/[^\d.]/g, '')

    // 2. 去掉开头的小数点（不允许 ".5" → 改为 "0.5" 更好，但这里先简单处理）
    if (result.startsWith('.')) {
      result = '0.' + result.slice(1)
    }

    // 3. 保证最多一个小数点
    const parts = result.split('.')
    if (parts.length > 2) {
      result = parts[0] + '.' + parts.slice(1).join('')
    }

    // 4. 限制小数位数（但保留结尾的小数点！）
    if (result.includes('.')) {
      const [intPart, decPart] = result.split('.')
      // 如果小数部分超过限制，截断
      if (decPart.length > decimalDigits) {
        result = intPart + '.' + decPart.slice(0, decimalDigits)
      }
      // ✅ 不再删除结尾的 '.'
    }
  }

  // 防止重复赋值（可选优化）
  if (localModel.value[prop] !== result) {
    localModel.value = { ...localModel.value, [prop]: result }
  }
}

// ==================== 暴露方法 ====================
defineExpose({
  getFormData() {
    return { ...localModel.value }
  },
  async validate() {
    return new Promise((resolve, reject) => {
      formRef.value?.validate(valid => {
        if (valid) resolve(localModel.value)
        else reject(new Error('Validation failed'))
      })
    })
  },
  resetForm() {
    const resetData = {}
    internalConfig.value.forEach(item => {
      const key = item.prop
      if (['checkbox-group', 'daterange'].includes(item.type) || item.multiple) {
        resetData[key] = item.defaultValue ?? []
      } else if (item.type === 'upload') {
        resetData[key] = item.defaultValue ?? [] // upload 也是数组
      } else {
        resetData[key] = item.defaultValue ?? ''
      }
    })
    localModel.value = { ...resetData }
    nextTick(() => formRef.value?.clearValidate())
  },
  // ✅ 新增：强制刷新某个字段的远程选项
  async refreshRemoteOptions(targetProp) {
    console.log(`[SearchForm] 收到刷新请求: ${targetProp}`)

    // 1. 查找配置项
    const item = internalConfig.value.find(i => i.prop === targetProp)

    if (!item) {
      console.warn(`[SearchForm] 未找到 prop 为 ${targetProp} 的配置项`)
      return
    }

    if (item.type !== 'select' || !item.api) {
      console.warn(`[SearchForm] 字段 ${targetProp} 不是远程 Select 或没有 API`)
      return
    }

    console.log(`[SearchForm] 开始强制加载 ${targetProp} 的数据，API: ${item.api}`)

    // 2. 关键：在调用前，先清空旧数据，防止子组件内部的 "已加载则跳过" 逻辑生效
    // 如果你的 loadRemoteOptions 里有 "if (remoteOptions.value[prop]?.length > 0) return"
    // 这里必须先清空
    remoteOptions.value[targetProp] = []
    remoteLoading.value[targetProp] = true // 手动开启 loading

    try {
      // 3. 调用内部加载函数
      // 注意：直接调用 loadRemoteOptions，它会读取最新的 requestParams
      await loadRemoteOptions(item)
      console.log(`[SearchForm] ${targetProp} 加载完成`)
    } catch (error) {
      console.error(`[SearchForm] ${targetProp} 加载失败`, error)
      throw error
    } finally {
      remoteLoading.value[targetProp] = false
    }
  }
})
</script>

<style scoped>
.formBox {
  box-sizing: border-box;
}

.search-form-item {
  margin-bottom: 20px;
}

.iconStyle {
  color: #409eff;
}
</style>
