<template>
  <div class="buy-module">
    <div class="header-tools">
      <div class="left-tools">
        <el-input
            v-model="queryParams.keyword"
            placeholder="🔍 搜索物料名称 / 规格 / 批号 / SN / 供应商..."
            class="search-input"
            clearable
            @clear="fetchData"
            @keyup.enter="fetchData"
            style="width: 300px; margin-right: 10px;"
        >
          <template #append>
            <el-button :icon="Search" @click="fetchData"/>
          </template>
        </el-input>

        <el-select
            v-model="queryParams.statuses"
            multiple
            collapse-tags
            placeholder="状态筛选"
            style="width: 220px;"
            @change="fetchData"
        >
          <el-option label="在库" value="在库" />
          <el-option label="借库" value="借库" />
          <el-option label="已出库" value="已出库" />
        </el-select>
      </div>

      <div class="right-tools">
        <el-button type="primary" :icon="Plus" @click="handleCreate" class="action-btn">采购入库登记</el-button>
        <el-button :icon="Refresh" @click="fetchData" class="action-btn">刷新</el-button>

        <el-popover placement="bottom-end" title="列配置" :width="500" trigger="click">
          <template #reference>
            <el-button :icon="Setting" class="action-btn">表头</el-button>
          </template>
          <el-checkbox-group v-model="visibleColumnProps" class="column-selector">
            <div class="col-group-title">基础信息</div>
            <el-row :gutter="10">
              <el-col :span="12" v-for="c in baseColumns" :key="c.prop">
                <el-checkbox :label="c.prop">{{ c.label }}</el-checkbox>
              </el-col>
            </el-row>
            <div class="col-group-title" style="margin-top:10px">库存与商务</div>
            <el-row :gutter="10">
              <el-col :span="12" v-for="c in stockColumns" :key="c.prop">
                <el-checkbox :label="c.prop">{{ c.label }}</el-checkbox>
              </el-col>
            </el-row>
          </el-checkbox-group>
        </el-popover>
      </div>
    </div>

    <el-table
        v-loading="loading"
        :data="tableData"
        border
        stripe
        style="width: 100%"
        class="modern-table"
        highlight-current-row
        header-cell-class-name="table-header-gray"
    >
      <template v-for="col in allColumns" :key="col.prop">
        <el-table-column
            v-if="visibleColumnProps.includes(col.prop)"
            :prop="col.prop"
            :label="col.label"
            :min-width="col.minWidth || '140'"
            show-overflow-tooltip
        >
          <template #default="scope" v-if="col.prop === 'material_name'">
            <span class="clickable-text" @click="handleUpdate(scope.row)">
              {{ scope.row.material_name }}
            </span>
          </template>

          <template #default="scope" v-else-if="col.prop === 'sn_bn'">
            <div v-if="scope.row.serial_number" class="id-cell">
              <span class="prefix-tag sn">SN</span>
              <span class="id-text">{{ scope.row.serial_number }}</span>
            </div>
            <div v-else-if="scope.row.batch_number" class="id-cell">
              <span class="prefix-tag bn">BN</span>
              <span class="id-text">{{ scope.row.batch_number }}</span>
            </div>
            <span v-else class="text-placeholder">-</span>
          </template>

          <template #default="scope" v-else-if="col.prop === 'status'">
            <el-tag :type="getStatusType(scope.row.status)" effect="light" round>
              {{ scope.row.status }}
            </el-tag>
          </template>

          <template #default="scope" v-else-if="col.prop === 'qty_stock'">
            <span class="stock-num">{{ scope.row.qty_stock }}</span>
          </template>
          <template #default="scope" v-else-if="col.prop === 'qty_available'">
            <span class="avail-num">{{ scope.row.qty_available }}</span>
          </template>

          <template #default="scope" v-else-if="['arrival_photo', 'inspection_report'].includes(col.prop)">
            <div v-if="getImagesOnly(scope.row[col.prop]).length > 0" style="display: flex; align-items: center; justify-content: center;">
              <el-image
                  style="width: 40px; height: 40px; border-radius: 4px; border: 1px solid #dcdfe6; cursor: zoom-in;"
                  :src="getImageUrl(getImagesOnly(scope.row[col.prop])[0])"
                  :preview-src-list="getImagesOnly(scope.row[col.prop]).map(u => getImageUrl(u))"
                  preview-teleported
                  fit="cover"
              >
                <template #error>
                  <div class="image-slot"><el-icon><Picture /></el-icon></div>
                </template>
              </el-image>
              <span v-if="getImagesOnly(scope.row[col.prop]).length > 1" class="more-images-badge">+{{getImagesOnly(scope.row[col.prop]).length}}</span>
            </div>
            <div v-else-if="hasExternalLink(scope.row[col.prop])" style="text-align: center;">
              <el-tag size="small" type="info"><el-icon><Link /></el-icon> 链接</el-tag>
            </div>
            <span v-else class="text-placeholder">-</span>
          </template>

          <template #default="scope" v-else-if="col.prop.includes('link')">
            <el-link v-if="scope.row[col.prop]" type="primary" :href="scope.row[col.prop]" target="_blank" :underline="false">
              <el-icon><Link/></el-icon> 查看
            </el-link>
          </template>

          <template #default="scope" v-else-if="['unit_price', 'total_price'].includes(col.prop)">
            <span class="money-text">{{ formatMoney(scope.row[col.prop], scope.row.currency) }}</span>
          </template>
        </el-table-column>
      </template>

      <el-table-column label="操作" width="220" fixed="right" align="center">
        <template #default="{ row }">
          <el-button link type="warning" size="default" @click="handlePrint(row)">
            <el-icon><Printer/></el-icon> 打印
          </el-button>
          <el-button link type="primary" size="default" @click="handleUpdate(row)">编辑</el-button>
          <el-popconfirm title="确定删除该条记录吗？不可恢复。" @confirm="handleDelete(row)" width="220">
            <template #reference>
              <el-button link type="danger" size="default">删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
        class="pagination-bar"
        v-model:current-page="queryParams.page"
        v-model:page-size="queryParams.pageSize"
        :total="total"
        :page-sizes="[15, 30, 50, 100]"
        layout="total, sizes, prev, pager, next, jumper"
        background
        @size-change="fetchData"
        @current-change="fetchData"
    />

    <el-dialog
        v-model="visible"
        :title="dialogStatus === 'create' ? '新增采购入库' : '编辑入库信息'"
        width="1000px"
        top="4vh"
        destroy-on-close
        :close-on-click-modal="false"
        class="stylish-dialog compact-layout"
    >
      <div class="dialog-scroll-container">
        <el-form :model="form" label-width="100px" ref="formRef" :rules="rules" size="default" class="stylish-form">

          <div class="form-card basic-card">
            <div class="card-title">
              <el-icon class="icon"><Box/></el-icon>
              <span>1. 基础信息</span>
              <span class="sub-title" v-if="dialogStatus === 'create'"> (请先搜索锁定物料)</span>
            </div>
            <div class="card-content">
              <el-row :gutter="24" v-if="dialogStatus === 'create'" style="margin-bottom: 15px;">
                <el-col :span="10">
                  <el-form-item label="物料搜索" prop="base_id" class="highlight-label">
                    <el-select
                        v-model="form.base_id"
                        filterable
                        remote
                        reserve-keyword
                        placeholder="输入名称或规格..."
                        :remote-method="handleSearchMaterial"
                        @visible-change="handleMaterialDropdownVisible"
                        :loading="searchLoading"
                        style="width: 100%"
                        @change="onMaterialSelected"
                        default-first-option
                    >
                      <el-option
                          v-for="item in materialOptions"
                          :key="item.id"
                          :label="item.name"
                          :value="item.id"
                      >
                        <div class="option-item">
                          <span class="opt-name">{{ item.name }}</span>
                          <span class="opt-spec">{{ item.spec }}</span>
                          <el-tag v-if="item.isHistory" size="small" type="info" effect="plain">历史</el-tag>
                          <el-tag v-else size="small" type="success" effect="plain">系统</el-tag>
                        </div>
                      </el-option>
                    </el-select>
                  </el-form-item>
                </el-col>
                <el-col :span="14" style="display: flex; align-items: center;">
                  <span class="search-tip">
                    <el-icon><InfoFilled/></el-icon> 未输入时展示最新物料；输入关键词进行精确搜索。
                  </span>
                </el-col>
              </el-row>

              <div class="read-only-grid">
                <el-row :gutter="20">
                  <el-col :span="8"><el-form-item label="名称"><el-input v-model="form.material_name" disabled class="is-text-view"/></el-form-item></el-col>
                  <el-col :span="8"><el-form-item label="类型"><el-input v-model="form.material_type" disabled class="is-text-view"/></el-form-item></el-col>
                  <el-col :span="8"><el-form-item label="类别"><el-input v-model="form.category" disabled class="is-text-view"/></el-form-item></el-col>
                  <el-col :span="8"><el-form-item label="规格型号"><el-input v-model="form.spec_model" disabled class="is-text-view"/></el-form-item></el-col>
                  <el-col :span="8"><el-form-item label="单位"><el-input v-model="form.unit" disabled class="is-text-view"/></el-form-item></el-col>
                </el-row>
              </div>
            </div>
          </div>

          <div class="form-card inbound-card">
            <div class="card-title">
              <el-icon class="icon"><House/></el-icon>
              <span>2. 入库详情</span>
            </div>
            <div class="card-content">
              <el-row :gutter="20">
                <el-col :span="6">
                  <el-form-item label="编码/SKU" prop="sku"><el-input v-model="form.sku" placeholder="系统自动生成" disabled/></el-form-item>
                </el-col>
                <el-col :span="6">
                  <el-form-item label="入库日期" prop="in_date"><el-date-picker v-model="form.in_date" type="date" value-format="YYYY-MM-DD" style="width:100%" disabled/></el-form-item>
                </el-col>
                <el-col :span="6">
                  <el-form-item label="条码" prop="barcode"><el-input v-model="form.barcode" placeholder="扫描条码"/></el-form-item>
                </el-col>
                <el-col :span="6">
                  <el-form-item label="库位" prop="warehouse_location"><el-input v-model="form.warehouse_location" placeholder="例如: A-01-02"/></el-form-item>
                </el-col>
              </el-row>

              <div class="identity-panel">
                <el-row>
                  <el-col :span="24" style="margin-bottom: 8px;">
                    <el-radio-group v-model="entryMode" @change="handleEntryModeChange" :disabled="modeLocked" size="small" class="custom-radio-group">
                      <el-radio-button label="batch">按批号入库 (Batch)</el-radio-button>
                      <el-radio-button label="serial">按序列号入库 (SN)</el-radio-button>
                    </el-radio-group>
                    <span v-if="modeLocked" class="locked-msg"><el-icon><Lock/></el-icon> 历史锁定 (同物料遵循历史模式)</span>
                  </el-col>
                </el-row>
                <el-row :gutter="20">
                  <el-col :span="12">
                    <el-form-item label="批号" prop="batch_number">
                      <el-input v-model="form.batch_number" :placeholder="entryMode === 'batch' ? '系统生成...' : '不可用'" :disabled="entryMode === 'serial'" clearable>
                        <template #prefix><span class="prefix-tag bn">BN</span></template>
                      </el-input>
                    </el-form-item>
                  </el-col>
                  <el-col :span="12">
                    <el-form-item label="序列号" prop="serial_number">
                      <el-input v-model="form.serial_number" :placeholder="entryMode === 'serial' ? '请扫描 SN...' : '不可用'" :disabled="entryMode === 'batch'" clearable>
                        <template #prefix><span class="prefix-tag sn">SN</span></template>
                      </el-input>
                    </el-form-item>
                  </el-col>
                </el-row>
              </div>

              <el-row :gutter="20" style="margin-top: 10px;">
                <el-col :span="6">
                  <el-form-item label="入库数量" prop="in_quantity">
                    <el-input-number v-model="form.in_quantity" :min="1" controls-position="right" style="width:100%" class="strong-input"/>
                  </el-form-item>
                </el-col>
                <template v-if="dialogStatus === 'update'">
                  <el-col :span="6"><el-form-item label="当前库存" prop="stock_quantity"><el-input-number v-model="form.stock_quantity" disabled style="width:100%" :controls="false"/></el-form-item></el-col>
                  <el-col :span="6"><el-form-item label="当前可用" prop="available_quantity"><el-input-number v-model="form.available_quantity" disabled style="width:100%" :controls="false"/></el-form-item></el-col>
                  <el-col :span="6">
                    <el-form-item label="库存状态" prop="status">
                      <el-select v-model="form.status" style="width:100%">
                        <el-option label="在库" value="在库"/>
                        <el-option label="已出库" value="已出库"/>
                        <el-option label="借库" value="借库"/>
                      </el-select>
                    </el-form-item>
                  </el-col>
                </template>
                <el-col :span="6">
                  <el-form-item label="到检状态" prop="inspection_status">
                    <el-select v-model="form.inspection_status" style="width:100%">
                      <el-option label="未检" value="未检"><span style="color:#909399">⚪ 未检</span></el-option>
                      <el-option label="合格" value="合格"><span style="color:#67C23A">🟢 合格</span></el-option>
                      <el-option label="不合格" value="不合格"><span style="color:#F56C6C">🔴 不合格</span></el-option>
                    </el-select>
                  </el-form-item>
                </el-col>
              </el-row>

              <el-row :gutter="20">
                <el-col :span="24">
                  <el-form-item label="到货图片" prop="arrival_photo">
                    <div class="upload-container">
                      <el-upload v-model:file-list="arrivalFileList" action="#" list-type="picture-card" multiple :http-request="(opts) => customUpload(opts, 'arrival_photo')" :on-preview="handlePreviewPicture" :on-remove="(file) => handleRemoveImage(file, 'arrival_photo')" :before-upload="beforeAvatarUpload">
                        <el-icon><Plus /></el-icon>
                      </el-upload>
                      <div class="camera-card" @click="triggerCamera('arrival_photo')"><el-icon><Camera /></el-icon><span class="text">拍照</span></div>
                    </div>
                    <el-input v-model="form.arrival_photo" placeholder="图片列表" style="display:none;" />
                  </el-form-item>
                </el-col>
                <el-col :span="24">
                  <el-form-item label="检测报告" prop="inspection_report">
                    <div class="upload-container">
                      <el-upload v-model:file-list="reportFileList" action="#" list-type="picture-card" multiple :http-request="(opts) => customUpload(opts, 'inspection_report')" :on-preview="handlePreviewPicture" :on-remove="(file) => handleRemoveImage(file, 'inspection_report')" :before-upload="beforeAvatarUpload">
                        <el-icon><Plus /></el-icon>
                      </el-upload>
                      <div class="camera-card" @click="triggerCamera('inspection_report')"><el-icon><Camera /></el-icon><span class="text">拍照</span></div>
                    </div>
                    <el-input v-model="inspection_report_url" placeholder="如有外部报告链接，请在此输入 (选填)" style="margin-top: 8px;" clearable><template #prefix><el-icon><Link /></el-icon></template></el-input>
                    <el-input v-model="form.inspection_report" placeholder="图片列表" style="display:none;" />
                  </el-form-item>
                </el-col>
              </el-row>

              <div class="divider-text">商务与采购信息</div>
              <el-row :gutter="20">
                <el-col :span="6">
                  <el-form-item label="币种">
                    <el-autocomplete v-model="form.currency" :fetch-suggestions="querySearchCurrency" placeholder="币种" style="width: 100%" :trigger-on-focus="true">
                      <template #default="{ item }"><span>{{ item.value }}</span><span style="float:right; color:#999; font-size:12px">{{ item.desc }}</span></template>
                    </el-autocomplete>
                  </el-form-item>
                </el-col>
                <el-col :span="6"><el-form-item label="汇率"><el-input-number v-model="form.exchange_rate" :precision="2" controls-position="right" style="width:100%"/></el-form-item></el-col>
                <el-col :span="6"><el-form-item label="含税单价" prop="unit_price"><el-input-number v-model="form.unit_price" :precision="4" controls-position="right" style="width:100%"/></el-form-item></el-col>
                <el-col :span="6"><el-form-item label="总价"><el-input-number v-model="form.total_price" :precision="2" disabled :controls="false" style="width:100%" class="total-price-input"/></el-form-item></el-col>
              </el-row>
              <el-row :gutter="20">
                <el-col :span="8"><el-form-item label="供应商"><el-autocomplete v-model="form.supplier_name" :fetch-suggestions="querySearchSupplier" placeholder="输入或选择供应商" style="width: 100%" clearable :trigger-on-focus="true" @select="handleSupplierSelect"/></el-form-item></el-col>
                <el-col :span="8"><el-form-item label="采购人"><el-autocomplete v-model="form.purchaser" :fetch-suggestions="querySearchPurchaser" placeholder="输入采购人" style="width: 100%" clearable :trigger-on-focus="true" @select="handlePurchaserSelect"/></el-form-item></el-col>
                <el-col :span="8"><el-form-item label="采购邮箱"><el-autocomplete v-model="form.purchaser_email" :fetch-suggestions="querySearchEmail" placeholder="输入邮箱" style="width: 100%" clearable :trigger-on-focus="true" @select="handleEmailSelect"/></el-form-item></el-col>
              </el-row>
              <el-row :gutter="20">
                <el-col :span="12"><el-form-item label="原始链接"><el-input v-model="form.source_link" placeholder="http://"/></el-form-item></el-col>
                <el-col :span="12"><el-form-item label="详情链接"><el-input v-model="form.detail_link" placeholder="http://"/></el-form-item></el-col>
              </el-row>
            </div>
          </div>
        </el-form>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="visible = false" size="large">取消</el-button>
          <el-button type="primary" :loading="submitting" @click="submitForm" size="large" class="confirm-btn">{{ dialogStatus === 'create' ? '确认入库并打印' : '保存修改' }}</el-button>
        </div>
      </template>
    </el-dialog>

    <input type="file" ref="cameraInputRef" accept="image/*" capture="environment" style="display: none" @change="handleCameraFile"/>

    <el-dialog v-model="dialogVisibleImage" append-to-body width="50%"><img style="width: 100%" :src="dialogImageUrl" alt="Preview Image" /></el-dialog>

    <el-dialog v-model="printVisible" title="标签打印预览" width="400px" destroy-on-close append-to-body>
      <div style="text-align: center;">
        <div v-loading="printLoading" class="preview-box">
          <img v-if="previewUrl" :src="previewUrl" alt="Label Preview" style="width: 100%; border: 1px solid #ccc;"/>
          <div v-else class="empty-preview">正在生成预览...</div>
        </div>
        <div style="margin-top: 20px; font-size: 14px; color: #666;"><p>打印机 IP: 192.168.9.205</p><p>尺寸: 40mm x 30mm</p></div>
      </div>
      <template #footer>
        <div class="dialog-footer"><el-button @click="printVisible = false">取消</el-button><el-button type="primary" :loading="printing" @click="confirmPrint"><el-icon><Printer/></el-icon>确认打印</el-button></div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import {ref, reactive, onMounted, watch} from 'vue'
import {Plus, Setting, Refresh, Search, Lock, Box, House, InfoFilled, Link, Printer, Camera, Delete, Picture} from '@element-plus/icons-vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import dayjs from 'dayjs'
import {
  getBuyList,
  createBuyInbound,
  updateBuyInbound,
  deleteBuyInbound,
  searchMaterialBase,
  uploadFile,
  deleteFile
} from '@/api/inbound/buy'
import {getLabelPreview, executePrint} from '@/api/common/print'

// ------------------------------------
// 状态与变量
// ------------------------------------
const loading = ref(false)
const submitting = ref(false)
const visible = ref(false)
const searchLoading = ref(false)
const dialogStatus = ref<'create' | 'update'>('create')
const tableData = ref([])
const total = ref(0)
const formRef = ref()

const queryParams = reactive({
  page: 1,
  pageSize: 15,
  keyword: '',
  statuses: ['在库', '借库']
})

const materialOptions = ref<any[]>([])
const printVisible = ref(false)
const printLoading = ref(false)
const printing = ref(false)
const previewUrl = ref('')
const currentPrintData = ref<any>({})
const entryMode = ref('batch')
const modeLocked = ref(false)
const dialogImageUrl = ref('')
const dialogVisibleImage = ref(false)
const arrivalFileList = ref<any[]>([])
const reportFileList = ref<any[]>([])
const cameraInputRef = ref<HTMLInputElement | null>(null)
const currentCameraField = ref<'arrival_photo' | 'inspection_report'>('arrival_photo')
const inspection_report_url = ref('')

// 基础列
const baseColumns = [
  {prop: 'material_name', label: '名称'},
  {prop: 'material_type', label: '类型'},
  {prop: 'category', label: '类别'},
  {prop: 'spec_model', label: '规格型号'},
  {prop: 'unit', label: '单位'},
]

// 库存与商务列
const stockColumns = [
  {prop: 'id', label: 'ID', minWidth: '60'},
  {prop: 'base_id', label: 'BaseID', minWidth: '80'},
  {prop: 'sku', label: 'SKU', minWidth: '120'},
  {prop: 'inbound_date', label: '入库日期', minWidth: '120'},
  {prop: 'barcode', label: '条码', minWidth: '120'},
  {prop: 'sn_bn', label: '序列号/批号', minWidth: '160'},
  {prop: 'status', label: '状态', minWidth: '100'},
  {prop: 'inspection_status', label: '到检', minWidth: '100'},
  {prop: 'qty_inbound', label: '入库量', minWidth: '100'},
  {prop: 'qty_stock', label: '库存数', minWidth: '100'},
  {prop: 'qty_available', label: '可用数', minWidth: '100'},
  {prop: 'warehouse_loc', label: '库位', minWidth: '120'},
  {prop: 'unit_price', label: '单价', minWidth: '120'},
  {prop: 'total_price', label: '总价', minWidth: '120'},
  {prop: 'currency', label: '币种', minWidth: '80'},
  {prop: 'exchange_rate', label: '汇率', minWidth: '80'},
  {prop: 'supplier_name', label: '供应商', minWidth: '150'},
  {prop: 'purchaser', label: '采购人', minWidth: '100'},
  {prop: 'purchaser_email', label: '邮箱', minWidth: '150'},
  {prop: 'source_link', label: '采购链接', minWidth: '100'},
  {prop: 'detail_link', label: '详情链接', minWidth: '100'},
  {prop: 'arrival_photo', label: '到货图', minWidth: '100'},
  {prop: 'inspection_report', label: '检测报告', minWidth: '100'}
]

const allColumns = [...baseColumns, ...stockColumns]
const STORAGE_KEY_COLS = 'stock_buy_visible_columns_v2'

const defaultColumns = [
  'material_name', 'material_type', 'category', 'spec_model', 'unit',
  'inbound_date', 'sn_bn', 'warehouse_loc', 'status', 'inspection_status',
  'unit_price', 'total_price', 'supplier_name', 'purchaser', 'qty_stock', 'qty_available', 'arrival_photo', 'inspection_report'
]

const getSavedColumns = () => { try { const saved = localStorage.getItem(STORAGE_KEY_COLS); return saved ? JSON.parse(saved) : defaultColumns } catch (e) { return defaultColumns } }
const visibleColumnProps = ref(getSavedColumns())
watch(visibleColumnProps, (newVal) => { localStorage.setItem(STORAGE_KEY_COLS, JSON.stringify(newVal)) }, {deep: true})

const form = reactive({
  id: undefined, base_id: undefined as number | undefined, material_name: '', spec_model: '', category: '', unit: '', material_type: '',
  sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', inspection_status: '未检',
  in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '',
  unit_price: 0, total_price: 0, currency: 'CNY', exchange_rate: 1.00,
  supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '',
  arrival_photo: [] as string[], inspection_report: [] as string[]
})

// 历史记录辅助函数
const HISTORY_KEYS = { SUPPLIER: 'history_suppliers', PURCHASER: 'history_purchasers', EMAIL: 'history_emails', MATERIAL: 'history_materials' }
const saveToHistory = (key: string, value: string) => {
  if (!value) return
  try {
    const existing = localStorage.getItem(key)
    let list = existing ? JSON.parse(existing) : []
    list = list.filter((i: string) => i !== value)
    list.unshift(value)
    if (list.length > 20) list = list.slice(0, 20)
    localStorage.setItem(key, JSON.stringify(list))
  } catch (e) { console.error('save history failed', e) }
}
const getHistoryList = (key: string): any[] => {
  try { return (JSON.parse(localStorage.getItem(key) || '[]')).map((v: string) => ({value: v})) } catch (e) { return [] }
}
const saveMaterialHistory = (item: any) => {
  if (!item || !item.id) return
  const key = HISTORY_KEYS.MATERIAL
  try {
    let list = JSON.parse(localStorage.getItem(key) || '[]')
    list = list.filter((i: any) => i.id !== item.id)
    list.unshift({...item, isHistory: true})
    if (list.length > 10) list = list.slice(0, 10)
    localStorage.setItem(key, JSON.stringify(list))
  } catch (e) {}
}
const getMaterialHistory = () => {
  try { return JSON.parse(localStorage.getItem(HISTORY_KEYS.MATERIAL) || '[]') } catch (e) { return [] }
}

const createFilter = (queryString: string) => { return (item: any) => (item.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0) }
const getTableDataUnique = (field: string) => { return Array.from(new Set(tableData.value.map((i: any) => i[field]).filter(Boolean))).map(i => ({value: i})) }
const mixedSearch = (queryString: string, tableField: string, storageKey: string, cb: any) => {
  const tableList = getTableDataUnique(tableField)
  const historyList = getHistoryList(storageKey)
  const map = new Map()
  historyList.forEach(i => map.set(i.value, i))
  tableList.forEach(i => map.set(i.value, i))
  const allList = Array.from(map.values())
  const results = queryString ? allList.filter(createFilter(queryString)) : allList
  cb(results)
}

const querySearchSupplier = (qs: string, cb: any) => mixedSearch(qs, 'supplier_name', HISTORY_KEYS.SUPPLIER, cb)
const handleSupplierSelect = (item: any) => saveToHistory(HISTORY_KEYS.SUPPLIER, item.value)
const querySearchPurchaser = (qs: string, cb: any) => mixedSearch(qs, 'purchaser', HISTORY_KEYS.PURCHASER, cb)
const handlePurchaserSelect = (item: any) => saveToHistory(HISTORY_KEYS.PURCHASER, item.value)
const querySearchEmail = (qs: string, cb: any) => mixedSearch(qs, 'purchaser_email', HISTORY_KEYS.EMAIL, cb)
const handleEmailSelect = (item: any) => saveToHistory(HISTORY_KEYS.EMAIL, item.value)
const currencyOptions = [{value: 'CNY', desc: '人民币'}, {value: 'USD', desc: '美元'}, {value: 'EUR', desc: '欧元'}]
const querySearchCurrency = (queryString: string, cb: any) => { cb(queryString ? currencyOptions.filter(createFilter(queryString)) : currencyOptions) }

const handleMaterialDropdownVisible = (visible: boolean) => { if (visible && materialOptions.value.length === 0) handleSearchMaterial('') }
const handleSearchMaterial = async (query: string) => {
  searchLoading.value = true
  try {
    const res: any = await searchMaterialBase(query)
    const apiResults = (res.data || []).map((i: any) => ({...i, isHistory: false}))
    if (!query) {
      const history = getMaterialHistory()
      const historyIds = new Set(history.map((h: any) => h.id))
      materialOptions.value = [...history, ...apiResults.filter((apiItem: any) => !historyIds.has(apiItem.id))]
    } else { materialOptions.value = apiResults }
  } finally { searchLoading.value = false }
}
const onMaterialSelected = (val: number) => {
  const item = materialOptions.value.find(i => i.id === val)
  if (item) {
    saveMaterialHistory(item)
    form.material_name = item.name
    form.spec_model = item.spec
    form.category = item.category
    form.unit = item.unit
    form.material_type = item.type
    checkHistoryAndSetMode(item.id)
  }
}

// ------------------------------------
// 校验规则
// ------------------------------------
const validateUnique = (rule: any, value: string, callback: any) => {
  if (!value) return callback()
  // 前端仅做当前页面的简单重复提示，真正的校验在后端
  const isDuplicate = tableData.value.some((row: any) => {
    if (dialogStatus.value === 'update' && row.id === form.id) return false
    if (rule.field === 'serial_number' && row.serial_number === value) return true
    if (rule.field === 'batch_number' && row.batch_number === value && row.base_id === form.base_id) return true
    return false
  })
  if (isDuplicate) callback(new Error('当前列表页存在相同编号(后端将进行全局校验)'))
  else callback()
}
const validateIdentity = (rule: any, value: any, callback: any) => {
  if (entryMode.value === 'serial' && !form.serial_number && rule.field === 'serial_number') callback(new Error('SN必填'))
  else if (entryMode.value === 'batch' && !form.batch_number && rule.field === 'batch_number') callback(new Error('批号必填'))
  else callback()
}
const rules = {
  base_id: [{required: true, message: '请选择物料', trigger: 'change'}],
  in_quantity: [{required: true, message: '请输入数量', trigger: 'blur'}],
  serial_number: [{validator: validateIdentity, trigger: 'blur'}, {validator: validateUnique, trigger: 'blur'}],
  batch_number: [{validator: validateIdentity, trigger: 'blur'}, {validator: validateUnique, trigger: 'blur'}]
}

// 自动计算批号逻辑
const checkHistoryAndSetMode = async (baseId: number) => {
  try {
    const res: any = await getBuyList({page: 1, pageSize: 1000}) // 获取最近数据
    const historyItems = (res.data.items || []).filter((item: any) => item.base_id === baseId)

    if (historyItems.length > 0) {
      modeLocked.value = true
      // 找最新的那条记录
      const latest = historyItems.sort((a: any, b: any) => b.id - a.id)[0]
      if (latest.serial_number) {
        entryMode.value = 'serial'
        form.serial_number = ''
        form.batch_number = ''
      } else {
        entryMode.value = 'batch'
        form.serial_number = ''
        // 自动递增批号
        form.batch_number = incrementBatchNumber(latest.batch_number || '000000')
      }
    } else {
      modeLocked.value = false
      entryMode.value = 'batch'
      form.batch_number = '000001'
    }
    if (formRef.value) {
      formRef.value.clearValidate('serial_number')
      formRef.value.clearValidate('batch_number')
    }
  } catch (e) {
    modeLocked.value = false
    entryMode.value = 'batch'
    form.batch_number = '000001'
  }
}
const incrementBatchNumber = (batchStr: string) => {
  if (!batchStr || !/^\d+$/.test(batchStr)) return '000001'
  return (parseInt(batchStr, 10) + 1).toString().padStart(6, '0')
}
const handleEntryModeChange = (val: string) => {
  if (val === 'batch') {
    form.serial_number = ''
    form.batch_number = '000001'
    if(formRef.value) formRef.value.clearValidate('serial_number')
  } else {
    form.batch_number = ''
    if(formRef.value) formRef.value.clearValidate('batch_number')
  }
}
watch(() => [form.in_quantity, form.unit_price], () => { form.total_price = Number((form.in_quantity * form.unit_price).toFixed(4)) })

const fetchData = async () => {
  loading.value = true
  try {
    const params = { ...queryParams, statuses: queryParams.statuses.join(',') }
    const res: any = await getBuyList(params)
    tableData.value = res.data.items || []
    total.value = res.data.total || 0
  } finally { loading.value = false }
}

const handleCreate = () => {
  dialogStatus.value = 'create'
  resetForm()
  form.in_date = dayjs().format('YYYY-MM-DD')
  modeLocked.value = false
  entryMode.value = 'batch'
  form.batch_number = ''
  visible.value = true
  materialOptions.value = []
}

const handleUpdate = (row: any) => {
  dialogStatus.value = 'update'
  resetForm()
  modeLocked.value = true
  Object.assign(form, {
    id: row.id, base_id: row.base_id, material_name: row.material_name, spec_model: row.spec_model, category: row.category,
    unit: row.unit, material_type: row.material_type, sku: row.sku, barcode: row.barcode, in_date: row.inbound_date,
    warehouse_location: row.warehouse_loc, status: row.status, inspection_status: row.inspection_status,
    in_quantity: Number(row.qty_inbound), stock_quantity: Number(row.qty_stock), available_quantity: Number(row.qty_available),
    unit_price: Number(row.unit_price), total_price: Number(row.total_price), currency: row.currency, exchange_rate: Number(row.exchange_rate),
    supplier_name: row.supplier_name, purchaser: row.purchaser, purchaser_email: row.purchaser_email,
    source_link: row.source_link, detail_link: row.detail_link,
    arrival_photo: row.arrival_photo || [], inspection_report: row.inspection_report || []
  })
  arrivalFileList.value = form.arrival_photo.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }))
  const reports = form.inspection_report || []
  const reportImgs = reports.filter(r => !isExternalLink(r))
  const reportLinks = reports.filter(r => isExternalLink(r))
  reportFileList.value = reportImgs.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }))
  inspection_report_url.value = reportLinks.length > 0 ? reportLinks[0] : ''
  if (row.serial_number) { entryMode.value = 'serial'; form.serial_number = row.serial_number; form.batch_number = '' }
  else { entryMode.value = 'batch'; form.batch_number = row.batch_number; form.serial_number = '' }
  materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category }]
  visible.value = true
}

// ------------------------------------
// 提交逻辑
// ------------------------------------
const submitForm = async () => {
  if (!formRef.value) return
  await formRef.value.validate(async (valid: boolean) => {
    if (valid) {
      submitting.value = true
      const finalReportList = [...form.inspection_report]
      if (inspection_report_url.value && !finalReportList.includes(inspection_report_url.value)) finalReportList.push(inspection_report_url.value)
      const onlyImages = finalReportList.filter(item => !isExternalLink(item))
      if (inspection_report_url.value) onlyImages.push(inspection_report_url.value)
      const payload = { ...form, inspection_report: onlyImages, in_quantity: Number(form.in_quantity), unit_price: Number(form.unit_price) }
      try {
        if (dialogStatus.value === 'create') {
          const res: any = await createBuyInbound(payload)
          ElMessage.success('入库成功')
          if (res.data) {
            ElMessage.info('发送打印指令...')
            try { await executePrint(res.data); ElMessage.success('打印指令已发送') }
            catch (printErr: any) { ElMessage.warning('打印失败：' + (printErr.msg || '未知错误')) }
          }
        } else { await updateBuyInbound(form.id!, payload); ElMessage.success('更新成功') }

        // 成功后保存历史记录
        saveToHistory(HISTORY_KEYS.SUPPLIER, form.supplier_name)
        saveToHistory(HISTORY_KEYS.PURCHASER, form.purchaser)
        saveToHistory(HISTORY_KEYS.EMAIL, form.purchaser_email)

        await fetchData()
        visible.value = false
      } catch (e: any) {
        // 重点：捕获后端唯一性校验错误
        ElMessage.error(e.msg || '操作失败')
      } finally { submitting.value = false }
    }
  })
}

// 其他辅助函数保持不变
const getImageUrl = (url: string) => { return !url ? '' : (url.startsWith('http') ? url : url) }
const isExternalLink = (str: string) => { return str && (str.startsWith('http://') || str.startsWith('https://')) && !str.includes('/api/v1/common/files') }
const getImagesOnly = (list: string[]) => { return !list ? [] : list.filter(item => !isExternalLink(item)) }
const hasExternalLink = (list: string[]) => { return !list ? false : list.some(item => isExternalLink(item)) }
const beforeAvatarUpload = (rawFile: any) => {
  if (rawFile.type !== 'image/jpeg' && rawFile.type !== 'image/png') { ElMessage.error('仅支持 JPG/PNG'); return false }
  if (rawFile.size / 1024 / 1024 > 5) { ElMessage.error('图片不能超过 5MB'); return false }
  return true
}
const customUpload = async (options: any, targetField: 'arrival_photo' | 'inspection_report') => {
  const { file, onSuccess, onError } = options
  const formData = new FormData()
  formData.append('file', file)
  try {
    const res: any = await uploadFile(formData)
    if (res.code === 200) {
      const newUrl = res.data.url
      form[targetField].push(newUrl)
      ElMessage.success('上传成功')
      onSuccess(res)
    } else { ElMessage.error(res.msg || '上传失败'); onError(new Error(res.msg)) }
  } catch (e) { ElMessage.error('网络错误'); onError(e) }
}
const handleRemoveImage = async (uploadFile: any, targetField: 'arrival_photo' | 'inspection_report') => {
  try {
    const urlToRemove = form[targetField].find(u => getImageUrl(u) === uploadFile.url) || uploadFile.url
    form[targetField] = form[targetField].filter(u => u !== urlToRemove)
    if (!isExternalLink(urlToRemove)) { const filename = urlToRemove.split('/').pop(); if (filename) await deleteFile(filename) }
    ElMessage.success('已删除')
  } catch (e) { console.error(e) }
}
const handlePreviewPicture = (uploadFile: any) => { dialogImageUrl.value = uploadFile.url!; dialogVisibleImage.value = true }
const triggerCamera = (field: 'arrival_photo' | 'inspection_report') => { currentCameraField.value = field; if (cameraInputRef.value) cameraInputRef.value.click() }
const handleCameraFile = async (event: Event) => {
  const input = event.target as HTMLInputElement
  if (input.files && input.files[0]) {
    const file = input.files[0]
    if (!beforeAvatarUpload(file)) { input.value = ''; return }
    const formData = new FormData(); formData.append('file', file)
    const loadingMsg = ElMessage.loading({ message: '照片上传中...', duration: 0 })
    try {
      const res: any = await uploadFile(formData)
      if (res.code === 200) {
        const newUrl = res.data.url; const field = currentCameraField.value
        form[field].push(newUrl)
        if (field === 'arrival_photo') arrivalFileList.value.push({ name: newUrl.split('/').pop(), url: getImageUrl(newUrl) })
        else reportFileList.value.push({ name: newUrl.split('/').pop(), url: getImageUrl(newUrl) })
        ElMessage.success('拍照上传成功')
      } else { ElMessage.error(res.msg || '上传失败') }
    } catch (e) { ElMessage.error('网络错误，上传失败') } finally { loadingMsg.close(); input.value = '' }
  }
}
const handleDelete = async (row: any) => { try { await deleteBuyInbound(row.id); ElMessage.success('删除成功'); fetchData() } catch (e) { ElMessage.error('删除失败') } }
const handlePrint = async (row: any) => {
  printVisible.value = true; printLoading.value = true; previewUrl.value = ''
  currentPrintData.value = { global_print_id: row.global_print_id, material_name: row.material_name, spec_model: row.spec_model, category: row.category, material_type: row.material_type, warehouse_loc: row.warehouse_loc, serial_number: row.serial_number, batch_number: row.batch_number, sku: row.sku }
  try { const res: any = await getLabelPreview(currentPrintData.value); previewUrl.value = res.data }
  catch (e) { ElMessage.error('预览失败') } finally { printLoading.value = false }
}
const confirmPrint = async () => { printing.value = true; try { await executePrint(currentPrintData.value); ElMessage.success('指令已发送'); printVisible.value = false } catch (e: any) { ElMessage.error(e.msg || '打印失败') } finally { printing.value = false } }
const resetForm = () => {
  materialOptions.value = []; arrivalFileList.value = []; reportFileList.value = []; inspection_report_url.value = ''
  Object.assign(form, { id: undefined, base_id: undefined, material_name: '', spec_model: '', category: '', unit: '', material_type: '', sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', inspection_status: '未检', in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '', unit_price: 0, total_price: 0, currency: 'CNY', exchange_rate: 1.00, supplier_name: '', purchaser: '', purchaser_email: '', source_link: '', detail_link: '', arrival_photo: [], inspection_report: [] })
}
const getStatusType = (status: string) => { const map: any = {'在库': 'success', '出库': 'info', '损耗': 'danger'}; return map[status] || 'warning' }
const formatMoney = (val: any, currency = '¥') => { const num = Number(val); return isNaN(num) ? '-' : `${currency} ${num.toFixed(2)}` }

onMounted(() => fetchData())
</script>

<style scoped>
/* 样式部分保持不变，直接复用原有代码 */
.buy-module { background: #f5f7fa; padding: 20px; min-height: 100vh; }
.header-tools { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; background: #fff; padding: 15px 20px; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); }
.left-tools { display: flex; gap: 10px; align-items: center; flex: 1; }
.right-tools { display: flex; gap: 10px; align-items: center; }
.action-btn { font-weight: 500; }
.modern-table { border-radius: 8px; overflow: hidden; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); }
:deep(.table-header-gray th) { background-color: #f8f9fb !important; color: #606266; font-weight: 600; height: 50px; }
.tag-sn { color: #409EFF; font-weight: bold; font-family: monospace; background: #ecf5ff; padding: 0 4px; border-radius: 4px; margin-right: 4px; font-size: 12px; }
.tag-bn { color: #67C23A; font-weight: bold; font-family: monospace; background: #f0f9eb; padding: 0 4px; border-radius: 4px; margin-right: 4px; font-size: 12px; }
.id-cell { display: flex; align-items: center; }
.id-text { font-family: monospace; color: #606266; }
.money-text { font-family: 'Consolas', monospace; color: #303133; }
.stock-num { font-weight: bold; color: #333; font-size: 15px; }
.avail-num { font-weight: bold; color: #67C23A; font-size: 15px; }
.sum-tag { margin-left: 4px; transform: scale(0.9); }
:deep(.el-dialog__body) { padding: 0; overflow: hidden; }
.dialog-scroll-container { padding: 15px 20px; max-height: 70vh; overflow-y: auto; overflow-x: hidden; }
.stylish-form .form-card { background: #fff; border-radius: 8px; border: 1px solid #e4e7ed; margin-bottom: 15px; overflow: hidden; }
.card-title { background: #fcfcfc; padding: 10px 20px; border-bottom: 1px solid #ebeef5; font-weight: 600; font-size: 14px; color: #303133; display: flex; align-items: center; }
.card-title .icon { margin-right: 8px; font-size: 18px; color: #409EFF; }
.card-title .sub-title { font-size: 12px; color: #909399; font-weight: normal; margin-left: 10px; }
.card-content { padding: 15px 20px; }
.basic-card { border-left: 4px solid #409EFF; }
.search-tip { color: #909399; font-size: 12px; margin-left: 10px; display: flex; align-items: center; gap: 4px; }
.is-text-view :deep(.el-input__wrapper) { box-shadow: none !important; background-color: #f5f7fa; border-bottom: 1px solid #dcdfe6; border-radius: 0; padding-left: 0; }
.is-text-view :deep(.el-input__inner) { color: #606266; font-weight: 500; font-size: 13px; }
.inbound-card { border-left: 4px solid #67C23A; }
.identity-panel { background: #fffbf0; border: 1px dashed #e6a23c; border-radius: 6px; padding: 12px; margin-bottom: 15px; }
.custom-radio-group { margin-bottom: 10px; }
.locked-msg { font-size: 12px; color: #e6a23c; margin-left: 15px; }
.prefix-tag { font-weight: bold; font-size: 12px; padding: 0 5px; border-radius: 4px; }
.prefix-tag.bn { color: #67C23A; background: #f0f9eb; }
.prefix-tag.sn { color: #409EFF; background: #ecf5ff; }
.divider-text { display: flex; align-items: center; text-align: center; margin: 20px 0 15px; color: #909399; font-size: 13px; font-weight: 500; }
.divider-text::before, .divider-text::after { content: ''; flex: 1; border-bottom: 1px solid #ebeef5; }
.divider-text::before { margin-right: 15px; }
.divider-text::after { margin-left: 15px; }
.dialog-footer { display: flex; justify-content: flex-end; gap: 15px; padding: 15px 20px; background: #fff; border-top: 1px solid #ebeef5; }
.option-item { display: flex; justify-content: space-between; width: 100%; align-items: center; }
.opt-name { font-weight: bold; }
.opt-spec { color: #8492a6; font-size: 13px; margin-right: 10px; }
.total-price-input :deep(.el-input__inner) { color: #F56C6C; font-weight: bold; }
.preview-box { min-height: 150px; display: flex; justify-content: center; align-items: center; background: #f5f7fa; border-radius: 4px; }
.empty-preview { color: #909399; }
.more-images-badge { margin-left: 5px; background: #909399; color: #fff; border-radius: 10px; padding: 0 6px; font-size: 12px; }
.clickable-text { color: #409EFF; cursor: pointer; font-weight: 500; text-decoration: underline; }
.clickable-text:hover { color: #66b1ff; }
.upload-container { display: flex; flex-wrap: wrap; gap: 8px; }
:deep(.el-upload--picture-card) { width: 100px; height: 100px; line-height: 100px; }
:deep(.el-upload-list--picture-card .el-upload-list__item) { width: 100px; height: 100px; }
.camera-card { width: 100px; height: 100px; background-color: #fbfdff; border: 1px dashed #c0ccda; border-radius: 6px; box-sizing: border-box; display: flex; flex-direction: column; justify-content: center; align-items: center; cursor: pointer; transition: all 0.3s; color: #8c939d; }
.camera-card:hover { border-color: #409EFF; color: #409EFF; }
.camera-card .text { font-size: 12px; margin-top: 5px; }
.camera-card .el-icon { font-size: 24px; }
</style>