<template>
  <div class="app-container allocation-page">
    <!-- 上半区：固定最高 400 -->
    <div class="section section-top">
      <el-row :gutter="16" class="section-row">
        <el-col :span="8" class="section-col">
          <el-card class="section-card">
            <div class="card-body">
              <el-tabs v-model="activeTab" type="border-card" class="fill-tabs">
                <el-tab-pane label="手工分配" name="manual">
                  <div class="tab-pane-body">
                    <el-form :model="manualQuery" size="small" label-width="88px" class="manual-query-form">
                      <el-row :gutter="12">
                        <el-col :span="12">
                          <el-form-item label="生产日期" prop="productionDate">
                            <el-date-picker
                              v-model="manualQuery.productionDate"
                              type="date"
                              value-format="yyyy-MM-dd"
                              placeholder="请选择生产日期"
                              style="width: 100%;"
                            />
                          </el-form-item>
                        </el-col>
                        <el-col :span="12">
                          <el-form-item label="发货日期" prop="shipDate">
                            <el-date-picker
                              v-model="manualQuery.shipDate"
                              type="date"
                              value-format="yyyy-MM-dd"
                              placeholder="请选择发货日期"
                              style="width: 100%;"
                            />
                          </el-form-item>
                        </el-col>
                      </el-row>

                      <el-row :gutter="12">
                        <el-col :span="12">
                          <el-form-item label="品种" prop="variety">
                            <el-select v-model="manualQuery.variety" placeholder="请选择品种" clearable filterable style="width: 100%;">
                              <el-option v-for="item in varietyList" :key="item.varietyNo" :value="item.varietyNo" :label="item.varietyName" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                        <el-col :span="12">
                          <el-form-item label="级别" prop="level">
                            <el-select v-model="manualQuery.level" placeholder="请选择级别" clearable filterable style="width: 100%;">
                              <el-option v-for="item in levelList" :key="item.levelNo" :value="item.levelNo" :label="item.levelName" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                      </el-row>

                      <el-row :gutter="12">
                        <el-col :span="12">
                          <el-form-item label="动物标识" prop="animalTag">
                            <el-input v-model="manualQuery.animalTag" placeholder="请输入动物标识" clearable />
                          </el-form-item>
                        </el-col>
                        <el-col :span="12">
                          <el-form-item label="批次" prop="batch">
                            <el-input v-model="manualQuery.batch" placeholder="请输入批次" clearable />
                          </el-form-item>
                        </el-col>
                      </el-row>

                      <el-row :gutter="12">
                        <el-col :span="12">
                          <el-form-item label="白条编号" prop="whiteNo">
                            <el-input v-model="manualQuery.whiteNo" placeholder="请输入白条编号" clearable />
                          </el-form-item>
                        </el-col>
                        <el-col :offset="2" :span="6">
                          <el-form-item  label-width="0" prop="enableSort">
                            <el-checkbox v-model="manualQuery.enableSort">启用排序</el-checkbox>
                          </el-form-item>
                        </el-col>
                        <el-col :span="4" >
                          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleManualQuery">查询</el-button>
                        </el-col>
                      </el-row>

                    </el-form>
                  </div>
                </el-tab-pane>
                <el-tab-pane label="白条排序设定" name="sort">
                  <div class="tab-pane-body">
                    <el-form :model="sortForm" size="small" label-width="88px" class="sort-form">
                      <el-row :gutter="12">
                        <el-col :span="24">
                          <el-form-item label="排序1" prop="sort1">
                            <el-select v-model="sortForm.sort1" placeholder="请选择" style="width: 100%;">
                              <el-option v-for="opt in sortOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                        <el-col :span="24">
                          <el-form-item label="排序2" prop="sort2">
                            <el-select v-model="sortForm.sort2" placeholder="请选择" style="width: 100%;">
                              <el-option v-for="opt in sortOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                        <el-col :span="24">
                          <el-form-item label="排序3" prop="sort3">
                            <el-select v-model="sortForm.sort3" placeholder="请选择" style="width: 100%;">
                              <el-option v-for="opt in sortOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                        <el-col :span="24">
                          <el-form-item label="排序4" prop="sort4">
                            <el-select v-model="sortForm.sort4" placeholder="请选择" style="width: 100%;">
                              <el-option v-for="opt in sortOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                        <el-col :span="24">
                          <el-form-item label="排序5" prop="sort5">
                            <el-select v-model="sortForm.sort5" placeholder="请选择" style="width: 100%;">
                              <el-option v-for="opt in sortOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
                            </el-select>
                          </el-form-item>
                        </el-col>
                      </el-row>
                    </el-form>
                  </div>
                </el-tab-pane>
              </el-tabs>
            </div>
          </el-card>
        </el-col>
        <el-col :span="16" class="section-col">
          <el-card class="section-card">
            <div class="card-body">
              <div class="card-toolbar">
                <el-button type="primary" plain icon="el-icon-refresh" size="mini" @click="refreshTopRight">刷新</el-button>
              </div>
              <el-table
                border
                stripe
                height="calc(100% - 40px)"
                :data="topRightList"
                @selection-change="handleTopRightSelectionChange"
              >
                <el-table-column label="品种" prop="varietyName" min-width="140" />
                <el-table-column label="级别" prop="grade" min-width="120" >
                  <template slot-scope="scope">
                    <span>{{ getLevelLabel(scope.row.grade) }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="订单未分配片数" prop="orderUnAllocNum" min-width="150" />
                <el-table-column label="可分配片数" prop="availAllocNum" min-width="130" />
              </el-table>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>

    <!-- 下半区：占用剩余高度（可分配高度 - 400） -->
    <div class="section section-bottom">
      <el-row :gutter="16" class="section-row">
        <el-col :span="8" class="section-col">
          <el-card class="section-card">
            <div class="card-body">
              <div class="card-title">可分配白条明细</div>
              <el-table
                ref="bottomLeftTable"
                class="bottom-left-table"
                border
                stripe
                highlight-current-row
                height="calc(100% - 36px)"
                :data="bottomLeftList"
                @row-click="handleBottomLeftRowClick"
                @selection-change="handleBottomLeftSelectionChange"
                style="width: 100%;"
              >
                <el-table-column label="白条编号" prop="whiteStripNumber" min-width="140" />
                <el-table-column label="品种" prop="varietyName" min-width="100" >
                  <template slot-scope="scope">
                    <span>{{ getVarietyLabel(scope.row.variety) }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="级别" prop="grade" min-width="90" >
                  <template slot-scope="scope">
                    <span>{{ getLevelLabel(scope.row.grade) }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="重量" prop="currentWeightKg" min-width="90" />
                <el-table-column label="锁定物流线" prop="lockedLogisticsLine" min-width="120" />
                <el-table-column label="扣分" prop="qualityDeduction" min-width="80" />
                <el-table-column label="动物标识" prop="animalIdentification" min-width="120" />
                <el-table-column label="物料名称" prop="goodsName" min-width="140" >
                  <template slot-scope="scope">
                    <span>{{ scope.row.goodsName || getGoodsNameByNum(scope.row.goodsNum) }}</span>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </el-card>
        </el-col>
        <el-col :span="16" class="section-col">
          <el-card class="section-card">
            <div class="card-body">
              <div class="card-toolbar">
                <el-button type="primary" plain icon="el-icon-refresh" size="mini" @click="refreshBottomRight">刷新</el-button>
              </div>
              <el-row :gutter="16" class="bottom-right-row">
                <el-col :span="6" class="bottom-right-col">
                  <el-card class="inner-card inner-card--order-tree" shadow="never">
                    <div class="inner-card-body inner-card-body--order-tree">
                      <el-tree
                        ref="allocationOrderTree"
                        :data="allocationOrderTreeData"
                        :props="allocationTreeProps"
                        node-key="id"
                        highlight-current
                        default-expand-all
                        :expand-on-click-node="false"
                        class="allocation-order-tree"
                        @node-click="handleAllocationTreeNodeClick"
                      >
                        <span slot-scope="{ data }" class="tree-node tree-node--any">
                          {{ getAllocationTreeNodeLabel(data) }}
                        </span>
                      </el-tree>
                    </div>
                  </el-card>
                </el-col>
                <el-col :span="18" class="bottom-right-col">
                  <el-card class="inner-card" shadow="never">
                    <div class="inner-card-body right-panel">
                      <!-- 1) 订单信息汇总 -->
                      <div class="panel-section panel-section-1">
                        <div class="card-title">订单信息汇总</div>
                        <el-table
                          ref="orderSummaryTable"
                          class="order-summary-table"
                          border
                          stripe
                          highlight-current-row
                          height="calc(100% - 28px)"
                          :data="orderSummaryList"
                          @row-click="handleOrderSummaryRowClick"
                          @selection-change="handleOrderSummarySelectionChange"
                          style="width: 100%;"
                        >
                          <el-table-column label="发货客户" prop="customer_name" min-width="140" />
                          <el-table-column label="白条数" prop="ass_num" min-width="90" />
                          <el-table-column label="订单未分配数量" prop="unalloc_num" min-width="140" />
                          <el-table-column label="品种" prop="variety_name" min-width="100" />
                          <el-table-column label="级别" prop="goods_level" min-width="90" >
                            <template slot-scope="scope">
                              <span>{{ getLevelLabel(scope.row.goods_level) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="动物标识" prop="animalTag" min-width="120" />
                          <el-table-column label="物料名称" prop="goods_name" min-width="140" />
                          <el-table-column label="备注" prop="remark" min-width="160" />
                        </el-table>
                      </div>

                      <!-- 2) 分配结果 -->
                      <div class="panel-section panel-section-2">
                        <div class="card-title">分配结果</div>
                        <el-table
                          ref="allocationResultTable"
                          class="allocation-result-table"
                          border
                          stripe
                          highlight-current-row
                          height="calc(100% - 28px)"
                          :data="allocationResultList"
                          @row-click="handleAllocationResultRowClick"
                          style="width: 100%;"
                        >
                          <!-- 以下 prop 与后端 list 返回字段一致；若字段名不同请只改 prop -->
                          <el-table-column label="市场" prop="market" min-width="120" show-overflow-tooltip >
                            <template slot-scope="scope">
                              <span>{{ getBazaarLabel(scope.row.market) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="客户" prop="customerName" min-width="140" show-overflow-tooltip >
                            <template slot-scope="scope">
                              <span>{{getCustomerLabel(scope.row.customer) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="白条编号" prop="whiteStripNumber" min-width="140" show-overflow-tooltip />
                          <el-table-column label="品种" prop="variety" min-width="100" show-overflow-tooltip >
                            <template slot-scope="scope">
                              <span>{{ getVarietyLabel(scope.row.variety) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="级别" prop="grade" min-width="90" show-overflow-tooltip >
                            <template slot-scope="scope">
                              <span>{{ getLevelLabel(scope.row.grade) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="毛色" prop="coatColor" min-width="90" show-overflow-tooltip >
                            <template slot-scope="scope">
                              <span>{{ getCoatLabel(scope.row.coatColor) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="重量" prop="weight" min-width="90" />
                          <el-table-column label="扣分" prop="deductionScore" min-width="80" />
                          <el-table-column label="完成分配" prop="completionStatus" min-width="100" >
                            <template slot-scope="scope">
                              <span>{{ scope.row.completionStatus === 1 ? 'Y' : 'N' }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="生猪批次" prop="pigBatch" min-width="120" />
                          <el-table-column label="物料名称" prop="materialName" min-width="140" show-overflow-tooltip >
                            <template slot-scope="scope">
                              <span>{{ getGoodsNameByNum(scope.row.materialCode) }}</span>
                            </template>
                          </el-table-column>
                          <el-table-column label="物料编码" prop="materialCode" min-width="120" show-overflow-tooltip />
                        </el-table>
                      </div>

                      <!-- 3) 按钮组 -->
                      <div class="panel-section panel-section-3">
                        <div class="btn-group">
                          <el-button size="mini" type="primary" plain :disabled="allocationLocked" @click="handleLock">锁定</el-button>
                          <el-button size="mini" type="warning" plain :disabled="!allocationLocked" @click="handleUnlock">解锁</el-button>
                          <el-button size="mini" type="success" plain @click="handleFinishAlloc">完成分配</el-button>
                          <el-button size="mini" type="primary" plain @click="handleLockLine">锁定物流线</el-button>
                          <el-button size="mini" type="info" plain @click="handlePrintCert">合格证打印</el-button>
                        </div>
                      </div>
                    </div>
                  </el-card>
                </el-col>
              </el-row>
            </div>
          </el-card>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<script>
import { getVarietyList } from "@/api/baseInfo/variety";
import { getLevelList } from "@/api/baseInfo/level";
import { formatDateYMS, getFindByKey } from "@/utils";
import { getAllocationWhiteList } from "@/api/production/convention";
import { getMaterialList } from "@/api/baseInfo/material";
import { getLineMarketCustomerStats, getSaleOrderGoodsDetailList } from "@/api/sale/saleOrder";
import { addAllocation, editAllocationStatus, delAllocation, getAllocationList } from "@/api/production/allocation";
import { getClienteleList } from "@/api/sale/clientele";
import { getCoatList } from "@/api/baseInfo/coat";
import { getBazaarList } from "@/api/baseInfo/bazaar";
import { getUnallocNum } from "@/api/sale/saleOrder";

export default {
  name: "ProductionAllocation",
  data() {
    return {
      activeTab: "manual",
      varietyList: [],
      levelList: [],
      coatList: [],
      bazaarList: [],
      customerList: [],
      topRightList: [
      ],
      topRightSelection: [],
      bottomLeftList: [
      
      ],
      bottomLeftSelection: [],
      orderSummaryList: [
       
      ],
      orderSummarySelection: [],
      /** 分配结果：全量列表（切换订单汇总时做过滤展示） */
      allocationResultAllList: [],
      /** 分配结果：展示列表（由 allocationResultAllList 过滤得到） */
      allocationResultList: [],
      /** 分配结果行自增 id（用于从展示列表定位回全量列表） */
      allocationResultSeq: 0,
      /** 当前选中的订单汇总行 key（用于过滤分配结果） */
      selectedOrderSummaryKey: null,
      /** 当前选中的订单信息汇总：整行数据对象（与表格高亮行一致，业务里直接用这一项即可） */
      selectedOrderSummaryRow: null,
      sortOptions: [
        { label: "无", value: "none" },
        { label: "品种", value: "variety" },
        { label: "重量", value: "weight" },
        { label: "级别", value: "level" },
        { label: "编号", value: "code" },
        { label: "毛色", value: "coat" },
      ],
      sortForm: {
        sort1: "none",
        sort2: "none",
        sort3: "none",
        sort4: "none",
        sort5: "none",
      },
      manualQuery: {
        productionDate: null,
        shipDate: null,
        variety: null,
        level: null,
        animalTag: null,
        batch: null,
        whiteNo: null,
        enableSort: false,
      },
      materialList: [],
      /** 右下左侧：与销售订单弹框同源，物流线 -> 市场 -> 客户（本页所有节点均可点击高亮） */
      allocationOrderTreeData: [],
      allocationTreeProps: {
        children: "children",
        label: "label",
      },
      /** 当前选中的树节点（后续可据 type 拉取订单汇总等） */
      selectedAllocationTreeNode: null,
      /**
       * 锁定后禁止左右键在白条明细与分配结果间移动；默认未锁定，此时「解锁」按钮不可用
       */
      allocationLocked: false,
      /**
       * 分配/取消分配接口提交中标记。
       * 用于防止键盘长按触发 keydown 连发，导致同一 url+data 在 1s 内重复提交被 request.js 拦截。
       */
      allocationSubmitting: false,

    };
  },
  created() {
    const tomorrow = formatDateYMS(Date.now() + 1000 * 60 * 60 * 24);
    this.manualQuery.productionDate = tomorrow;
    this.manualQuery.shipDate = tomorrow;
    this.getVariety();
    this.getLevel();
    this.getCoat();
    this.getMaterial();
    this.getBazaar();
    this.getCustomer();
    this.fetchAllocationOrderTree();
  },
  mounted() {
    window.addEventListener("keydown", this.onAllocationKeydown, true);
  },
  beforeDestroy() {
    window.removeEventListener("keydown", this.onAllocationKeydown, true);
  },
  methods: {
    /**  topRightList 数据接口 */
    getTopRightList() {
      let params = {
        saleDate: this.manualQuery.productionDate,

      }
      getUnallocNum(params).then((res) => {
        this.topRightList = res.data || [];
      });
    },
    /**
     * 树节点显示文案：label + (goodsCount)
     * @param {Object} node 树节点
     * @returns {string}
     */
    getAllocationTreeNodeLabel(node) {
      const label = node && node.label != null ? String(node.label) : "-";
      const cnt = node && node.goodsCount != null && node.goodsCount !== "" ? Number(node.goodsCount) : null;
      if (cnt == null || Number.isNaN(cnt)) return label;
      return `${label} (${cnt})`;
    },
    getMaterial() {
      getMaterialList({}).then((res) => {
        this.materialList = res.data || [];
      });
    },
     /** 根据 goodsNum 反查物料名称（表格展示兜底用） */
      getGoodsNameByNum(goodsNum) {
        const key = goodsNum == null ? '' : String(goodsNum).trim()
        if (!key) return '-'
        const item = getFindByKey(this.materialList || [], key, 'goodsNum')
        return item ? (item.goodsName || '-') : '-'
      },
    getVariety() {
      getVarietyList({}).then((res) => {
        this.varietyList = res.data || [];
      });
    },
      /** 品种编码 -> 名称 */
    getVarietyLabel(val) {
      const item = getFindByKey(this.varietyList, val, 'varietyNo')
      return item ? item.varietyName : (val ?? '-')
    },
    getLevel() {
      getLevelList({}).then((res) => {
        this.levelList = res.data || [];
      });
    },
    /** 级别编码 -> 名称 */
    getLevelLabel(val) {
      const item = getFindByKey(this.levelList, val, 'levelNo')
      return item ? item.levelName : (val ?? '-')
    },
    getCoat() {
      getCoatList({}).then((res) => {
        this.coatList = res.data || [];
      });
    },
    getCoatLabel(val) {
      const item = getFindByKey(this.coatList, val, 'coatNum')
      return item ? item.coatName : (val ?? '-')
    },
    getBazaar() {
      getBazaarList({}).then((res) => {
        this.bazaarList = res.data || [];
      });
    },
    getBazaarLabel(val) {
      const item = getFindByKey(this.bazaarList, val, 'marketNum')
      return item ? item.marketName : (val ?? '-')
    },
    getCustomer() {
      getClienteleList({}).then((res) => {
        this.customerList = res.data || [];
      });
    },
    getCustomerLabel(val) {
      const item = getFindByKey(this.customerList, val, 'customerNum')
      return item ? item.customerName : (val ?? '-')
    },
   
    /**
     * 可分配白条明细：查询（与「查询」按钮同源）
     * @returns {Promise<void>} 便于 add/del 分配后链式刷新左侧列表
     */
    handleManualQuery() {
      const params = {
        productionDate: this.manualQuery.productionDate,
        shipDate: this.manualQuery.shipDate,
        variety: this.manualQuery.variety,
        level: this.manualQuery.level,
        animalTag: this.manualQuery.animalTag,
        batch: this.manualQuery.batch,
        whiteNo: this.manualQuery.whiteNo,
        enableSort: this.manualQuery.enableSort,
      };
      getAllocationWhiteList(params).then((res) => {
        this.bottomLeftList = res.data || [];
      });
      this.getTopRightList();
    },
    refreshTopRight() {
      /** 刷新右上区域数据（当前页面未实现：避免无意义日志） */
    },
    handleTopRightSelectionChange(val) {
      this.topRightSelection = val || [];
    },
    /**
     * 可分配白条明细：鼠标左键点行（仅选中高亮）
     * 分配/取消分配后左侧数据由 {@link handleManualQuery} 统一刷新，此处不必改 bottomLeftList
     */
    handleBottomLeftRowClick(row) {
      if (this.$refs.bottomLeftTable) {
        this.$refs.bottomLeftTable.setCurrentRow(row);
      }
    },
    handleBottomLeftSelectionChange(val) {
      this.bottomLeftSelection = val || [];
    },
    /**
     * 订单信息汇总：鼠标左键点行（高亮 + 更新 selectedOrderSummaryRow + 过滤分配结果）
     * 若需「切换行时再拉一次接口」，在此方法内追加（或在此调用 fetchOrderSummaryList 的变体）
     */
    handleOrderSummaryRowClick(row) {
      if (this.$refs.orderSummaryTable) {
        this.$refs.orderSummaryTable.setCurrentRow(row);
      }
      /** 当前选中的整行（你要的「那一条数据」） */
      this.selectedOrderSummaryRow = row || null;
      /** 切换订单汇总当前行时，分配结果跟着切换 */
      this.selectedOrderSummaryKey = row && row._osKey != null ? row._osKey : null;
      this.syncAllocationResultList();
      this.fetchAllocationResultAllList();
    },
    handleOrderSummarySelectionChange(val) {
      this.orderSummarySelection = val || [];

    },
    /**
     * 分配结果：鼠标左键点行（仅选中高亮）
     * 若需「点击行即取消分配/调 delAllocation」，在此方法内写接口；与键盘 ← 可共用 {@link moveWhiteStripFromAllocationResult}
     */
    handleAllocationResultRowClick(row) {
      if (this.$refs.allocationResultTable) {
        this.$refs.allocationResultTable.setCurrentRow(row);
      }
    },
    /**
     * 读取 Element 表格当前高亮行
     * @param {string} refName 表格 ref 名
     * @returns {Object|null}
     */
    getTableCurrentRow(refName) {
      const t = this.$refs[refName];
      if (!t || !t.store || !t.store.states) return null;
      return t.store.states.currentRow;
    },
    /**
     * 获取当前选中的「订单信息汇总」整行数据
     * @returns {Object|null}
     */
    getSelectedOrderSummaryRow() {
      return this.selectedOrderSummaryRow || this.getTableCurrentRow("orderSummaryTable");
    },
    /**
     * 根据当前高亮或缓存定位订单汇总在 orderSummaryList 中的下标（避免 currentRow 与数组项引用不一致导致 indexOf 失败）
     * @param {Object} osRow 订单汇总行
     * @returns {number}
     */
    findOrderSummaryIndex(osRow) {
      if (!osRow || !this.orderSummaryList || !this.orderSummaryList.length) return -1;
      let idx = this.orderSummaryList.indexOf(osRow);
      if (idx >= 0) return idx;
      if (osRow._osKey != null) {
        idx = this.orderSummaryList.findIndex((r) => r && r._osKey === osRow._osKey);
        if (idx >= 0) return idx;
      }
      if (osRow.id != null) {
        idx = this.orderSummaryList.findIndex((r) => r && r.id === osRow.id);
        if (idx >= 0) return idx;
      }
      return -1;
    },
    /**
     * 根据当前选中的订单汇总行过滤分配结果展示
     * - 未选中订单汇总行：默认展示全部
     */
    syncAllocationResultList() {
      if (this.selectedOrderSummaryKey == null || this.selectedOrderSummaryKey === "") {
        this.allocationResultList = (this.allocationResultAllList || []).slice();
        return;
      }
      this.allocationResultList = (this.allocationResultAllList || []).filter(
        (r) => r && r._osKey === this.selectedOrderSummaryKey
      );
      this.$nextTick(() => {
        if (this.$refs.allocationResultTable) {
          this.$refs.allocationResultTable.setCurrentRow(this.allocationResultList[0] || null);
        }
      });
    },
    /**
     * 键盘左右键：未锁定时，右键将选中白条 + 选中订单行移入分配结果；左键从分配结果移回白条明细
     * @param {KeyboardEvent} e
     */
    onAllocationKeydown(e) {
      if (this.allocationLocked) return;
      if (e.key !== "ArrowRight" && e.key !== "ArrowLeft") return;
      const tag = (e.target && e.target.tagName) || "";
      if (["INPUT", "TEXTAREA", "SELECT"].includes(tag)) return;
      if (e.key === "ArrowRight") {
        const ok = this.moveWhiteStripToAllocationResult();
        if (ok) e.preventDefault();
        return;
      }
      if (e.key === "ArrowLeft") {
        const ok = this.moveWhiteStripFromAllocationResult();
        if (ok) e.preventDefault();
      }
    },
    /**
     * 右键：白条 + 订单汇总有当前行时调 addAllocation；成功后用 handleManualQuery 刷新可分配白条、fetchAllocationResultAllList 刷新分配结果（不再本地 splice 左侧表）
     * 键盘 **→** 由 {@link onAllocationKeydown} 调用。
     * @returns {boolean} 校验通过并已发起请求时为 true（用于 preventDefault）
     */
    moveWhiteStripToAllocationResult() {
      if (this.allocationSubmitting) return false;
      const blRow = this.getTableCurrentRow("bottomLeftTable");
      const osRow = this.getTableCurrentRow("orderSummaryTable");
      if (!blRow || !osRow) {
        this.$message.warning('请先在「可分配白条明细」与「订单信息汇总」中各选中一行');
        return false;
      }
      const qty = Number(osRow.unalloc_num);
      if (Number.isNaN(qty) || qty <= 0) {
        this.$message.warning("该订单行未分配数量已为 0，无法继续分配");
        return false;
      }
      const orderIdx = this.findOrderSummaryIndex(osRow);
      if (orderIdx < 0) {
        this.$message.warning("未在订单汇总列表中定位到当前行，请重新点击订单信息汇总");
        return false;
      }
      /** 刷新列表后用于恢复高亮：分配成功后该行从接口消失，原下一条会顶到该索引 */
      const blIdx = this.bottomLeftList.indexOf(blRow);
      const payload = {
        productionDate: this.manualQuery.productionDate,
        deliveryDate: this.manualQuery.shipDate,
        regularId: blRow.id,
        variety: blRow.variety,
        grade: blRow.grade,
        animalIdentification: blRow.animalIdentification,
        batchNumber: blRow.batch,
        whiteStripNumber: blRow.whiteStripNumber,
        weight: blRow.currentWeightKg,
        deductionScore: blRow.qualityDeduction,
        materialCode: blRow.goodsNum,
        pigBatch: blRow.pigBatch,
        coatColor: blRow.coatColor,
        deliveryCustomer: osRow.customer_num,
        lockedLogisticsLine: osRow.line_num,
        market: osRow.market_num,
        customer: osRow.customer_num,
        saleNum: osRow.order_num,
        saleId: osRow.id,
      };
      this.allocationSubmitting = true;
      addAllocation(payload)
        .then((res) => {
          if (res.code !== 200) {
            this.$message.error(res.msg || "分配失败");
            return Promise.reject(new Error("BIZ_FAIL"));
          }
          this.$message.success("分配成功");
          this.selectedOrderSummaryKey =
            osRow && osRow._osKey != null ? osRow._osKey : this.selectedOrderSummaryKey;
          /** 与列表项对齐引用，避免只更新了「孤儿对象」界面不变 */
          this.selectedOrderSummaryRow = this.orderSummaryList[orderIdx] || osRow;
          const listParams = this.buildAllocationListQueryParams();
          /** 分配结果列表 + 可分配白条明细均走接口刷新，不维护本地 splice */
          return Promise.all([
            this.fetchOrderSummaryList(listParams),
            this.handleManualQuery(),
            this.getTopRightList()
          ]);
        })
        .then(() => {
          /** 接口整表替换后 currentRow 会丢，按原索引顺延选中下一条（或末条） */
          let nextBlRow = null;
          if (this.bottomLeftList.length > 0 && blIdx >= 0) {
            if (blIdx < this.bottomLeftList.length) {
              nextBlRow = this.bottomLeftList[blIdx];
            } else {
              nextBlRow = this.bottomLeftList[this.bottomLeftList.length - 1];
            }
          } else if (this.bottomLeftList.length > 0) {
            nextBlRow = this.bottomLeftList[0];
          }
          this.$nextTick(() => {
            this.$nextTick(() => {
              if (this.$refs.bottomLeftTable) {
                this.$refs.bottomLeftTable.setCurrentRow(nextBlRow);
              }
              if (this.$refs.allocationResultTable) {
                this.$refs.allocationResultTable.setCurrentRow(this.allocationResultList[0] || null);
              }
              /** 保持订单汇总当前行与数据源一致，未分配数量才能立即反映 */
              const osIdx = this.findOrderSummaryIndex(osRow);
              if (this.$refs.orderSummaryTable && osIdx >= 0) {
                this.$refs.orderSummaryTable.setCurrentRow(this.orderSummaryList[osIdx]);
              }
            });
          });
        })
        .catch((err) => {
          if (!err || err.message !== "BIZ_FAIL") {
            this.$message.error("分配失败");
          }
        })
        .finally(() => {
          this.allocationSubmitting = false;
        });
      return true;
    },
    /**
     * 键盘 ←：delAllocation 成功后 handleManualQuery 刷新可分配白条、fetchAllocationResultAllList 刷新分配结果（不再 push 左侧表）
     * @returns {boolean} 校验通过并已发起请求时为 true（用于 preventDefault）
     */
    moveWhiteStripFromAllocationResult() {
      if (this.allocationSubmitting) return false;
      const arRow = this.getTableCurrentRow("allocationResultTable");
      if (!arRow) {
        this.$message.warning("请先在「分配结果」中选中一行");
        return false;
      }
      if(arRow.completionStatus === 1){
        this.$message.warning("该白条已分配完成，无法取消分配");
        return false;
      }
      const idxAll = (this.allocationResultAllList || []).findIndex(
        (r) => r && arRow && r._allocId === arRow._allocId
      );
      if (idxAll < 0) return false;
      const addQty = arRow._allocQty != null ? Number(arRow._allocQty) : 1;
      const allocId = arRow._allocId;
      /** 无后端主键：仅本地移出分配结果，再 handleManualQuery 同步白条列表 */
      if (allocId == null || String(allocId).indexOf("tmp-") === 0) {
        this.allocationResultAllList.splice(idxAll, 1);
        this.syncAllocationResultList();
        this.handleManualQuery().then(() => {
          this.$nextTick(() => {
            if (this.$refs.allocationResultTable) {
              this.$refs.allocationResultTable.setCurrentRow(this.allocationResultList[0] || null);
            }
            const osIdx = this.findOrderSummaryIndex(arRow);
            if (this.$refs.orderSummaryTable && osIdx >= 0) {
              this.$refs.orderSummaryTable.setCurrentRow(this.orderSummaryList[osIdx]);
            }
          });
        });
        return true;
      }
      const delPayload = { ids: allocId };
      this.allocationSubmitting = true;
      delAllocation(delPayload)
        .then((res) => {
          if (res.code !== 200) {
            this.$message.error(res.msg || "取消分配失败");
            return Promise.reject(new Error("BIZ_FAIL"));
          }
          this.$message.success("已取消分配");
          const listParams = this.buildAllocationListQueryParams();
          return Promise.all([
            this.fetchOrderSummaryList(listParams),
            this.handleManualQuery(),
            this.getTopRightList()
          ]);
        })
        .then(() => {
          const oIdx = this.findOrderSummaryIndex(arRow);
          this.$nextTick(() => {
            if (this.$refs.allocationResultTable) {
              this.$refs.allocationResultTable.setCurrentRow(this.allocationResultList[0] || null);
            }
            if (this.$refs.orderSummaryTable && oIdx >= 0) {
              this.$refs.orderSummaryTable.setCurrentRow(this.orderSummaryList[oIdx]);
            }
          });
        })
        .catch((err) => {
          if (!err || err.message !== "BIZ_FAIL") {
            this.$message.error("取消分配失败");
          }
        })
        .finally(() => {
          this.allocationSubmitting = false;
        });
      return true;
    },
    /**
     * 前序遍历，取第一个带 id 的节点（与树自上而下展示顺序一致，便于默认选中第一项）
     * @param {Array} nodes 树节点列表
     * @returns {Object|null}
     */
    findFirstTreeNodeWithId(nodes) {
      if (!nodes || !nodes.length) return null;
      for (let i = 0; i < nodes.length; i++) {
        const n = nodes[i];
        if (!n) continue;
        if (n.id != null) return n;
        if (n.children && n.children.length) {
          const hit = this.findFirstTreeNodeWithId(n.children);
          if (hit) return hit;
        }
      }
      return null;
    },
    /**
     * 加载分配页左侧销售订单树
     * 加载完成后默认选中第一个可识别节点（与手动点击同一套逻辑）
     */
    fetchAllocationOrderTree() {
      let params = {
        saleDate: this.manualQuery.shipDate,
      }
      getLineMarketCustomerStats(params).then((res) => {
        this.allocationOrderTreeData = res.data || [];
        this.$nextTick(() => {
          const first = this.findFirstTreeNodeWithId(this.allocationOrderTreeData);
          if (first) {
            this.handleAllocationTreeNodeClick(first);
          }
        });
      });
    },
    /**
     * 树节点点击：任意节点可选中、蓝色高亮（与 saleOrder 仅客户可点不同）
     * @param {Object} data 节点数据，含 id、label、type、children 等
     */
    handleAllocationTreeNodeClick(data) {
      if (!data) return;
      this.selectedAllocationTreeNode = data;
      const params = {
        lineNum: data.type === 'line' ? data.lineNum : null,
        marketNum: data.type === 'market' ? data.marketNum : null,
        customerNum: data.type === 'customer' ? data.customerNum : null,
        saleDate: this.manualQuery.productionDate,
      }
      /** 根据树节点 + 日期条件拉取订单汇总；分配结果由 fetchOrderSummaryList 内部联动触发 */
      this.fetchOrderSummaryList(params);
      
      this.$nextTick(() => {
        if (this.$refs.allocationOrderTree && data.id != null) {
          this.$refs.allocationOrderTree.setCurrentKey(data.id);
        }
      });
    },
    refreshBottomRight() {
      this.fetchAllocationOrderTree();
      /** 刷新右下区（订单汇总、分配结果） */
      if (this.selectedAllocationTreeNode) {
        const data = this.selectedAllocationTreeNode;
        const params = {
          lineNum: data.type === 'line' ? data.lineNum : null,
          marketNum: data.type === 'market' ? data.marketNum : null,
          customerNum: data.type === 'customer' ? data.customerNum : null,
          saleDate: this.manualQuery.productionDate,
        }
        /** 分配结果由 fetchOrderSummaryList 内部联动触发 */
        this.fetchOrderSummaryList(params);
      }
    },
    /**
     * 查询订单信息汇总
     * @param {Object} params 查询参数（示例：lineNum/marketNum/customerNum + 日期区间）
     * @returns {Promise<void>}
     */
    fetchOrderSummaryList(params) {
      return getSaleOrderGoodsDetailList(params).then((res) => {
        const list = (res && res.data) || [];
        /**
         * 兼容后端字段命名差异：
         * - 页面展示/键盘逻辑使用 orderUnassignedQty
         * - 实际接口可能返回 unassignedQty / orderUnassigned / orderUnassignedQuantity 等
         */
        this.orderSummaryList = (list || []).map((r, i) => {
          const rawWhiteCount =
            r && r.ass_num != null ? r.ass_num : null;

          /** 订单汇总行唯一 key：优先用业务主键，其次用组合键，最后兜底 index */
          const osKey =
            r && r.id != null ? r.id : null;
          return {
            _osKey: osKey,
            ...r,
            whiteCount: rawWhiteCount != null ? Number(rawWhiteCount) : (r && r.whiteCount),
          };
        });

        /** 默认选中第一行，并联动分配结果展示 */
        const firstOs = this.orderSummaryList[0] || null;
        this.selectedOrderSummaryKey = firstOs ? firstOs._osKey : null;
        this.selectedOrderSummaryRow = firstOs;
        this.fetchAllocationResultAllList();
        this.syncAllocationResultList();

        this.$nextTick(() => {
          if (this.$refs.orderSummaryTable) {
            this.$refs.orderSummaryTable.setCurrentRow(firstOs);
          }
        });
      });
    
    },
    /**
     * 构建分配结果列表查询参数（与树节点、订单汇总查询维度一致，可被 extra 覆盖）
     * @param {Object} [extra] 额外参数
     * @returns {Object}
     */
    buildAllocationListQueryParams(extra = {}) {
      const node = this.selectedAllocationTreeNode;
      const base = {
        saleDate: this.manualQuery.productionDate,
        productionDate: this.manualQuery.productionDate,
        deliveryDate: this.manualQuery.shipDate,
      };
      if (node) {
        base.lineNum = node.type === "line" ? node.lineNum : null;
        base.marketNum = node.type === "market" ? node.marketNum : null;
        base.customerNum = node.type === "customer" ? node.customerNum : null;
      }
      return { ...base, ...extra };
    },
    /**
     * 在 getAllocationList 返回行上仅追加页面用内部字段（删除、按订单行过滤等），保留接口字段原样
     * @param {Object} r 接口原始行
     * @param {number} index 下标，用于兜底 _allocId / _osKey
     * @returns {Object}
     */
    attachAllocationRowMeta(r, index) {
      const saleNum = r.saleNum != null ? r.saleNum : r.sale_num;
      const osIdx = (this.orderSummaryList || []).findIndex(
        (o) =>
          o &&
          (o.order_num === saleNum ||
            o.orderNum === saleNum ||
            String(o.order_num) === String(saleNum) ||
            String(o.orderNum) === String(saleNum))
      );
      const osRow = osIdx >= 0 ? this.orderSummaryList[osIdx] : null;
      const osKey =
        (osRow && osRow._osKey != null ? osRow._osKey : null) ||
        (r.osKey != null ? r.osKey : null) ||
        (r.orderLineId != null ? r.orderLineId : null) ||
        `alloc-${index}`;
      const id = r.id != null ? r.id : r.allocationId;
      return {
        ...r,
        _allocId: id != null ? id : `tmp-${index}`,
        _osKey: osKey,
        _orderSummaryIndex: osIdx >= 0 ? osIdx : null,
        _allocQty: 1,
      };
    },
    /**
     * 查询分配结果（全量）：getAllocationList → allocationResultAllList → syncAllocationResultList → allocationResultList
     * @param {Object} [params] 查询参数；不传则 {@link buildAllocationListQueryParams}
     * @returns {Promise<void>}
     */
    fetchAllocationResultAllList() {
      let row = this.selectedOrderSummaryRow
      if(!row) return;
      let p = {
        saleId: row.id,
      }
      return getAllocationList(p).then((res) => {
        let list = [];
        if (Array.isArray(res && res.data)) {
          list = res.data;
        }
        this.allocationResultAllList = (list || []).map((apiRow, i) =>
          this.attachAllocationRowMeta(apiRow, i)
        );
        const maxId = (this.allocationResultAllList || []).reduce((m, r) => {
          const v = Number(r && r._allocId);
          return Math.max(m, Number.isNaN(v) ? 0 : v);
        }, 0);
        if (maxId > this.allocationResultSeq) this.allocationResultSeq = maxId;
        this.syncAllocationResultList();
      });
    },
    /** 锁定：禁止左右键在白条与分配结果间移动；「解锁」可点 */
    handleLock() {
      this.allocationLocked = true;
    },
    /** 解锁：恢复左右键；未锁定时「解锁」按钮禁用 */
    handleUnlock() {
      this.allocationLocked = false;
    },
    handleFinishAlloc() {
      if (this.allocationResultList.length <= 0) {
        this.$message.warning("没有可分配的白条");
        return;
      }
      this.$modal.confirm("确定要完成分配吗？").then(() => {
        const params = {
          ids: this.allocationResultList
            .map((r) => r.id ?? r.allocationId)
            .filter((v) => v != null && v !== "")
            .join(","),
        };
        editAllocationStatus(params)
          .then((res) => {
            this.$message.success("完成分配成功");
            this.handleManualQuery();
            this.fetchAllocationResultAllList();
            this.getTopRightList();
          })
          .catch((err) => {});
      });
    },
    handleLockLine() {
    },
    handlePrintCert() {
    },
  },
};
</script>

<style scoped lang="scss">
.allocation-page {
  display: flex;
  flex-direction: column;
  /* 让上下两块能按视口高度分配（减去 app-container 上下 padding 20*2） */
  height: calc(100vh - 90px);
  min-height: 0;
  overflow: hidden; /* 避免页面出现整体滚动条 */
  gap: 16px;
}

.section {
  min-height: 0; /* 允许内部滚动/撑满 */
}

.section-top {
  height: 300px;
  max-height: 300px;
  flex: 0 0 300px;
}

.section-bottom {
  flex: 1 1 auto; /* 剩余高度 */
  min-height: 0;
}

.section-row,
.section-col,
.section-card {
  height: 100%;
}

.section-card ::v-deep .el-card__body {
  height: 100%;
}

.card-body {
  height: 100%;
  overflow: auto;
}

.fill-tabs {
  height: 100%;
}

.fill-tabs ::v-deep .el-tabs__content {
  height: calc(100% - 40px); /* 扣掉 tabs header */
  overflow: auto;
}

.tab-pane-body {
  min-height: 100%;
}

.manual-query-form {
  padding: 4px 0;
}

.sort-form {
  padding: 4px 0;
}

.card-toolbar {
  display: flex;
  justify-content: flex-start;
  margin-bottom: 8px;
}

.card-title {
  font-weight: 700;
  color: #606266;
  margin-bottom: 8px;
}

.card-title--compact {
  flex-shrink: 0;
  margin-bottom: 6px;
}

.bottom-right-row {
  height: calc(100% - 40px);
}

.bottom-right-col,
.inner-card {
  height: 100%;
}

.inner-card ::v-deep .el-card__body {
  height: 100%;
}

.inner-card-body {
  height: 100%;
  overflow: auto;
}

.right-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.panel-section {
  min-height: 0;
}

.panel-section-1 {
  flex: 0 0 38%;
}

.panel-section-2 {
  flex: 1 1 auto;
}

.panel-section-3 {
  flex: 0 0 auto;
}

.btn-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/** 可分配白条明细：当前点击行蓝色高亮（覆盖 Element 默认灰底） */
.bottom-left-table ::v-deep .el-table__body tr.current-row > td {
  background-color: #d9ecff !important;
}

/** 右下左侧订单树：卡片内纵向铺满，树区域滚动 */
.inner-card--order-tree ::v-deep .el-card__body {
  height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding: 10px 12px;
}

.inner-card-body--order-tree {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.allocation-order-tree {
  flex: 1;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
}

.allocation-order-tree ::v-deep .el-tree-node__content {
  height: 32px;
}

/** 任意节点可点 */
.tree-node--any {
  cursor: pointer;
}

/** 当前选中节点：浅蓝高亮（与 saleOrder 弹框树一致） */
.allocation-order-tree ::v-deep .el-tree-node.is-current > .el-tree-node__content {
  background-color: #d9ecff !important;
}

/** 订单信息汇总：当前行黄色高亮 */
.order-summary-table ::v-deep .el-table__body tr.current-row > td {
  background-color: #fff9c4 !important;
}

/** 分配结果：当前行浅绿，便于与左右键操作对应 */
.allocation-result-table ::v-deep .el-table__body tr.current-row > td {
  background-color: #e8f5e9 !important;
}
</style>
