<template>
  <view class="page-container">
    <AppTitleHeader title="模具台账" subTitle="按型号、状态、编码快速筛选" :showSubTitle="true" />

    <view class="filter-card">
      <view class="filter-row">
        <view class="filter-item" @click="openBrandPicker">
          <text class="filter-label">型号</text>
          <text class="filter-value" :class="{ placeholder: !selectedBrandLabel }">
            {{ selectedBrandLabel || '全部型号' }}
          </text>
          <text class="filter-arrow">›</text>
        </view>
        <view class="filter-item" @click="openStatusPicker">
          <text class="filter-label">状态</text>
          <text class="filter-value" :class="{ placeholder: !selectedStatusLabel }">
            {{ selectedStatusLabel || '全部状态' }}
          </text>
          <text class="filter-arrow">›</text>
        </view>
      </view>

      <view class="search-row">
        <view class="search-wrapper">
          <view class="search-icon">
            <text class="iconfont icon-search"></text>
          </view>
          <input v-model="searchKeyword" class="search-input" type="text" placeholder="请输入模具编码或名称"
            placeholder-class="input-placeholder" @confirm="handleSearch" />
          <view v-if="searchKeyword" class="clear-btn" @click="clearSearch">
            <text class="clear-icon">×</text>
          </view>
        </view>
        <view class="search-btn" @click="handleSearch">
          <text class="search-btn-text">查询</text>
        </view>
      </view>
    </view>

    <scroll-view scroll-y class="content-scroll" :scroll-top="scrollTop" @scroll="handleScroll"
      @scrolltolower="loadMore" :lower-threshold="80">
      <view class="list-wrap">
        <view v-for="item in list" :key="item.id" class="ledger-card" @click="openDetail(item)">
          <view class="card-header">
            <view class="header-left">
              <text class="name">{{ textValue(item.name) }}</text>
              <view class="code-wrapper">
                <text class="code">编码：{{ textValue(item.code) }}</text>
                <CopyButton :content="item.code" />
              </view>
            </view>
            <view class="header-right">
              <view class="status-chip" :class="statusClass(item.status)">
                {{ moldStatusText(item.status) }}
              </view>
            </view>
          </view>
          <view class="card-body">
            <view class="row">
              <text class="label">使用次数</text>
              <text class="value">{{ textValue(item.useTime) }}</text>
            </view>
            <view class="row">
              <text class="label">创建时间</text>
              <text class="value">{{ formatDateTime(item.createTime) }}</text>
            </view>
          </view>
          <view class="card-actions">
            <view class="action-btn edit-btn" @click.stop="openEdit(item)">
              <uni-icons type="compose" size="18" color="#ffffff"></uni-icons>
            </view>
            <view class="action-btn delete-btn" @click.stop="confirmDelete(item)">
              <uni-icons type="trash" size="18" color="#ffffff"></uni-icons>
            </view>
          </view>
        </view>

        <view v-if="loading && pageNo === 1" class="loading-text">加载中...</view>
        <view v-else-if="!list.length" class="empty-text">暂无模具台账数据</view>
        <view v-else-if="loadingMore" class="loading-text">正在加载更多...</view>
        <view v-else-if="finished" class="finished-text">没有更多数据了</view>
      </view>
    </scroll-view>

    <view v-if="showGoTop" class="go-top-btn" @click="goTop">
      <text class="go-top-icon">↑</text>
    </view>

    <view class="add-btn" @click="openCreate">
      <text class="add-icon">+</text>
    </view>

    <uni-popup ref="brandPickerRef" type="bottom" background-color="#fff">
      <view class="picker-content">
        <view class="picker-header">
          <text class="picker-title">选择模具型号</text>
          <view class="picker-clear" @click="resetBrand">
            <text class="picker-clear-text">清空</text>
          </view>
        </view>
        <scroll-view scroll-y class="picker-list">
          <view v-for="option in brandOptions" :key="option.value" class="picker-item" @click="selectBrand(option)">
            <text class="picker-text">{{ option.label }}</text>
            <text v-if="selectedBrandId === option.value" class="picker-check">✓</text>
          </view>
        </scroll-view>
      </view>
    </uni-popup>

    <uni-popup ref="statusPickerRef" type="bottom" background-color="#fff">
      <view class="picker-content">
        <view class="picker-header">
          <text class="picker-title">选择模具状态</text>
          <view class="picker-clear" @click="resetStatus">
            <text class="picker-clear-text">清空</text>
          </view>
        </view>
        <view class="picker-list">
          <view v-for="option in statusOptions" :key="option.value" class="picker-item" @click="selectStatus(option)">
            <text class="picker-text">{{ option.label }}</text>
            <text v-if="selectedStatus === option.value" class="picker-check">✓</text>
          </view>
        </view>
      </view>
    </uni-popup>

    <uni-popup ref="formPopupRef" type="center" background-color="#fff">
      <view class="popup-content-center">
        <view class="popup-header">
          <text class="picker-title">{{ formMode === 'create' ? '新增模具台账' : '编辑模具台账' }}</text>
        </view>
        <scroll-view scroll-y class="form-scroll">
          <view class="form-content">
            <view class="form-item">
              <text class="form-label">模具型号 <text class="required-star">*</text></text>
              <view class="form-picker" @click="openFormBrandPicker">
                <text class="form-picker-text" :class="{ placeholder: !formBrandLabel }">
                  {{ formBrandLabel || '请选择模具型号' }}
                </text>
                <text class="filter-arrow">›</text>
              </view>
            </view>
            <view class="form-item">
              <view class="form-label-row">
                <text class="form-label">
                  模具编码
                  <text v-if="!formData.isCode" class="required-star">*</text>
                </text>
                <view class="switch-wrap">
                  <text class="switch-label">自动生成</text>
                  <switch :checked="formData.isCode" color="#2d5a87"
                    @change="(e) => formData.isCode = e.detail.value" />
                </view>
              </view>
              <input v-model="formData.code" :disabled="formData.isCode || formMode === 'update'" class="form-input" type="text"
                placeholder="请输入模具编码" />
            </view>
            <view class="form-item">
              <text class="form-label">模具名称 <text class="required-star">*</text></text>
              <input v-model="formData.name" class="form-input" type="text" placeholder="请输入模具名称" />
            </view>
            <view class="form-item">
              <text class="form-label">单位 <text class="required-star">*</text></text>
              <view class="form-picker" @click="openUnitPicker">
                <text class="form-picker-text" :class="{ placeholder: !formUnitLabel }">
                  {{ formUnitLabel || '请选择单位' }}
                </text>
                <text class="filter-arrow">›</text>
              </view>
            </view>
            <view class="form-item">
              <text class="form-label">入库时间 <text class="required-star">*</text></text>
              <picker mode="date" :value="formData.inTimeDate" @change="handleInTimeChange">
                <view class="form-picker">
                  <text class="form-picker-text" :class="{ placeholder: !formData.inTimeDate }">
                    {{ formData.inTimeDate || '请选择入库时间' }}
                  </text>
                  <text class="filter-arrow">›</text>
                </view>
              </picker>
            </view>
            <view class="form-item">
              <text class="form-label">状态</text>
              <picker mode="selector" :range="formStatusRange" :value="formStatusIndex"
                @change="handleFormStatusChange">
                <view class="form-picker">
                  <text class="form-picker-text" :class="{ placeholder: formData.status === '' }">
                    {{ formStatusLabel || '请选择状态' }}
                  </text>
                  <text class="filter-arrow">›</text>
                </view>
              </picker>
            </view>
            <view class="form-item">
              <text class="form-label">使用次数</text>
              <input v-model="formData.useTime" class="form-input" type="number" placeholder="请输入使用次数" />
            </view>
            <view class="form-item">
              <text class="form-label">模具图片</text>
              <view class="image-list">
                <view v-for="(img, idx) in formData.images" :key="`${img}-${idx}`" class="image-item">
                  <image class="image-preview" :src="img" mode="aspectFill"
                    @click="previewImages(formData.images, img)" />
                  <view class="image-delete" @click.stop="removeImage(idx)">
                    <text class="image-delete-text">×</text>
                  </view>
                </view>
                <view v-if="formData.images.length < 6" class="image-add" @click="chooseAndUploadImages">
                  <text class="image-add-text">+</text>
                </view>
              </view>
            </view>
            <view class="form-item">
              <text class="form-label">是否启用 <text class="required-star">*</text></text>
              <view class="enable-group">
                <view class="enable-item" :class="{ active: formData.isEnable === true }"
                  @click="formData.isEnable = true">
                  <text>是</text>
                </view>
                <view class="enable-item" :class="{ active: formData.isEnable === false }"
                  @click="formData.isEnable = false">
                  <text>否</text>
                </view>
              </view>
            </view>
            <view class="form-item">
              <text class="form-label">备注</text>
              <textarea v-model="formData.remark" class="form-textarea" placeholder="请输入备注" :maxlength="200" />
            </view>
          </view>
        </scroll-view>
        <view class="form-footer">
          <view class="footer-btn cancel-btn" @click="closeForm">
            <text class="btn-text cancel-text">取消</text>
          </view>
          <view class="footer-btn confirm-btn" @click="submitForm">
            <text class="btn-text">保存</text>
          </view>
        </view>
      </view>
    </uni-popup>

    <uni-popup ref="formBrandPickerRef" type="bottom" background-color="#fff">
      <view class="picker-content">
        <view class="picker-header">
          <text class="picker-title">选择模具型号</text>
        </view>
        <scroll-view scroll-y class="picker-list">
          <view v-for="option in brandOptions" :key="`f-${option.value}`" class="picker-item"
            @click="selectFormBrand(option)">
            <text class="picker-text">{{ option.label }}</text>
            <text v-if="formData.brandId === option.value" class="picker-check">✓</text>
          </view>
        </scroll-view>
      </view>
    </uni-popup>

    <uni-popup ref="unitPickerRef" type="bottom" background-color="#fff">
      <view class="picker-content">
        <view class="picker-header">
          <text class="picker-title">选择单位</text>
        </view>
        <scroll-view scroll-y class="picker-list">
          <view v-for="option in unitOptions" :key="`u-${option.value}`" class="picker-item"
            @click="selectUnit(option)">
            <text class="picker-text">{{ option.label }}</text>
            <text v-if="Number(formData.unitId) === Number(option.value)" class="picker-check">✓</text>
          </view>
        </scroll-view>
      </view>
    </uni-popup>
  </view>
</template>

<script setup>
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import AppTitleHeader from '@/components/common/AppTitleHeader.vue'
import CopyButton from '@/components/common/CopyButton.vue'
import { createMold, deleteMold, getMoldBrandTree, getMoldDetail, getMoldPage, updateMold, uploadMoldImage } from '@/api/mes/mold'
import { getProductUnitSimpleList, getUnitList } from '@/api/mes/product'
import { DICT_TYPE, getDictLabel, initAllDict } from '@/utils/dict'

const brandPickerRef = ref(null)
const statusPickerRef = ref(null)
const formPopupRef = ref(null)
const formBrandPickerRef = ref(null)
const unitPickerRef = ref(null)

const list = ref([])
const loading = ref(false)
const loadingMore = ref(false)
const finished = ref(false)
const pageNo = ref(1)
const pageSize = ref(10)
const total = ref(0)

const searchKeyword = ref('')
const selectedBrandId = ref(undefined)
const selectedStatus = ref(undefined)
const brandOptions = ref([{ label: '全部', value: undefined }])

const scrollTop = ref(0)
const showGoTop = ref(false)
const formMode = ref('create')
const formData = ref({
  id: undefined,
  code: '',
  isCode: true,
  name: '',
  unitId: '',
  useTime: '',
  inTimeDate: '',
  status: '',
  remark: '',
  images: [],
  brandId: undefined,
  isEnable: true
})
const unitOptions = ref([])

const selectedBrandLabel = computed(() => {
  const item = brandOptions.value.find((v) => v.value === selectedBrandId.value)
  return item ? item.label : ''
})

const statusOptions = computed(() => {
  const options = []
  for (let i = 0; i <= 9; i += 1) {
    const label = getDictLabel(DICT_TYPE.ERP_MOLD_STATUS, i, '')
    if (label && label !== String(i)) {
      options.push({ label, value: i })
    }
  }
  return options
})

const selectedStatusLabel = computed(() => {
  const item = statusOptions.value.find((v) => v.value === selectedStatus.value)
  return item ? item.label : ''
})

const formStatusLabel = computed(() => {
  if (formData.value.status === '' || formData.value.status === undefined || formData.value.status === null) return ''
  return moldStatusText(formData.value.status)
})
const formStatusRange = computed(() => statusOptions.value.map((v) => v.label))
const formStatusIndex = computed(() => {
  const idx = statusOptions.value.findIndex((v) => Number(v.value) === Number(formData.value.status))
  return idx >= 0 ? idx : 0
})

const formBrandLabel = computed(() => {
  const item = brandOptions.value.find((v) => v.value === formData.value.brandId)
  return item ? item.label : ''
})

const formUnitLabel = computed(() => {
  const item = unitOptions.value.find((v) => Number(v.value) === Number(formData.value.unitId))
  return item ? item.label : ''
})

onLoad(async () => {
  await initAllDict()
  await loadUnitOptions()
  await loadBrandTree()
  await fetchList(true)
})

async function loadUnitOptions() {
  try {
    const res = await getProductUnitSimpleList()
    const rows = normalizeListData(res)
    unitOptions.value = rows
      .map((item) => ({ label: textValue(item?.name), value: item?.id }))
      .filter((item) => item.value !== undefined && item.value !== null)
  } catch (e) {
    try {
      const fallbackRes = await getUnitList()
      const rows = normalizeListData(fallbackRes)
      unitOptions.value = rows
        .map((item) => ({ label: textValue(item?.name), value: item?.id }))
        .filter((item) => item.value !== undefined && item.value !== null)
    } catch (error) {
      unitOptions.value = []
    }
  }
}

async function loadBrandTree() {
  try {
    const res = await getMoldBrandTree()
    const tree = normalizeListData(res)
    const flatList = [{ label: '全部', value: undefined }, ...flattenTree(tree)]
    brandOptions.value = flatList
  } catch (e) {
    brandOptions.value = [{ label: '全部', value: undefined }]
  }
}

function flattenTree(nodes, level = 0) {
  const result = []
  const list = Array.isArray(nodes) ? nodes : []
  for (const node of list) {
    const id = node?.id
    if (id === undefined || id === null) continue
    const prefix = level > 0 ? `${'　'.repeat(level)}└ ` : ''
    result.push({
      label: `${prefix}${textValue(node?.name)}`,
      value: id
    })
    if (Array.isArray(node?.children) && node.children.length) {
      result.push(...flattenTree(node.children, level + 1))
    }
  }
  return result
}

async function handleSearch() {
  await fetchList(true)
}

async function clearSearch() {
  searchKeyword.value = ''
  await fetchList(true)
}

function openBrandPicker() {
  brandPickerRef.value?.open()
}

function openStatusPicker() {
  statusPickerRef.value?.open()
}

function openFormBrandPicker() {
  formBrandPickerRef.value?.open()
}

function closeFormBrandPicker() {
  formBrandPickerRef.value?.close()
}

function openUnitPicker() {
  unitPickerRef.value?.open()
}

function closeUnitPicker() {
  unitPickerRef.value?.close()
}

async function selectBrand(option) {
  selectedBrandId.value = option.value
  brandPickerRef.value?.close()
  await fetchList(true)
}

async function selectStatus(option) {
  selectedStatus.value = option.value
  statusPickerRef.value?.close()
  await fetchList(true)
}

async function resetBrand() {
  selectedBrandId.value = undefined
  brandPickerRef.value?.close()
  await fetchList(true)
}

async function resetStatus() {
  selectedStatus.value = undefined
  statusPickerRef.value?.close()
  await fetchList(true)
}

function selectFormBrand(option) {
  formData.value.brandId = option.value
  formBrandPickerRef.value?.close()
}

function selectUnit(option) {
  formData.value.unitId = option.value
  unitPickerRef.value?.close()
}

async function loadMore() {
  if (loading.value || loadingMore.value || finished.value) return
  pageNo.value += 1
  await fetchList(false)
}

async function fetchList(reset) {
  if (reset) {
    pageNo.value = 1
    finished.value = false
  }
  if (pageNo.value === 1) {
    loading.value = true
  } else {
    loadingMore.value = true
  }
  try {
    const keyword = searchKeyword.value.trim()
    const params = {
      pageNo: pageNo.value,
      pageSize: pageSize.value,
      code: keyword || undefined,
      name: keyword || undefined,
      brandId: selectedBrandId.value,
      status: selectedStatus.value
    }
    const res = await getMoldPage(params)
    const page = normalizePageData(res)
    total.value = page.total
    if (reset) {
      list.value = page.list
    } else {
      list.value = [...list.value, ...page.list]
    }
    finished.value = list.value.length >= total.value || page.list.length < pageSize.value
  } catch (e) {
    if (!reset) pageNo.value = Math.max(1, pageNo.value - 1)
    uni.showToast({ title: '加载失败', icon: 'none' })
  } finally {
    loading.value = false
    loadingMore.value = false
  }
}

function handleScroll(e) {
  const top = e?.detail?.scrollTop || 0
  showGoTop.value = top > 600
}

function goTop() {
  scrollTop.value = 0
}

function openDetail(item) {
  const id = item?.id
  if (id === undefined || id === null) {
    uni.showToast({ title: '缺少ID，无法查看详情', icon: 'none' })
    return
  }
  uni.navigateTo({
    url: `/pages_function/pages/moldLedger/detail?id=${encodeURIComponent(String(id))}`
  })
}

function openCreate() {
  formMode.value = 'create'
  resetForm()
  if (selectedBrandId.value !== undefined) {
    formData.value.brandId = selectedBrandId.value
  }
  formPopupRef.value?.open()
}

async function openEdit(item) {
  const id = item?.id
  if (id === undefined || id === null) {
    uni.showToast({ title: '缺少ID，无法编辑', icon: 'none' })
    return
  }
  try {
    const res = await getMoldDetail(id)
    const detail = normalizeDetailData(res)
    formMode.value = 'update'
    formData.value = {
      id: detail?.id,
      code: textValueForInput(detail?.code),
      isCode: Boolean(detail?.isCode),
      name: textValueForInput(detail?.name),
      unitId: textValueForInput(detail?.unitId),
      useTime: textValueForInput(detail?.useTime),
      inTimeDate: normalizeDateInput(detail?.inTime),
      status: detail?.status ?? '',
      remark: textValueForInput(detail?.remark),
      images: parseImages(detail?.images),
      brandId: detail?.brandId,
      isEnable: detail?.isEnable ?? true
    }
    formPopupRef.value?.open()
  } catch (e) {
    uni.showToast({ title: '加载编辑数据失败', icon: 'none' })
  }
}

function closeForm() {
  formPopupRef.value?.close()
}

async function submitForm() {
  if (!formData.value.brandId && formData.value.brandId !== 0) {
    uni.showToast({ title: '请选择模具型号', icon: 'none' })
    return
  }
  if (!formData.value.isCode && !String(formData.value.code || '').trim()) {
    uni.showToast({ title: '模具编码必填', icon: 'none' })
    return
  }
  if (!String(formData.value.name || '').trim()) {
    uni.showToast({ title: '模具名称必填', icon: 'none' })
    return
  }
  if (!String(formData.value.unitId || '').trim()) {
    uni.showToast({ title: '单位ID必填', icon: 'none' })
    return
  }
  if (!String(formData.value.inTimeDate || '').trim()) {
    uni.showToast({ title: '入库时间必填', icon: 'none' })
    return
  }
  if (formData.value.isEnable === undefined || formData.value.isEnable === null) {
    uni.showToast({ title: '请选择是否启用', icon: 'none' })
    return
  }
  const payload = {
    id: formMode.value === 'update' ? formData.value.id : undefined,
    code: formData.value.isCode ? undefined : String(formData.value.code || '').trim(),
    name: String(formData.value.name || '').trim(),
    unitId: toNumberOrUndefined(formData.value.unitId),
    brandId: formData.value.brandId,
    useTime: toNumberOrUndefined(formData.value.useTime) ?? 0,
    inTime: normalizeInTimeForSubmit(formData.value.inTimeDate),
    status: toNumberOrUndefined(formData.value.status) ?? 3,
    remark: String(formData.value.remark || '').trim() || undefined,
    images: formData.value.images.join(','),
    isEnable: formData.value.isEnable,
    isCode: formData.value.isCode
  }
  try {
    if (formMode.value === 'create') {
      await createMold(payload)
      uni.showToast({ title: '新增成功', icon: 'success' })
    } else {
      await updateMold(payload)
      uni.showToast({ title: '更新成功', icon: 'success' })
    }
    closeForm()
    await fetchList(true)
  } catch (e) {
    uni.showToast({ title: '保存失败', icon: 'none' })
  }
}

function confirmDelete(item) {
  const id = item?.id
  if (id === undefined || id === null) {
    uni.showToast({ title: '缺少ID，无法删除', icon: 'none' })
    return
  }
  uni.showModal({
    title: '确认删除',
    content: `确认删除模具"${textValue(item?.name)}"吗？`,
    success: async (res) => {
      if (!res.confirm) return
      try {
        await deleteMold(id)
        uni.showToast({ title: '删除成功', icon: 'success' })
        await fetchList(true)
      } catch (e) {
        uni.showToast({ title: '删除失败', icon: 'none' })
      }
    }
  })
}

function resetForm() {
  formData.value = {
    id: undefined,
    code: '',
    isCode: true,
    name: '',
    unitId: '',
    useTime: '',
    inTimeDate: '',
    status: '',
    remark: '',
    images: [],
    brandId: undefined,
    isEnable: true
  }
}

function handleInTimeChange(e) {
  formData.value.inTimeDate = e?.detail?.value || ''
}

function handleFormStatusChange(e) {
  const idx = Number(e?.detail?.value)
  const option = statusOptions.value[idx]
  formData.value.status = option ? option.value : ''
}

function normalizePageData(res) {
  const root = res && res.data !== undefined ? res.data : res
  const candidateList = root?.list || root?.rows || root?.records || root?.data?.list || root?.data?.rows || []
  const candidateTotal = root?.total ?? root?.data?.total ?? (Array.isArray(candidateList) ? candidateList.length : 0)
  return {
    list: Array.isArray(candidateList) ? candidateList : [],
    total: Number(candidateTotal || 0)
  }
}

function normalizeListData(res) {
  const root = res && res.data !== undefined ? res.data : res
  if (Array.isArray(root)) return root
  if (Array.isArray(root?.data)) return root.data
  if (Array.isArray(root?.list)) return root.list
  return []
}

function normalizeDetailData(res) {
  const root = res && res.data !== undefined ? res.data : res
  if (root?.data && typeof root.data === 'object') return root.data
  if (root && typeof root === 'object') return root
  return {}
}

function moldStatusText(status) {
  return getDictLabel(DICT_TYPE.ERP_MOLD_STATUS, status, textValue(status))
}

function statusClass(status) {
  const label = moldStatusText(status)
  if (label.includes('正常') || label.toLowerCase() === 'ok') return 'status-normal'
  if (label.includes('停') || label.includes('坏') || label.includes('禁') || label.toLowerCase() === 'ng') return 'status-danger'
  return 'status-warning'
}

function textValue(value) {
  if (value === 0) return '0'
  if (value === false) return '否'
  if (value === true) return '是'
  if (value === null || value === undefined) return '-'
  const text = String(value).trim()
  return text || '-'
}

function formatDateTime(value) {
  if (!value) return '-'
  if (Array.isArray(value) && value.length >= 3) {
    const [y, m, d, hh = 0, mm = 0, ss = 0] = value
    const pad = (n) => String(n).padStart(2, '0')
    return `${y}-${pad(m)}-${pad(d)} ${pad(hh)}:${pad(mm)}:${pad(ss)}`
  }
  const text = String(value).trim()
  if (!text) return '-'
  const num = Number(text)
  if (Number.isFinite(num)) {
    const time = text.length === 10 ? num * 1000 : num
    const date = new Date(time)
    if (!Number.isNaN(date.getTime())) {
      return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`
    }
  }
  const date = new Date(text)
  if (!Number.isNaN(date.getTime())) {
    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`
  }
  return text
}

function normalizeDateInput(value) {
  const text = formatDateTime(value)
  return text === '-' ? '' : text.split(' ')[0]
}

function toNumberOrUndefined(value) {
  if (value === null || value === undefined || String(value).trim() === '') return undefined
  const num = Number(value)
  return Number.isFinite(num) ? num : undefined
}

function textValueForInput(value) {
  if (value === null || value === undefined) return ''
  return String(value)
}

function normalizeInTimeForSubmit(value) {
  const text = String(value || '').trim()
  if (!text) return undefined
  const date = new Date(text)
  if (Number.isNaN(date.getTime())) return text
  return date.getTime()
}

function parseImages(value) {
  if (!value) return []
  if (Array.isArray(value)) return value.map((v) => String(v)).filter(Boolean)
  return String(value).split(',').map((v) => v.trim()).filter(Boolean)
}

function previewImages(list, current) {
  if (!list || !list.length) return
  uni.previewImage({ urls: list, current })
}

function removeImage(index) {
  formData.value.images.splice(index, 1)
}

async function chooseAndUploadImages() {
  const remain = Math.max(0, 6 - formData.value.images.length)
  if (remain <= 0) return
  uni.chooseImage({
    count: remain,
    sizeType: ['compressed'],
    sourceType: ['album', 'camera'],
    success: async (res) => {
      const paths = Array.isArray(res?.tempFilePaths) ? res.tempFilePaths : []
      if (!paths.length) return
      uni.showLoading({ title: '上传中', mask: true })
      try {
        for (const filePath of paths) {
          const uploadRes = await uploadMoldImage(filePath)
          const url = resolveUploadUrl(uploadRes)
          if (url) {
            formData.value.images.push(url)
          }
        }
      } catch (e) {
        uni.showToast({ title: '图片上传失败', icon: 'none' })
      } finally {
        uni.hideLoading()
      }
    }
  })
}

function resolveUploadUrl(res) {
  const root = res && res.data !== undefined ? res.data : res
  const data = root?.data !== undefined ? root.data : root
  if (typeof data === 'string') return data
  if (data && typeof data.url === 'string') return data.url
  if (data && typeof data.fullUrl === 'string') return data.fullUrl
  if (data && typeof data.path === 'string') return data.path
  return ''
}
</script>

<style lang="scss" scoped>
.page-container {
  min-height: 100vh;
  background-color: #f0f2f5;
}

.filter-card {
  background: #ffffff;
  margin: 20rpx 24rpx;
  border-radius: 18rpx;
  padding: 20rpx;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
}

.filter-row {
  display: flex;
  gap: 16rpx;
}

.filter-item {
  flex: 1;
  background: #f7f9fc;
  border-radius: 12rpx;
  min-height: 84rpx;
  display: flex;
  align-items: center;
  padding: 0 16rpx;
}

.filter-label {
  font-size: 24rpx;
  color: #8a9099;
  margin-right: 12rpx;
}

.filter-value {
  flex: 1;
  font-size: 26rpx;
  color: #2f353d;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.placeholder {
  color: #a3a9b2;
}

.filter-arrow {
  font-size: 34rpx;
  color: #b1b7bf;
}

.search-row {
  display: flex;
  gap: 14rpx;
  margin-top: 16rpx;
}

.search-wrapper {
  flex: 1;
  display: flex;
  align-items: center;
  background: #f5f7fa;
  border-radius: 42rpx;
  padding: 0 20rpx;
}

.search-icon {
  margin-right: 14rpx;

  .iconfont {
    font-size: 34rpx;
    color: #666666;
  }
}

.search-input {
  flex: 1;
  height: 72rpx;
  font-size: 28rpx;
  color: #333333;
  background: transparent;
}

.input-placeholder {
  color: #a0a6ad;
}

.clear-btn {
  width: 42rpx;
  height: 42rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.clear-icon {
  font-size: 34rpx;
  color: #999999;
}

.search-btn {
  width: 140rpx;
  height: 72rpx;
  border-radius: 36rpx;
  background: linear-gradient(135deg, #1a3a5c 0%, #2d5a87 100%);
  display: flex;
  align-items: center;
  justify-content: center;
}

.search-btn-text {
  color: #ffffff;
  font-size: 28rpx;
  font-weight: 600;
}

.content-scroll {
  height: calc(100vh - 380rpx);
}

.list-wrap {
  padding: 0 24rpx 40rpx;
}

.ledger-card {
  background: #ffffff;
  border-radius: 18rpx;
  padding: 24rpx;
  margin-bottom: 18rpx;
  box-shadow: 0 4rpx 18rpx rgba(0, 0, 0, 0.05);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1rpx solid #eef1f4;
  padding-bottom: 16rpx;
}

.name {
  display: block;
  font-size: 32rpx;
  color: #1a3a5c;
  font-weight: 600;
}

.code {
  display: block;
  margin-top: 8rpx;
  font-size: 24rpx;
  color: #8c929a;
}

.code-wrapper {
  display: flex;
  align-items: center;
  gap: 8rpx;
}

.header-right {
  display: flex;
  align-items: center;
  gap: 12rpx;
}

.card-actions {
  margin-top: 24rpx;
  display: flex;
  justify-content: flex-end;
  gap: 14rpx;
}

.action-btn {
  width: 60rpx;
  height: 60rpx;
  border-radius: 12rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.action-icon {
  color: #ffffff;
  font-size: 28rpx;
}

.edit-btn {
  background: #1a3a5c;
}

.delete-btn {
  background: #ff4d4f;
}

.status-chip {
  padding: 8rpx 16rpx;
  border-radius: 999rpx;
  font-size: 22rpx;
}

.status-normal {
  background: rgba(31, 178, 94, 0.12);
  color: #0d9b4f;
}

.status-warning {
  background: rgba(255, 153, 0, 0.14);
  color: #db8400;
}

.status-danger {
  background: rgba(255, 77, 79, 0.14);
  color: #de3d40;
}

.card-body {
  padding-top: 10rpx;
}

.row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 12rpx;
}

.label {
  font-size: 26rpx;
  color: #8a9099;
}

.value {
  max-width: 62%;
  text-align: right;
  font-size: 27rpx;
  color: #2f353d;
}

.loading-text,
.empty-text,
.finished-text {
  text-align: center;
  color: #9aa2ab;
  font-size: 26rpx;
  padding: 28rpx 0;
}

.go-top-btn {
  position: fixed;
  right: 28rpx;
  bottom: 150rpx;
  width: 88rpx;
  height: 88rpx;
  border-radius: 44rpx;
  background: rgba(26, 58, 92, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 99;
  box-shadow: 0 6rpx 16rpx rgba(26, 58, 92, 0.25);
}

.go-top-icon {
  color: #ffffff;
  font-size: 36rpx;
  font-weight: 700;
}

.add-btn {
  position: fixed;
  right: 28rpx;
  bottom: 258rpx;
  width: 96rpx;
  height: 96rpx;
  border-radius: 48rpx;
  background: linear-gradient(135deg, #1a3a5c 0%, #2d5a87 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 99;
  box-shadow: 0 8rpx 24rpx rgba(26, 58, 92, 0.32);
}

.add-icon {
  color: #ffffff;
  font-size: 56rpx;
  line-height: 1;
}

.picker-content {
  border-top-left-radius: 20rpx;
  border-top-right-radius: 20rpx;
  max-height: 70vh;
  overflow: hidden;
}

.picker-header {
  padding: 24rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1rpx solid #edf0f3;
}

.popup-header {
  margin: 10rpx 0 0 20rpx;
}

.picker-title {
  font-size: 30rpx;
  font-weight: 600;
  color: #1a3a5c;
}

.picker-clear-text {
  font-size: 26rpx;
  color: #2d5a87;
}

.picker-list {
  max-height: 58vh;
}

.picker-item {
  min-height: 84rpx;
  padding: 0 24rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1rpx solid #f2f4f7;
}

.picker-text {
  flex: 1;
  font-size: 28rpx;
  color: #2f353d;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.picker-check {
  font-size: 30rpx;
  color: #2d5a87;
  margin-left: 20rpx;
}

.popup-content-center {
  width: 680rpx;
  max-height: 82vh;

  overflow: hidden;
}

.form-scroll {
  max-height: 56vh;
}

.form-content {
  padding: 24rpx;
}

.form-item {
  margin-bottom: 16rpx;
}

.form-label {
  display: block;
  margin-bottom: 8rpx;
  font-size: 26rpx;
  color: #8a9099;
}

.required-star {
  color: #ff4d4f;
}

.form-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8rpx;
}

.switch-wrap {
  display: flex;
  align-items: center;
  gap: 10rpx;
}

.switch-label {
  font-size: 24rpx;
  color: #8a9099;
}

.form-input {
  height: 76rpx;
  padding: 0 20rpx;
  border-radius: 12rpx;
  background: #f5f7fa;
  font-size: 28rpx;
  color: #30363d;
}

.form-input[disabled] {
  color: #a3a9b2;
}

.form-picker {
  height: 76rpx;
  border-radius: 12rpx;
  background: #f5f7fa;
  padding: 0 20rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.form-picker-text {
  flex: 1;
  font-size: 28rpx;
  color: #30363d;
}

.form-textarea {
  width: 100%;
  min-height: 130rpx;
  border-radius: 12rpx;
  background: #f5f7fa;
  padding: 16rpx 20rpx;
  font-size: 28rpx;
  color: #30363d;
}

.image-list {
  display: flex;
  flex-wrap: wrap;
  gap: 14rpx;
}

.image-item,
.image-add {
  width: 130rpx;
  height: 130rpx;
  border-radius: 12rpx;
  overflow: hidden;
  position: relative;
}

.image-preview {
  width: 100%;
  height: 100%;
  background: #edf0f4;
}

.image-add {
  background: #f5f7fa;
  border: 1rpx dashed #c8ced6;
  display: flex;
  align-items: center;
  justify-content: center;
}

.image-add-text {
  font-size: 52rpx;
  color: #8e95a0;
  line-height: 1;
}

.image-delete {
  position: absolute;
  top: 0;
  right: 0;
  width: 36rpx;
  height: 36rpx;
  border-bottom-left-radius: 10rpx;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
}

.image-delete-text {
  color: #ffffff;
  font-size: 24rpx;
  line-height: 1;
}

.enable-group {
  display: flex;
  gap: 14rpx;
}

.enable-item {
  flex: 1;
  height: 72rpx;
  border-radius: 12rpx;
  background: #f5f7fa;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28rpx;
  color: #586070;
}

.enable-item.active {
  background: rgba(45, 90, 135, 0.12);
  color: #1a3a5c;
  font-weight: 600;
}

.form-footer {
  display: flex;
  gap: 14rpx;
  padding: 20rpx 24rpx 24rpx;
}

.footer-btn {
  flex: 1;
  height: 76rpx;
  border-radius: 12rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cancel-btn {
  background: #edf0f4;
}

.confirm-btn {
  background: linear-gradient(135deg, #1a3a5c 0%, #2d5a87 100%);
}

.btn-text {
  font-size: 28rpx;
  font-weight: 600;
  color: #ffffff;
}

.cancel-text {
  color: #586070;
}
</style>
