<template>
  <div class="app-container sale-price-admin-page">
    <!-- 上：查询 -->
    <el-card class="top-card" shadow="never">
      <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="88px">
        <el-form-item label="执行日期" prop="executeDateRange">
          <el-date-picker
            v-model="queryParams.executeDateRange"
            type="daterange"
            value-format="yyyy-MM-dd"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            style="width: 320px;"
          />
        </el-form-item>
        <el-form-item>
          <!-- 按钮权限：sale:priceAdmin:query（若无该权限可移除） -->
          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
          <!-- 按钮权限：sale:priceAdmin:add -->
          <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['sale:priceAdmin:add']">新增</el-button>
          <!-- 按钮权限：sale:priceAdmin:remove -->
          <!-- <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDeleteAll" v-hasPermi="['sale:priceAdmin:remove']">删除</el-button> -->
        </el-form-item>
      </el-form>
    </el-card>

    <!-- 下：左右两部分 -->
    <el-row :gutter="12" class="bottom-row">
      <!-- 左：价格类型 -->
      <el-col :span="6" class="bottom-col">
        <el-card class="section-card" shadow="never">
          <div slot="header" class="card-header">
            <span>价格类型</span>
          </div>
          <el-table
            ref="priceTypeTable"
            border
            stripe
            height="100%"
            :data="priceTypeList"
            class="price-type-table"
            highlight-current-row
            @row-click="handlePriceTypeRowClick"
            @current-change="handlePriceTypeCurrentChange"
            style="width: 100%;"
          >
            <el-table-column label="序号" type="index" width="60" align="center" />
            <el-table-column label="价格类型" prop="priceTypeName" min-width="120" />
          </el-table>
        </el-card>
      </el-col>

      <!-- 右：价格列表 -->
      <el-col :span="18" class="bottom-col">
        <el-card class="section-card" shadow="never">
          <div slot="header" class="card-header">
            <span>价格列表</span>
          </div>
          <el-table
            ref="priceTable"
            border
            stripe
            height="100%"
            v-loading="loading"
            :data="priceList"
            @selection-change="handleSelectionChange"
            style="width: 100%;"
          >
            <el-table-column type="selection" width="55" align="center" fixed="left" />
            <el-table-column label="序号" type="index" width="60" align="center" />
            <el-table-column label="执行日期" prop="expireDate" min-width="120" />
            <el-table-column label="失效日期" prop="expireDate" min-width="120" />
            <el-table-column label="物料名称" prop="materialName" min-width="140" />
            <el-table-column label="规格" prop="materialSpec" min-width="120" />
            <el-table-column label="品种" prop="variety" min-width="100">
              <template slot-scope="scope">
                <span>{{ getPriceListVarietyLabel(scope.row) }}</span>
              </template>
            </el-table-column>
            <el-table-column label="级别" prop="level" min-width="90">
              <template slot-scope="scope">
                <span>{{ getPriceListLevelLabel(scope.row) }}</span>
              </template>
            </el-table-column>
            <el-table-column label="单价" prop="unitPrice" min-width="90" />
            <el-table-column label="单位" prop="unit" min-width="80" />
            <el-table-column label="自提价" prop="pickupPrice" min-width="90" />
            <el-table-column label="单位" prop="unit" min-width="80" />
            <el-table-column label="备注" prop="remark" min-width="160" />
          </el-table>
        </el-card>
      </el-col>
    </el-row>

    <!-- 新增弹框（全屏）：执行日期/失效日期/复制价格/备注 + 左右表格 -->
    <el-dialog :title="dialogTitle" :visible.sync="dialogOpen" fullscreen append-to-body>
      <el-form ref="dialogForm" :model="dialogForm" label-width="88px">
        <el-row :gutter="16">
          <el-col :span="6">
            <el-form-item label="执行日期" prop="executeDate">
              <el-date-picker
                v-model="dialogForm.executeDate"
                type="date"
                value-format="yyyy-MM-dd"
                placeholder="请选择执行日期"
                clearable
                style="width: 100%;"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="失效日期" prop="invalidDate">
              <el-date-picker
                v-model="dialogForm.invalidDate"
                type="date"
                value-format="yyyy-MM-dd"
                placeholder="请选择失效日期"
                clearable
                style="width: 100%;"
              />
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label-width="0">
              <!-- 复制价格按钮：预留复制逻辑 -->
              <el-button type="primary" plain icon="el-icon-document-copy" size="mini" @click="handleCopyPrice">复制价格</el-button>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="16">
          <el-col :span="24">
            <el-form-item label="备注" prop="remark">
              <el-input type="textarea" v-model="dialogForm.remark" placeholder="请输入备注" :rows="2" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>

      <el-row :gutter="12" class="dialog-bottom-row">
        <!-- 左：价格类型 -->
        <el-col :span="6" class="dialog-bottom-col">
          <el-card class="section-card" shadow="never">
            <div slot="header" class="card-header">
              <span>价格类型</span>
            </div>
            <el-table
              ref="dialogPriceTypeTable"
              border
              stripe
              height="100%"
              :data="dialogPriceTypeList"
              class="price-type-table"
              highlight-current-row
              @row-click="handleDialogPriceTypeRowClick"
              @current-change="handleDialogPriceTypeCurrentChange"
              style="width: 100%;"
            >
              <el-table-column label="序号" type="index" width="60" align="center" />
              <el-table-column label="价格类型" prop="priceTypeName" min-width="120" />
            </el-table>
          </el-card>
        </el-col>

        <!-- 右：价格列表（操作列为删除 icon） -->
        <el-col :span="18" class="dialog-bottom-col">
          <el-card class="section-card dialog-price-card" shadow="never">
            <div slot="header" class="card-header card-header--with-action">
              <span>价格列表</span>
              <div class="card-header-action">
                <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleDialogAddRow">添加</el-button>
              </div>
            </div>
            <!-- 可编辑价格列表：物料名称可通过物料速查选择（goodsNum 不展示但会写入） -->
            <el-table border stripe class="dialog-price-table" :data="dialogPriceList" style="width: 100%;">
              <el-table-column label="序号" type="index" width="60" align="center" />
              <el-table-column label="物料名称" prop="materialName" min-width="180">
                <template slot-scope="{ row, $index }">
                  <el-input v-model="row.materialName" placeholder="请选择物料" clearable>
                    <template #append>
                      <el-tooltip content="查询物料" placement="top">
                        <el-button type="success" icon="el-icon-search" circle size="mini" @click="openMaterialQuery($index)" />
                      </el-tooltip>
                    </template>
                  </el-input>
                </template>
              </el-table-column>
              <el-table-column label="规格" prop="spec" min-width="120" />
              <el-table-column label="品种" prop="variety" min-width="100" >
                <template slot-scope="{ row }">
                  <!-- 须传整行：方法内用 varietyName / varietyNo 与 varietyList 做展示映射，勿只传 row.variety -->
                  <span>{{ getPriceListVarietyLabel(row) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="级别" prop="level" min-width="90" >
                <template slot-scope="{ row }">
                  <span>{{ getPriceListLevelLabel(row) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="单价" prop="unitPrice" min-width="110">
                <template slot-scope="{ row }">
                  <decimal-input v-model="row.unitPrice" :precision="2" :min="0" placeholder="单价" />
                </template>
              </el-table-column>
              <el-table-column label="单位" prop="unit" min-width="90"></el-table-column>
              <el-table-column label="自提价" prop="pickupPrice" min-width="110">
                <template slot-scope="{ row }">
                  <decimal-input v-model="row.pickupPrice" :precision="2" :min="0" placeholder="自提价" />
                </template>
              </el-table-column>
              <el-table-column label="单位" prop="unit" min-width="90"> </el-table-column>
              <el-table-column label="备注" prop="remark" min-width="160">
                <template slot-scope="{ row }">
                  <el-input v-model="row.remark" placeholder="备注" clearable />
                </template>
              </el-table-column>
              <el-table-column label="操作" width="70" align="center" fixed="right">
                <template slot-scope="scope">
                  <el-button type="text" icon="el-icon-delete" @click="handleDialogDeleteRow(scope.$index)" />
                </template>
              </el-table-column>
            </el-table>
          </el-card>
        </el-col>
      </el-row>

      <div slot="footer" class="dialog-footer">
        <el-button size="small" @click="dialogOpen = false">取 消</el-button>
        <el-button size="small" type="primary" @click="submitDialog">确 定</el-button>
      </div>
    </el-dialog>

    <!-- 物料速查：多选，确定后写入当前价格类型的价格列表；已选物料禁止再次选择 -->
    <query-material
      ref="queryMaterial"
      :isMultiple="true"
      :excludeGoodsNums="materialExcludeGoodsNums"
      @selectList="handleMaterialSelect"
    />
  </div>
</template>

<script>
import { getPriceList } from "@/api/baseInfo/price";
import { formatDateYMS } from "@/utils";
import QueryMaterial from "@/views/components/queryMaterial.vue";
import { getPriceAdminList, addPriceAdmin, editPriceAdmin, delPriceAdmin } from "@/api/sale/priceAdmin";
import { getVarietyList } from "@/api/baseInfo/variety";
import { getLevelList } from "@/api/baseInfo/level";

export default {
  name: "SalePriceAdmin",
  components: { QueryMaterial },
  data() {
    return {
      /** 加载状态（右侧价格列表） */
      loading: false,
      /** 右侧表格多选禁用控制 */
      multiple: true,
      /** 右侧表格选中行 */
      selection: [],
      /** 当前选中的价格类型编号（只取 priceTypeNum） */
      currentPriceTypeNum: null,
      /** 查询参数（包含 pageNum/pageSize） */
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        executeDateRange: [],
        effectiveDateStart: null,
        effectiveDateEnd: null
      },
      /** 价格类型列表（左侧） */
      priceTypeList: [],
      /** 价格列表（右侧），TODO：对接真实接口 */
      priceList: [],
      /** 品种/级别基础数据：用于 priceList 表格 value -> label */
      varietyList: [],
      levelList: [],
      /** 新增弹框标题 */
      dialogTitle: "新增价格",
      /** 新增弹框开关 */
      dialogOpen: false,
      /** 新增弹框表单 */
      dialogForm: {
        executeDate: null,
        invalidDate: null,
        remark: null,
      },
      /** 新增弹框左侧价格类型 */
      dialogPriceTypeList: [],
      /** 新增弹框：按价格类型分别维护价格列表（key=priceTypeNum） */
      dialogPriceMap: {},
      /** 新增弹框当前展示的价格列表（来自 dialogPriceMap） */
      dialogPriceList: [],
      /** 新增弹框当前选中的价格类型编号（只取 priceTypeNum） */
      dialogCurrentPriceTypeNum: null,
      /** 当前正在选择物料的行索引 */
      currentMaterialRowIndex: null,
      /** 物料速查需要禁用的 goodsNum 集合（防止重复选中） */
      materialExcludeGoodsNums: [],
    };
  },
  created() {
    /** 执行日期默认今天到今天 */
    const today = formatDateYMS(new Date().getTime() + 24 * 60 * 60 * 1000);
    this.queryParams.executeDateRange = [today, today];
    this.queryParams.effectiveDateStart = today;
    this.queryParams.effectiveDateEnd = today;
    /** 初始化加载价格类型（拿到默认价格类型后再触发默认查询） */
    this.getPriceTypeList();
    this.fetchVarietyAndLevelForPriceList();
  },
  methods: {
    /** 加载品种、级别下拉数据，供右侧 priceList 展示编码对应名称 */
    fetchVarietyAndLevelForPriceList() {
      getVarietyList({}).then((res) => {
        this.varietyList = res.data || [];
      });
      getLevelList({}).then((res) => {
        this.levelList = res.data || [];
      });
    },
    /**
     * 价格列表行：品种 value -> label（须传整行对象：优先 varietyName，再按 variety/varietyNo 在 varietyList 中映射）
     * @param {Object} row 表格行
     */
    getPriceListVarietyLabel(row) {
      const r = row || {};
      if (r.varietyName != null && String(r.varietyName).trim() !== "") {
        return r.varietyName;
      }
      const val = r.variety != null ? r.variety : r.varietyNo;
      if (val == null || val === "") return "-";
      const list = Array.isArray(this.varietyList) ? this.varietyList : [];
      const hit = list.find((item) => String(item.varietyNo) === String(val));
      return hit ? (hit.varietyName || "-") : val;
    },
    /**
     * 价格列表行：级别 value -> label（须传整行：优先 levelName，再按 level/grade 在 levelList 中映射）
     * @param {Object} row 表格行
     */
    getPriceListLevelLabel(row) {
      const r = row || {};
      if (r.levelName != null && String(r.levelName).trim() !== "") {
        return r.levelName;
      }
      const val = r.level != null ? r.level : r.grade;
      if (val == null || val === "") return "-";
      const list = Array.isArray(this.levelList) ? this.levelList : [];
      const hit = list.find((item) => String(item.levelNo) === String(val));
      return hit ? (hit.levelName || "-") : val;
    },
    /** 查询按钮：重置页码并刷新价格列表 */
    handleQuery() {
      this.queryParams.pageNum = 1;
      /** 查询前提：必须先选择价格类型（默认会选中第一个，只取 priceTypeNum） */
      if (!this.currentPriceTypeNum) {
        this.$message.warning("请先选择价格类型");
        return;
      }
      this.getPriceData();
    },
    /** 新增按钮：预留新增逻辑 */
    handleAdd() {
      /** 打开新增弹框（全屏）并初始化数据 */
      this.openAddDialog();
    },
    /** 删除按钮：预留批量删除逻辑 */
    handleDeleteAll() {
      console.log("delete selected", this.selection);
    },
    /** 打开新增弹框：初始化表单与左右表格数据 */
    openAddDialog() {
      const today = formatDateYMS(new Date().getTime() + 24 * 60 * 60 * 1000);
      this.dialogTitle = "新增价格";
      this.dialogForm = {
        executeDate: today,
        invalidDate: today,
        remark: null,
      };
      /** 弹框表格数据：默认取当前页面数据（逻辑可后续分离） */
      this.dialogPriceTypeList = [...(this.priceTypeList || [])];
      /** 初始化：每个价格类型默认 1 条空行（全 null） */
      this.dialogPriceMap = {};
      (this.dialogPriceTypeList || []).forEach((t) => {
        const key = t && t.priceTypeNum != null ? String(t.priceTypeNum) : null;
        if (!key) return;
        this.dialogPriceMap[key] = [this.createEmptyDialogPriceRow()];
      });
      /** 弹框价格类型默认选中第一个并高亮（只记录 priceTypeNum） */
      if (this.dialogPriceTypeList.length > 0) {
        const firstRow = this.dialogPriceTypeList[0];
        this.dialogCurrentPriceTypeNum = firstRow.priceTypeNum || null;
        this.$nextTick(() => {
          if (this.$refs.dialogPriceTypeTable) this.$refs.dialogPriceTypeTable.setCurrentRow(firstRow);
        });
      } else {
        this.dialogCurrentPriceTypeNum = null;
      }
      /** 根据默认价格类型切换右侧列表显示 */
      this.refreshDialogPriceList();
      this.dialogOpen = true;
    },
    /**
     * 判断价格列表行是否整行为空（与 submitDialog 一致，便于剔除占位行）
     * @param {Object} row 行数据
     */
    isDialogPriceRowAllEmpty(row) {
      const r = row || {};
      const fields = [
        "goodsNum",
        "materialNum",
        "materialName",
        "spec",
        "variety",
        "varietyName",
        "level",
        "levelName",
        "unitPrice",
        "unit",
        "pickupPrice",
        "remark",
      ];
      return fields.every((k) => r[k] === null || r[k] === undefined || String(r[k]).trim() === "");
    },
    /** 非空字段校验（物料名称、单价、自提价） */
    isDialogPriceFieldFilled(v) {
      return v !== null && v !== undefined && String(v).trim() !== "";
    },
    /**
     * 复制价格：校验当前价格类型下列表有数据且每行物料名称/单价/自提价已填；
     * 确认后将当前表格数据同步到左侧其它价格类型对应的价格列表。
     */
    handleCopyPrice() {
      const typeKey =
        this.dialogCurrentPriceTypeNum != null ? String(this.dialogCurrentPriceTypeNum) : null;
      if (!typeKey) {
        this.$message.warning("请先选择价格类型");
        return;
      }
      const rawList =
        (this.dialogPriceMap && this.dialogPriceMap[typeKey]) ||
        this.dialogPriceList ||
        [];
      const dataRows = (rawList || []).filter((r) => !this.isDialogPriceRowAllEmpty(r));
      if (dataRows.length === 0) {
        this.$message.warning("当前价格类型的价格列表没有有效数据，请先填写物料名称、单价、自提价等");
        return;
      }
      for (let i = 0; i < dataRows.length; i++) {
        const row = dataRows[i] || {};
        if (!this.isDialogPriceFieldFilled(row.materialName)) {
          this.$message.warning(`第 ${i + 1} 行：请填写物料名称`);
          return;
        }
        if (!this.isDialogPriceFieldFilled(row.unitPrice)) {
          this.$message.warning(`第 ${i + 1} 行：请填写单价`);
          return;
        }
        if (!this.isDialogPriceFieldFilled(row.pickupPrice)) {
          this.$message.warning(`第 ${i + 1} 行：请填写自提价`);
          return;
        }
      }
      /** 左侧每个价格类型（市场）除当前选中外，均需可写入 */
      const typeList = this.dialogPriceTypeList || [];
      const otherTypes = typeList.filter(
        (t) => t && t.priceTypeNum != null && String(t.priceTypeNum) !== typeKey
      );
      if (otherTypes.length === 0) {
        this.$message.warning("暂无其他市场（价格类型）可同步");
        return;
      }
      /** 深拷贝当前有效行，避免各市场列表引用同一对象 */
      const snapshot = dataRows.map((r) => ({ ...r }));
      this.$confirm("是否将价格同步到其他市场？", "提示", {
        confirmButtonText: "是",
        cancelButtonText: "否",
        type: "warning",
      })
        .then(() => {
          otherTypes.forEach((t) => {
            const k = String(t.priceTypeNum);
            this.$set(
              this.dialogPriceMap,
              k,
              snapshot.map((row) => ({ ...row }))
            );
          });
          this.$message.success(`已同步到 ${otherTypes.length} 个其他市场`);
          this.refreshDialogPriceList();
        })
        .catch(() => {});
    },
    /** 弹框内价格列表删除一行（icon 操作） */
    handleDialogDeleteRow(index) {
      if (index < 0) return;
      /** 表格仅剩 1 行时不允许删除 */
      if ((this.dialogPriceList || []).length <= 1) {
        this.$message.warning("表格仅剩一条数据，不能删除");
        return;
      }
      const list = (this.dialogPriceList || []).filter((_, i) => i !== index);
      this.setDialogPriceListForCurrentType(list);
    },
    /** 弹框内价格列表添加一行空数据 */
    handleDialogAddRow() {
      const list = [...(this.dialogPriceList || []), this.createEmptyDialogPriceRow()];
      this.setDialogPriceListForCurrentType(list);
    },
    /** 创建一行空的可编辑价格数据（默认都是 null，goodsNum 不展示但会提交） */
    createEmptyDialogPriceRow() {
      return {
        goodsNum: null,
        materialNum: null,
        materialName: null,
        spec: null,
        variety: null,
        varietyName: null,
        level: null,
        levelName: null,
        unitPrice: null,
        unit: null,
        pickupPrice: null,
        remark: null,
      };
    },
    /** 打开物料速查弹框（单选），记录当前行索引 */
    openMaterialQuery(rowIndex) {
      this.currentMaterialRowIndex = rowIndex;
      /** 打开速查前计算禁用清单：当前价格类型下已选过的 goodsNum */
      this.materialExcludeGoodsNums = this.getCurrentTypeSelectedGoodsNums();
      if (this.$refs.queryMaterial) this.$refs.queryMaterial.open();
    },
    /** 获取当前价格类型下已选择的 goodsNum，用于在物料速查中禁用再次选择 */
    getCurrentTypeSelectedGoodsNums() {
      const key = this.dialogCurrentPriceTypeNum != null ? String(this.dialogCurrentPriceTypeNum) : null;
      const rows = key && this.dialogPriceMap ? this.dialogPriceMap[key] : [];
      return (rows || [])
        .map((r) => {
          if (!r) return null;
          const n = r.materialNum != null ? r.materialNum : r.goodsNum;
          return n != null ? String(n) : null;
        })
        .filter((x) => x);
    },
    /**
     * 物料速查选择回调（单选也会返回数组）
     * - goodsNum 字段不展示，但需要写入到价格列表行
     */
    handleMaterialSelect(list) {
      /** 多选：把选中的物料填充到“当前价格类型”的价格列表中 */
      const selected = list || [];
      if (selected.length === 0) return;
      const startIndex = this.currentMaterialRowIndex != null ? this.currentMaterialRowIndex : 0;
      const currentList = [...(this.dialogPriceList || [])];
      /** 至少保证有一行可写入 */
      if (currentList.length === 0) currentList.push(this.createEmptyDialogPriceRow());

      selected.forEach((item, i) => {
        const targetIndex = startIndex + i;
        if (!currentList[targetIndex]) currentList[targetIndex] = this.createEmptyDialogPriceRow();
        const row = { ...currentList[targetIndex] };
        // 写入：goodsNum（隐藏字段）+ 基础展示字段
        row.goodsNum = item.goodsNum;
        row.materialNum = item.goodsNum;
        row.materialName = item.goodsName;
        row.spec = item.goodsSpec;
        row.variety = item.variety;
        /** 速查表格列名为 varietyName，与编码一并写入便于展示与提交兜底 */
        row.varietyName = item.varietyName != null ? item.varietyName : null;
        row.level = item.goodsLevel;
        row.levelName = item.levelName != null ? item.levelName : null;
        row.unit = item.unit;
        currentList[targetIndex] = row;
      });

      this.setDialogPriceListForCurrentType(currentList);
    },
    /** 弹框左侧价格类型点击：切换当前价格类型并刷新右侧列表 */
    handleDialogPriceTypeRowClick(row) {
      this.dialogCurrentPriceTypeNum = row ? row.priceTypeNum : null;
      this.refreshDialogPriceList();
    },
    /** 弹框左侧价格类型当前行变化：同步当前价格类型并刷新右侧列表 */
    handleDialogPriceTypeCurrentChange(row) {
      this.dialogCurrentPriceTypeNum = row ? row.priceTypeNum : null;
      this.refreshDialogPriceList();
    },
    /** 根据当前价格类型刷新右侧可编辑列表显示 */
    refreshDialogPriceList() {
      const key = this.dialogCurrentPriceTypeNum != null ? String(this.dialogCurrentPriceTypeNum) : null;
      if (!key) {
        this.dialogPriceList = [this.createEmptyDialogPriceRow()];
        return;
      }
      if (!this.dialogPriceMap[key]) {
        /** 兜底：该价格类型没有列表时，默认一条空行 */
        this.$set(this.dialogPriceMap, key, [this.createEmptyDialogPriceRow()]);
      }
      this.dialogPriceList = [...this.dialogPriceMap[key]];
    },
    /** 将当前右侧列表写回到 dialogPriceMap（按当前价格类型） */
    setDialogPriceListForCurrentType(list) {
      const key = this.dialogCurrentPriceTypeNum != null ? String(this.dialogCurrentPriceTypeNum) : null;
      if (!key) return;
      const next = list && list.length > 0 ? list : [this.createEmptyDialogPriceRow()];
      this.$set(this.dialogPriceMap, key, next);
      this.dialogPriceList = [...next];
    },
    /** 弹框确认：校验后调用 addPriceAdmin（/price/batchAdd）批量保存 */
    submitDialog() {
      /**
       * 弹框确认前：剔除“整行全为空”的占位数据（除序号外）
       * - 仅删除完全未填写的空行
       * - 避免空行触发必填校验
       */
      const isAllNullRow = (row) => {
        const r = row || {};
        /** 与弹框行字段一致（unitPrice / pickupPrice，勿用已废弃的 price / selfPickupPrice） */
        const fields = [
          "goodsNum",
          "materialNum",
          "materialName",
          "spec",
          "variety",
          "varietyName",
          "level",
          "levelName",
          "unitPrice",
          "unit",
          "pickupPrice",
          "remark",
        ];
        return fields.every((k) => r[k] === null || r[k] === undefined || String(r[k]).trim() === "");
      };

      /** 清洗每个价格类型的价格列表：去掉全空行 */
      const map = this.dialogPriceMap || {};
      Object.keys(map).forEach((key) => {
        const rows = map[key] || [];
        const next = (rows || []).filter((r) => !isAllNullRow(r));
        this.$set(this.dialogPriceMap, String(key), next);
      });
      /** 同步当前展示列表 */
      this.refreshDialogPriceList();

      /**
       * 校验可编辑表格必填：
       * - 物料名称
       * - 单价
       * - 自提价
       */
      const checkRequired = (v) => v !== null && v !== undefined && String(v).trim() !== "";
      const typeMap = new Map((this.dialogPriceTypeList || []).map((t) => [String(t.priceTypeNum), t]));
      const mapAfterClean = this.dialogPriceMap || {};

      for (const key of Object.keys(mapAfterClean)) {
        const rows = mapAfterClean[key] || [];
        const type = typeMap.get(String(key));
        const typeName = type ? type.priceTypeName : String(key);
        for (let i = 0; i < rows.length; i++) {
          const row = rows[i] || {};
          if (!checkRequired(row.materialName)) {
            this.$message.warning(`价格类型【${typeName}】第${i + 1}行：物料名称必填`);
            return;
          }
          if (!checkRequired(row.unitPrice)) {
            this.$message.warning(`价格类型【${typeName}】第${i + 1}行：单价必填`);
            return;
          }
          if (!checkRequired(row.pickupPrice)) {
            this.$message.warning(`价格类型【${typeName}】第${i + 1}行：自提价必填`);
            return;
          }
        }
      }

      if (!checkRequired(this.dialogForm.executeDate)) {
        this.$message.warning("请选择执行日期");
        return;
      }
      if (!checkRequired(this.dialogForm.invalidDate)) {
        this.$message.warning("请选择失效日期");
        return;
      }

      /** 组装 batchAdd 入参：[{ priceType, effectiveDate, expireDate, remark, items }] */
      const payload = this.buildAddPriceAdminPayload(mapAfterClean, typeMap);
      if (!payload.length) {
        this.$message.warning("请至少在一个价格类型下填写价格明细");
        return;
      }
      addPriceAdmin(payload)
        .then(() => {
          this.$message.success("保存成功");
          this.dialogOpen = false;
          this.handleQuery();
        })
        .catch(() => {});
    },
    /**
     * 将弹框内 dialogPriceMap 转为接口 batchAdd 所需结构。
     * @param {Object} mapAfterClean 按 priceTypeNum 清洗后的行列表
     * @param {Map} typeMap priceTypeNum -> 价格类型行（取 priceTypeCode / priceTypeNum）
     * @returns {Array<{ priceType: string, effectiveDate: string, expireDate: string, remark: string, items: Array }>}
     */
    buildAddPriceAdminPayload(mapAfterClean, typeMap) {
      const effectiveDate = this.dialogForm.executeDate || "";
      const expireDate = this.dialogForm.invalidDate || "";
      const remark =
        this.dialogForm.remark != null && this.dialogForm.remark !== undefined
          ? String(this.dialogForm.remark)
          : "";

      const toStr = (v) => (v != null && v !== "" ? String(v) : "");

      const list = [];
      Object.keys(mapAfterClean || {}).forEach((key) => {
        const rows = mapAfterClean[key] || [];
        if (!rows.length) return;

        const type = typeMap.get(String(key));
        /** 接口 priceType：优先编码字段，否则用 priceTypeNum */
        const priceType =
          type && type.priceTypeCode != null && String(type.priceTypeCode).trim() !== ""
            ? String(type.priceTypeCode)
            : type && type.priceTypeNum != null
              ? String(type.priceTypeNum)
              : String(key);

        const items = rows.map((row) => {
          const r = row || {};
          const materialNum = r.materialNum != null ? r.materialNum : r.goodsNum;
          return {
            materialNum: toStr(materialNum),
            materialName: toStr(r.materialName),
            spec: toStr(r.spec),
            variety: toStr(r.variety != null ? r.variety : r.varietyName),
            level: toStr(r.level != null ? r.level : r.levelName),
            unitPrice: toStr(r.unitPrice),
            unit: toStr(r.unit),
            pickupPrice: toStr(r.pickupPrice),
            remark: toStr(r.remark),
          };
        });

        list.push({
          priceType,
          effectiveDate,
          expireDate,
          remark,
          items,
        });
      });
      return list;
    },
    /** 右侧表格勾选变化 */
    handleSelectionChange(val) {
      this.selection = val || [];
      this.multiple = this.selection.length === 0;
    },
    /** 获取价格类型（左侧），仅保留状态为启用的数据 */
    getPriceTypeList() {
      getPriceList({}).then((res) => {
        const list = res.data || [];
        // 兼容不同字段：status / priceTypeStatus（启用）
        this.priceTypeList = list.filter(
          (item) =>
            item.priceTypeStatus === 1 
        );
        /** 默认选中第一个价格类型并高亮 */
        if (this.priceTypeList.length > 0) {
          const firstRow = this.priceTypeList[0];
          this.currentPriceTypeNum = firstRow.priceTypeNum || null;
          this.$nextTick(() => {
            if (this.$refs.priceTypeTable) this.$refs.priceTypeTable.setCurrentRow(firstRow);
          });
          /** 默认进来就查询：前提是已拿到默认价格类型 */
          this.handleQuery();
        } else {
          /** 无可用价格类型时清空右侧列表 */
          this.currentPriceTypeNum = null;
          this.priceList = [];
        }
      });
    },
    /** 左侧表格当前行变化：同步当前选中的价格类型编号（priceTypeNum） */
    handlePriceTypeCurrentChange(row) {
      this.currentPriceTypeNum = row ? row.priceTypeNum : null;
    },
    /** 点击左侧价格类型：记录当前类型并刷新右侧价格列表（预留） */
    handlePriceTypeRowClick(row) {
      this.currentPriceTypeNum = row ? row.priceTypeNum : null;
      this.getPriceData();
    },
    /**
     * 获取价格列表（右侧）
     * TODO：对接真实接口（应携带：执行日期范围、当前价格类型、pageNum/pageSize）
     */
    getPriceData() {
      this.loading = true;
      let params = {
        effectiveDateStart: this.queryParams.effectiveDateStart,
        effectiveDateEnd: this.queryParams.effectiveDateEnd,
        priceType: this.currentPriceTypeNum,
      }
      getPriceAdminList(params).then(res => {
        this.priceList = res.data;
      
        this.loading = false;
      });
    },
  },
  watch: {
    'queryParams.executeDateRange': {
      handler(newVal) {
        if(newVal && newVal.length === 2) {
          this.queryParams.effectiveDateStart = newVal[0];
          this.queryParams.effectiveDateEnd = newVal[1];
        } else {
          this.queryParams.effectiveDateStart = null;
          this.queryParams.effectiveDateEnd = null;
        }
      },
      deep: true,
      immediate: true,
    },  
  
  },
};
</script>

<style scoped>
.sale-price-admin-page {
  height: calc(100vh - 90px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.top-card {
  flex: 0 0 auto;
}

/** 下方区域占剩余高度 */
.bottom-row {
  flex: 1 1 0;
  min-height: 0;
  margin-left: 0 !important;
  margin-right: 0 !important;
}

.bottom-col {
  height: 100%;
}

.section-card {
  height: 100%;
}

/** 让 el-card 内容区撑满，从而 table height=100% 生效 */
::v-deep .section-card > .el-card__body {
  height: calc(100% - 0px);
  min-height: 0;
  padding: 12px;
}

.card-header {
  font-weight: 500;
  color: #303133;
}

/** 标题右侧按钮：右对齐显示 */
.card-header--with-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.card-header-action {
  text-align: right;
}

/** 左侧价格类型高亮：浅蓝底 + 白色文字 */
::v-deep .price-type-table .el-table__body tr.current-row > td {
  background-color: #66b1ff !important;
}

::v-deep .price-type-table .el-table__body tr.current-row > td .cell {
  color: #ffffff !important;
}

/** 价格类型表格 hover 时鼠标小手 */
::v-deep .price-type-table .el-table__body-wrapper tbody tr {
  cursor: pointer;
}

/** 弹框下方左右区域占剩余高度 */
.dialog-bottom-row {
  height: calc(100vh - 320px);
  min-height: 300px;
}

.dialog-bottom-col {
  height: 100%;
}

/** 弹框内表格下方工具栏 */
.dialog-table-toolbar {
  padding-top: 10px;
  text-align: center;
}

/** 弹框右侧：价格列表（表格 + 工具栏）需要纵向布局，保证“添加”按钮可见 */
::v-deep .dialog-price-card > .el-card__body {
  display: flex;
  flex-direction: column;
}

.dialog-price-table {
  flex: 1 1 0;
  min-height: 0;
}
</style>
