<!-- searchForm -->
<template>
  <div>
    <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 => {
                  if (!item.inputType || !value) return value
                  const str = String(value)
                  // 如果包含小数点
                  if (str.indexOf('.') > -1) {
                    const [int, dec] = str.split('.')
                    // 只格式化整数部分，保留小数部分原样
                    return int.replace(/\B(?=(\d{3})+(?!\d))/g, ',') + '.' + dec
                  }
                  // 如果没有小数点，直接格式化
                  return str.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
                }
              "
              :parser="value => value.replace(/\$\s?|(,*)/g, '')"
            />
            <el-select
              v-else-if="item.type === 'select'"
              :ref="
                el => {
                  if (el) selectRefs[item.prop] = el
                }
              "
              v-model="localModel[item.prop]"
              :multiple="!!item.multiple"
              :placeholder="item.placeholder || `请选择${item.label}`"
              :clearable="true"
              filterable
              :remote="!!item.api"
              :remote-method="query => handleRemoteSearch(query, item)"
              :loading="remoteLoading[item.prop] || false"
              :disabled="item.disabled"
              @change="val => handleModelChange(val, 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="item.startPlaceholder || '开始日期'"
              :end-placeholder="item.endPlaceholder || '结束日期'"
              :value-format="item.valueFormat || 'YYYY-MM-DD'"
              :disabled="item.disabled"
              :disabled-date="getDisabledDateFn(item)"
              style="width: 100%"
              @change="val => handleModelChange(val, item)"
            />
            <!-- Monthrange (新增) -->
            <el-date-picker
              v-else-if="item.type === 'monthrange'"
              v-model="localModel[item.prop]"
              type="monthrange"
              range-separator="至"
              :start-placeholder="item.startPlaceholder || '开始月份'"
              :end-placeholder="item.endPlaceholder || '结束月份'"
              :value-format="item.valueFormat || 'YYYY-MM'"
              :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不是必须的根据需要传值'}]-->
            <template v-else-if="item.type === 'upload'">
              <!-- 🔽 默认模式：完整使用 el-upload（含自带文件列表） -->
              <el-upload
                v-if="!item.customFileList"
                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 !== false"
                :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>

              <!-- 🔽 自定义列表模式：只保留上传触发器，自己渲染文件列表 -->
              <div v-else class="custom-upload-wrapper">
                <el-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"
                  :disabled="item.disabled"
                  :auto-upload="true"
                  :show-file-list="false"
                  :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-button type="primary" size="small" :disabled="item.disabled">
                    {{ item.customUploadButtonText || '点击上传文件' }}
                  </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>

                <!-- 自定义文件列表 -->
                <div v-if="(localModel[item.prop] || []).length" class="custom-file-list">
                  <div
                    v-for="(file, idx) in localModel[item.prop]"
                    :key="file.uid || idx"
                    class="file-item"
                  >
                    <span class="file-name" :title="file.name">{{ file.name }}</span>
                    <div class="file-actions">
                      <el-button link type="primary" size="small" @click="previewFile(file, item)">
                        查看
                      </el-button>
                      <el-button link type="danger" size="small" @click="removeFile(file, item)">
                        删除
                      </el-button>
                    </div>
                  </div>
                </div>
              </div>
            </template>
            <span v-else>不支持的类型: {{ item.type }}</span>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <!-- 文件预览弹窗（页面内查看，不打开新窗口） -->
    <el-dialog
      v-model="previewDialogVisible"
      :title="previewFileName"
      width="70%"
      :close-on-click-modal="false"
      destroy-on-close
      @close="previewUrl = ''"
    >
      <div class="preview-container">
        <!-- 图片预览 -->
        <div v-if="previewFileType === 'image'" class="preview-image-wrapper">
          <img :src="previewUrl" class="preview-image" alt="预览图片" />
        </div>

        <!-- PDF 预览（使用 iframe 内嵌） -->
        <iframe
          v-else-if="previewFileType === 'pdf'"
          :src="previewUrl"
          class="preview-pdf"
          frameborder="0"
        ></iframe>

        <!-- 不支持预览的文件类型 -->
        <div v-else-if="previewFileType === 'unsupported'" class="preview-unsupported">
          <el-icon :size="48" color="#909399"><Document /></el-icon>
          <p>暂不支持预览此类型文件</p>
          <el-button type="primary" @click="previewDialogVisible = false"> 关闭 </el-button>
        </div>
      </div>
    </el-dialog>
    <!-- 文件预览弹窗 -->
    <FilePreview ref="filePreviewRef" />
  </div>
</template>

<script setup>
import { ref, watch, onMounted, nextTick, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Upload, Document } from '@element-plus/icons-vue'
// 🔑 引入你的字典方法
import useDictStore from '@/store/modules/dict'
import { getDicts } from '@/api/system/dict/data'
import request from '@/utils/request'
import FilePreview from '@/components/Preview/filePreview.vue'
import dayjs from 'dayjs'
import * as PDFJS from 'pdfjs-dist'

PDFJS.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.mjs'
// ==================== select ====================
const selectRefs = ref({})
// 新增远程搜索入口（带防抖）
let remoteSearchTimer = null
function handleRemoteSearch(query, item) {
  if (!item.api) return
  // 🔥 关键修改：如果 query 为空且当前已有选项数据，则不重新加载
  if (query === '' && remoteOptions.value[item.prop] && remoteOptions.value[item.prop].length > 0) {
    return
  }
  clearTimeout(remoteSearchTimer)
  remoteSearchTimer = setTimeout(async () => {
    await loadRemoteOptions(item, query)
  }, item.debounceWait || 300)
}
// ==================== 文件预览弹窗 ====================
const filePreviewRef = ref(null)
const previewDialogVisible = ref(false)
const previewUrl = ref('')
const previewFileName = ref('')
const previewFileType = ref('') // 'image', 'pdf', 'unsupported'
function previewFile(file, item) {
  // 确保传入对象包含 url 和 name 属性
  filePreviewRef.value?.open({
    url: file.url || file.response?.data?.url,
    name: file.name
  })
}

// 删除文件（复用原有删除逻辑）
function removeFile(file, item) {
  const fileList = localModel.value[item.prop] || []
  const newList = fileList.filter(f => f.uid !== file.uid)
  handleUploadRemove(file, newList, item) // 调用原有的删除处理函数
}

// 文件大小格式化
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) {
  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} 上传成功`)
}

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',
  'inputChange'
])

// ==================== Refs ====================
const formRef = ref(null)
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
})

// 同步 extra 字段：根据当前选中的 option 填充 extra 字段（不触发外部 emit）
function syncExtraFieldsForProp(prop, value) {
  const item = internalConfig.value.find(i => i.prop === prop)
  if (!item || item.type !== 'select' || !item.onChangeExtraFields) return false

  const options = getSelectOptions(item)
  const selectedOption = options.find(opt => String(opt.value) === String(value))
  if (selectedOption && selectedOption.raw) {
    let needUpdate = false
    const newModel = { ...localModel.value }
    for (const [targetProp, sourceKey] of Object.entries(item.onChangeExtraFields)) {
      const extraValue = selectedOption.raw[sourceKey]
      if (newModel[targetProp] !== extraValue) {
        newModel[targetProp] = extraValue
        needUpdate = true
      }
    }
    if (needUpdate) {
      localModel.value = newModel
      console.log('====================================')
      console.log('localModel.value', localModel.value)
      console.log('====================================')
      return true
    }
  }
  return false
}

// 监听 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', 'monthrange'].includes(item.type)
      ) {
        initialModel[key] = item.defaultValue ?? []
      } else {
        initialModel[key] = item.defaultValue ?? ''
      }
    }

    localModel.value = syncModelFromProps(props.modelValue, internalConfig.value)
  },
  { immediate: true }
)

// 监听 modelValue（用于后续外部更新）
watch(
  () => props.modelValue,
  newVal => {
    if (!newVal || !internalConfig.value) return
    localModel.value = syncModelFromProps(newVal, internalConfig.value)
  },
  { deep: true }
)

// 从 props 同步模型数据
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', 'monthrange'].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]

    let sourceObj = null

    if (idValue && typeof idValue === 'object') {
      sourceObj = idValue
    } else if (idValue !== undefined && idValue !== null) {
      const opts = getSelectOptions(item)
      const valueKey = item.valueKey || 'value'
      sourceObj = opts.find(opt => opt[valueKey] === idValue)
    }
    // else if (Array.isArray(item.options) && idValue !== undefined && idValue !== null) {
    //   const valueKey = item.valueKey || 'value'
    //   sourceObj = item.options.find(opt => opt[valueKey] === idValue)
    // }

    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

    if (newModelValue[sourceField] === undefined) {
      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) {
    if (synced.hasOwnProperty(key)) continue

    const isExtraTarget = newConfig.some(
      item => item.onChangeExtraFields && item.onChangeExtraFields.hasOwnProperty(key)
    )

    if (isExtraTarget) {
      synced[key] = newModelValue[key]
    } else if (!newConfig.some(item => item.prop === key)) {
      synced[key] = newModelValue[key]
    }
  }
  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]
  }
}

// 用户操作导致 localModel 变化时，emit
function handleModelChange(value, item) {
  const newModel = { ...localModel.value, [item.prop]: value }

  if (item?.type === 'select' && item.onChangeExtraFields) {
    const options = getSelectOptions(item)
    const opt = options.find(o => String(o.value) === String(value))
    if (opt?.raw) {
      for (const [targetProp, sourceKey] of Object.entries(item.onChangeExtraFields)) {
        newModel[targetProp] = opt.raw[sourceKey]
      }
    }
  }
  localModel.value = newModel
  // 🔥 新增：多选远程 select，选中后清空搜索关键词
  if (item.type === 'select' && item.multiple && item.api && selectRefs.value[item.prop]) {
    const selectInstance = selectRefs.value[item.prop]
    // 获取 el-select 内部的 input 元素
    const inputElement = selectInstance.$el?.querySelector('input')
    if (inputElement && inputElement.value) {
      inputElement.value = ''
      // 触发 input 事件，让组件内部同步状态
      inputElement.dispatchEvent(new Event('input', { bubbles: true }))
      loadRemoteOptions(item, '')
    }
  }

  nextTick(() => {
    if (!isEqualShallow(props.modelValue, newModel)) {
      emit('update:modelValue', newModel)
    }
  })
  if (item.type === 'select') {
    emit('selectChange', item.prop, value, item)
  } else if (item.type == 'upload') {
    emit('uploadSuccess', item.prop, newModel)
  } else if (item.type == 'input') {
    emit('inputChange', item.prop, value, item)
  }
}

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) {
    ElMessage.error(`字典 ${dictType} 加载失败`)
    return []
  }
}

// ==================== 获取 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
//     }))
//   } else if (item.options) {
//     return item.options.map(opt => ({
//       value: opt.value,
//       label: opt.label,
//       raw: opt.raw
//     }))
//   }
//   return []
// }
// 替换原有的 getSelectOptions 函数
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
    }))
  } else if (item.options) {
    // 静态选项或函数选项
    if (typeof item.options === 'function') {
      // 传入当前表单数据（localModel.value）作为 row
      const opts = item.options(localModel.value)
      return opts.map(opt => ({
        value: opt.value,
        label: opt.label,
        raw: opt.raw || opt
      }))
    } else if (Array.isArray(item.options)) {
      return item.options.map(opt => ({
        value: opt.value,
        label: opt.label,
        raw: opt.raw || opt
      }))
    }
  }
  return []
}
// 初始化加载远程 API 选项（无搜索词）
async function loadRemoteOptionsForInit(item) {
  const { prop, api, requestParams } = item
  try {
    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 || []

    const newOptions = list.map(i => ({
      value: String(i[item.valueKey || 'value']),
      label: i[item.labelKey || 'label'],
      raw: i
    }))

    remoteOptions.value[prop] = newOptions
    markDictLoaded(prop)

    // 同步 extra 字段
    const currentVal = localModel.value[prop]
    if (currentVal !== undefined && currentVal !== null && currentVal !== '') {
      syncExtraFieldsForProp(prop, currentVal)
    }
  } catch (err) {
    ElMessage.error(`预加载 ${item.label} 失败`)
    remoteOptions.value[prop] = []
  }
}

// 修改原有的 loadRemoteOptions，使其支持关键词参数
// async function loadRemoteOptions(item, keyword = '') {
//   const { prop, api, requestParams, keywordField = 'keyword' } = item
//   if (!api) return

//   try {
//     remoteLoading.value[prop] = true

//     let params = typeof requestParams === 'function' ? requestParams() : requestParams || {}
//     if (keyword) {
//       params = { ...params, [keywordField]: keyword }
//     } else {
//       // 可选：重置分页参数为第一页
//       params = { ...params, pageNo: 1 }
//     }

//     const res = await request({ url: api, method: 'post', data: params })
//     const list =
//       typeof item.transform === 'function'
//         ? item.transform(res)
//         : res.data?.records || res.data || []

//     remoteOptions.value[prop] = list.map(i => ({
//       value: String(i[item.valueKey || 'value']),
//       label: i[item.labelKey || 'label'],
//       raw: i
//     }))
//     markDictLoaded(prop)

//     const currentVal = localModel.value[prop]
//     if (currentVal !== undefined && currentVal !== null && currentVal !== '') {
//       syncExtraFieldsForProp(prop, currentVal)
//     }
//   } catch (err) {
//     ElMessage.error(`加载 ${item.label} 失败`)
//     remoteOptions.value[prop] = []
//   } finally {
//     remoteLoading.value[prop] = false
//   }
// }
// 修改 loadRemoteOptions 函数
async function loadRemoteOptions(item, keyword = '') {
  const { prop, api, requestParams, keywordField = 'keyword', method = 'post' } = item
  if (!api) return

  try {
    remoteLoading.value[prop] = true

    let params = typeof requestParams === 'function' ? requestParams() : requestParams || {}
    if (keyword) {
      params = { ...params, [keywordField]: keyword }
    } else {
      params = { ...params, pageNo: 1 }
    }

    // 根据 method 决定参数位置
    const requestConfig = {
      url: api,
      method: method
    }
    if (method.toLowerCase() === 'get') {
      requestConfig.params = params
    } else {
      requestConfig.data = params
    }

    const res = await request(requestConfig)

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

    remoteOptions.value[prop] = list.map(i => ({
      value: String(i[item.valueKey || 'value']),
      label: i[item.labelKey || 'label'],
      raw: i
    }))
    markDictLoaded(prop)

    const currentVal = localModel.value[prop]
    if (currentVal !== undefined && currentVal !== null && currentVal !== '') {
      syncExtraFieldsForProp(prop, currentVal)
    }
  } 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

      const payload = {
        ...(typeof requestParams === 'function' ? requestParams() : requestParams || {}),
        [keywordField]: keyword
      }

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

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

      remoteOptions.value[prop] = list.map(i => ({
        value: String(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, '')
    if ((result.match(/-/g) || []).length > 1) {
      result = result.replace(/-/g, '').replace(/^/, '-')
    }
  } else if (inputType === 'decimalNumber') {
    result = result.replace(/[^-\d.]/g, '')
    if ((result.match(/-/g) || []).length > 1) {
      result = result.replace(/-/g, '')
      if (result.startsWith('-')) {
        result = '-' + result.slice(1)
      } else {
        result = '-' + result
      }
    }
    if (result.startsWith('.')) {
      result = '0' + result
    } else if (result.startsWith('-.')) {
      result = '-0' + result.slice(2)
    }
    const parts = result.split('.')
    if (parts.length > 2) {
      result = parts[0] + '.' + parts.slice(1).join('')
    }
    if (result.includes('.')) {
      const [intPart, decPart] = result.split('.')
      if (decPart.length > decimalDigits) {
        result = intPart + '.' + decPart.slice(0, decimalDigits)
      }
    }
  } else if (inputType === 'decimal') {
    result = result.replace(/[^\d.]/g, '')
    if (result.startsWith('.')) {
      result = '0.' + result.slice(1)
    }
    const parts = result.split('.')
    if (parts.length > 2) {
      result = parts[0] + '.' + parts.slice(1).join('')
    }
    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 }
  }
}
// 同步所有 select 的 extra 字段
function syncAllExtraFields() {
  for (const item of internalConfig.value) {
    if (item.type === 'select' && item.onChangeExtraFields) {
      const currentVal = localModel.value[item.prop]
      if (currentVal !== undefined && currentVal !== null && currentVal !== '') {
        syncExtraFieldsForProp(item.prop, currentVal)
      }
    }
  }
}
// ==================== 初始化 ====================
onMounted(async () => {
  internalConfig.value = deepCloneConfig(props.config)

  const initialData = {}
  const dictTypePromises = []
  const apiPromises = []
  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', 'monthrange'].includes(item.type)) {
        initialData[key] = item.defaultValue ?? []
      } else {
        initialData[key] = item.defaultValue ?? ''
      }
    }

    if (item.type === 'select' && item.dictType) {
      dictTypePromises.push(
        loadDictOptions(item.dictType).then(opts => {
          remoteOptions.value[key] = opts
          markDictLoaded(key)
        })
      )
    } else if (item.type === 'select' && item.api) {
      apiPromises.push(loadRemoteOptions(item, ''))
    }  else if (item.type === 'select' && item.options) {
  // 支持 options 为数组或函数（函数调用时传入当前表单数据）
  remoteOptions.value[key] = getSelectOptions(item)
  markDictLoaded(key)
}
  }

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

  // 等待所有字典和远程选项加载完成
  await Promise.allSettled([...dictTypePromises, ...apiPromises])

  // 所有 select 选项加载完成后，为有 onChangeExtraFields 且有值的字段填充 extra 字段
  for (const item of internalConfig.value) {
    if (item.type === 'select' && item.onChangeExtraFields) {
      const currentVal = localModel.value[item.prop]
      if (currentVal !== undefined && currentVal !== null && currentVal !== '') {
        syncExtraFieldsForProp(item.prop, currentVal)
      }
    }
  }
})

// ==================== 暴露方法 ====================
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', 'monthrange'].includes(item.type) || item.multiple) {
        resetData[key] = item.defaultValue ?? []
      } else if (item.type === 'upload') {
        resetData[key] = item.defaultValue ?? []
      } else {
        resetData[key] = item.defaultValue ?? ''
      }
    })
    localModel.value = { ...resetData }
    // 关键：重置后重新同步额外字段
    nextTick(() => {
      syncAllExtraFields()
      formRef.value?.clearValidate()
    })
  },
  async refreshRemoteOptions(targetProp) {
    const item = internalConfig.value.find(i => i.prop === targetProp)
    if (!item || item.type !== 'select' || !item.api) return
    await loadRemoteOptions(item, '')
  }
})
</script>

<style scoped>
.preview-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 400px;
}
.preview-image-wrapper {
  text-align: center;
}
.preview-image {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
}
.preview-pdf {
  width: 100%;
  height: 70vh;
}
.preview-unsupported {
  text-align: center;
  padding: 40px;
}
.preview-unsupported p {
  margin: 16px 0;
  color: #909399;
}
.custom-upload-wrapper {
  width: 100%;
}
.custom-file-list {
  margin-top: 12px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  background-color: #fff;
}
.file-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  border-bottom: 1px solid #ebeef5;
}
.file-item:last-child {
  border-bottom: none;
}
.file-name {
  flex: 1;
  font-size: 14px;
  color: #606266;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-right: 16px;
}
.file-actions {
  display: flex;
  gap: 12px;
}
.formBox {
  box-sizing: border-box;
}
.search-form-item {
  margin-bottom: 20px;
}
.iconStyle {
  color: #409eff;
}
</style>
