<template>
  <view
    class="section"
    :style="{
      position: 'relative',
      zIndex: dropdownOpen || dropdownRegionOpen || dropdownManufacturerOpen ? 9 : 'auto',
    }">
    <view v-if="showHeader" class="section-header" :class="!shouldShowAreaSearch ? 'noAreaHeader' : ''">
      <view class="section-title-row">
        <text class="section-title">{{ title }}</text>
      </view>
      <view v-if="showSelector" class="selector-row">
        <view class="selector-wrap" v-if="shouldShowAreaSearch">
          <view class="selector" @click.stop="toggleDropdownRegion">
            <text class="selector-text">{{ region?.regionCode ? region.regionName : "选择片区" }}</text>
            <text class="selector-arrow" :class="{ open: dropdownRegionOpen }"></text>
          </view>
          <view class="dropdown" v-show="dropdownRegionOpen" :style="dropdownDirection === 'top' ? { top: 'auto', bottom: '48rpx' } : {}" @click.stop>
            <view class="dropdown-search-bar">
              <input class="dropdown-search-input" v-model="regionSearchText" @input="onRegionSearch" placeholder="搜索..." />
            </view>
            <scroll-view scroll-y="true" class="dropdown-scroll-view" lower-threshold="80" @scrolltolower="loadMoreRegions">
              <view
                class="dropdown-item"
                v-for="(p, i) in regionList"
                :key="p.regionCode || i"
                :style="
                  p.regionCode === region?.regionCode || (!region?.regionCode && i == 0)
                    ? {
                        backgroundColor: '#2c69ff',
                        color: '#fff',
                      }
                    : {}
                "
                @click.stop="selectProduct('region', p)"
                >{{ p.regionName || p }}</view
              >
              <view v-if="regionList.length === 0" class="dropdown-item" style="text-align: center; color: #999">暂无数据 </view>
            </scroll-view>
          </view>
        </view>
        <view class="selector-wrap">
          <view class="selector" @click.stop="toggleDropdownManufacturer">
            <text class="selector-text">{{ manufacturer?.manufacturerId ? manufacturer.produceEntName : "选择厂家" }}</text>
            <text class="selector-arrow" :class="{ open: dropdownManufacturerOpen }"></text>
          </view>
          <view class="dropdown" v-show="dropdownManufacturerOpen" :style="dropdownDirection === 'top' ? { top: 'auto', bottom: '48rpx' } : {}" @click.stop>
            <view class="dropdown-search-bar">
              <input class="dropdown-search-input" v-model="manufacturerSearchText" @input="onManufacturerSearch" placeholder="搜索..." />
            </view>
            <scroll-view scroll-y="true" class="dropdown-scroll-view" lower-threshold="80" @scrolltolower="loadMoreManufacturers">
              <view
                class="dropdown-item"
                v-for="(m, i) in manufacturerList"
                :key="m.manufacturerId || i"
                :style="
                  m.manufacturerId === manufacturer?.manufacturerId || (!manufacturer?.manufacturerId && i == 0)
                    ? {
                        backgroundColor: '#2c69ff',
                        color: '#fff',
                      }
                    : {}
                "
                @click.stop="selectProduct('manufacturer', m)"
                >{{ m.produceEntName }}</view
              >
              <view v-if="manufacturerList.length === 0" class="dropdown-item" style="text-align: center; color: #999">暂无数据</view>
            </scroll-view>
          </view>
        </view>
        <view class="selector-wrap">
          <view class="selector" @click.stop="toggleDropdown">
            <text class="selector-text">{{ cascaderDisplayText }}</text>
            <text class="selector-arrow" :class="{ open: dropdownOpen }"></text>
          </view>
          <view
            class="dropdown cascader-dropdown"
            v-show="dropdownOpen"
            :style="
              dropdownDirection === 'top'
                ? {
                    top: 'auto',
                    bottom: '48rpx',
                  }
                : {}
            "
            @click.stop>
            <view class="cascader-search-row">
              <view class="dropdown-search-bar cascader-search">
                <input class="dropdown-search-input" v-model="productSearchText" @input="onProductSearch" placeholder="搜索品种" />
              </view>
              <view class="dropdown-search-bar cascader-search">
                <input class="dropdown-search-input" v-model="specSearchText" @input="onSpecSearch" placeholder="搜索规格" />
              </view>
            </view>
            <view class="cascader-body">
              <scroll-view scroll-y="true" class="dropdown-scroll-view cascader-col" lower-threshold="80" @scrolltolower="loadMoreProducts">
                <view
                  class="dropdown-item"
                  v-for="(p, i) in productList"
                  :key="p.drugEntBaseInfoId || i"
                  :style="
                    p.drugEntBaseInfoId === activeProductForSpec?.drugEntBaseInfoId
                      ? {
                          backgroundColor: '#2c69ff',
                          color: '#fff',
                        }
                      : {}
                  "
                  @click.stop="selectCascadeProduct(p)"
                  >{{ p.physicName }}</view
                >
                <view v-if="productList.length === 0" class="dropdown-item" style="text-align: center; color: #999">暂无数据 </view>
              </scroll-view>
              <scroll-view scroll-y="true" class="dropdown-scroll-view cascader-col cascader-col-right" lower-threshold="80" @scrolltolower="loadMoreSpecs">
                <view
                  class="dropdown-item"
                  v-for="(s, i) in specList"
                  :key="s.specId || i"
                  :style="
                    s.specId === selectedSpec?.specId || (!selectedSpec?.specId && i == 0)
                      ? {
                          backgroundColor: '#2c69ff',
                          color: '#fff',
                        }
                      : {}
                  "
                  @click.stop="selectCascadeSpec(s)"
                  >{{ s.pkgSpec }}</view
                >
                <view v-if="specList.length === 0" class="dropdown-item" style="text-align: center; color: #999">暂无数据 </view>
              </scroll-view>
            </view>
          </view>
        </view>
      </view>
    </view>

    <view
      class="table-scroll-x"
      :style="{
        height: tableHeightAuto || list.length < 7 ? 'auto' : _tableBodyHeight + 80 + 'rpx',
        maxHeight: tableHeightAuto,
      }">
      <scroll-view
        class="no-scrollbar"
        :style="{ height: '100%' }"
        scroll-x="true"
        scroll-y="true"
        enhanced
        :show-scrollbar="false"
        @scrolltolower="onScrollToLower">
        <view class="card" :style="{ width: tableWidth }">
          <view
            class="table-header"
            :style="{
              position: 'sticky',
              top: '0',
              zIndex: 10,
              fontWeight: headerBold ? 'bold' : 'normal',
            }">
            <view
              v-for="(col, ci) in columnList"
              :key="getUid()"
              class="cell"
              :style="{
                ...headerCellStyle(ci, col),
              }">
              <view
                v-if="isPlainTitle(col.title)"
                :style="{
                  display: 'flex',
                  alignItems: 'center',
                  position: 'relative',
                }">
                <text>{{ col.title }}</text>
                <uni-icons v-if="col.tooltip" type="help" size="16" color="#2c69ff" @tap.stop.prevent="toggleHeaderTooltip(ci)"></uni-icons>
                <view v-if="headerTooltip[ci]" class="header-tooltip-wrap" @click.stop>
                  <view class="header-tooltip">{{ col.tooltip }}</view>
                  <view class="header-tooltip-arrow"></view>
                </view>
              </view>
              <rich-text v-else :nodes="titleNodes(col.title)" />
            </view>
          </view>
          <view v-if="!loading && list && list.length > 0" class="table-body">
            <template>
              <view class="row" v-for="(item, i) in list" :key="getUid()">
                <view
                  v-for="(col, ci) in columnList"
                  :key="getUid()"
                  class="cell"
                  :class="{
                    underline: col.underline,
                    striped: striped && (i + 1) % 2 === 0,
                  }"
                  :style="bodyCellStyle(ci, col)"
                  @click="handleClick(item, col)"
                  >{{ renderCell(item, col) }}</view
                >
              </view>
              <view class="row loading-row" v-if="hasmore">
                <view class="loading-wrapper">
                  <image class="loading-icon" :src="loadingImg" />
                </view>
              </view>
              <view
                class="row"
                v-if="showSummary"
                :style="{
                  position: 'sticky',
                  bottom: '0',
                  zIndex: 5,
                  backgroundColor: '#fff',
                  borderTop: '1rpx solid #eef0f4',
                  color: summaryFontColor,
                }">
                <view
                  v-for="(col, ci) in columnList"
                  :key="getUid()"
                  class="cell"
                  :style="{
                    ...bodyCellStyle(ci, col),
                    fontWeight: summaryBold ? 'bold' : 'normal',
                  }"
                  >{{ getSummary(col, ci) }}</view
                >
              </view>
            </template>
          </view>
        </view>
        <view v-if="loading" class="no-data-placeholder" :style="{ height: 'auto' }">
          <view class="row loading-row">
            <view class="loading-wrapper">
              <image class="loading-icon" :src="loadingImg" />
            </view>
          </view>
        </view>
        <view v-if="!loading && (!list || list.length === 0)" class="no-data-placeholder">
          <EmptyView />
        </view>
      </scroll-view>
      <view v-if="loading" class="no-data" :style="{ height: 'auto', top: cellHeight }">
        <view class="row loading-row">
          <view class="loading-wrapper">
            <image class="loading-icon" :src="loadingImg" />
          </view>
        </view>
      </view>
      <view v-if="!loading && (!list || list.length === 0)" class="no-data" :style="{ top: cellHeight }">
        <EmptyView />
      </view>
    </view>
  </view>
</template>

<script>
import EmptyView from "../../../../wigets/empty.vue";
import loadingImg from "../../../../static/images/loading.png";
import { getUid } from "../../../../utils/utils.js";
import request from "../../../../request/index.js";
import Select from "../../../../wigets/select.vue";
export default {
  name: "ScanRateTable",
  components: { EmptyView, Select },
  props: {
    params: {
      type: Object,
      default: null,
    },
    scanType: { type: String, default: "1" },
    api: {
      type: String,
      default: "",
    },
    tableType: { type: String, default: "customer" },
    title: { type: String, default: "客户扫码率" },
    showSelector: { type: Boolean, default: true },
    showAreaSearch: { type: [Boolean, String], default: true },
    showHeader: { type: Boolean, default: true },
    dropdownDirection: { type: String, default: "bottom" },
    showSummary: { type: Boolean, default: true },
    striped: { type: Boolean, default: true },
    summaryStructure: {
      type: Array,
      default: () => [
        {
          key: "totalInRate",
          title: "入库扫码率",
          unit: "%",
        },
        {
          key: "totalOutRate",
          title: "出库扫码率",
          unit: "%",
        },
        // {
        //   key: "totalSelfExaminationRate",
        //   title: "自验证率",
        //   unit: "%",
        // },
      ],
    },
    summaryBold: { type: Boolean, default: false },
    summaryFontColor: {
      type: String,
      default: "#2c69ff",
    },
    initial: { type: Array, default: () => [] },
    products: { type: Array, default: () => [] },
    regions: { type: Array, default: () => [] },
    entNames: { type: Array, default: () => [] },
    product: { type: String, default: "" },
    drugEntBaseInfoId: { type: [String, Number], default: "" },
    spec: { type: String, default: "" },
    entName: { type: String, default: "" },
    regionCode: { type: [String, Number], default: "" },
    regionName: { type: String, default: "" },
    cellHeight: {
      type: String,
      default: "76rpx",
    },
    headerFontSize: {
      type: String,
      default: "32rpx",
    },
    headerBold: {
      type: Boolean,
      default: true,
    },
    bodyFontSize: {
      type: String,
      default: "32rpx",
    },
    bodyFontColor: {
      type: String,
      default: "",
    },
    //若需要横向滚动且左侧固定，则tableWidth需等于columns所有width之和（可以略小于）
    tableWidth: {
      type: String,
      default: "100%",
    },
    tableHeightAuto: {
      type: Boolean,
      default: false,
    },
    pageSize: {
      type: Number,
      default: 10,
    },
    tableBodyHeight: {
      type: Number,
      default: 0,
    },
    columns: {
      type: Array,
      default: () => [
        {
          key: "regionName",
          title: "区域",
          underline: true,
          fixed: true,
          width: "",
        },
        {
          key: "inScanRate",
          title: "入库扫码率",
          fixed: false,
          width: "",
          tooltip: "客户入库扫码量（与上游出库单中相同的追溯码）/上游企业出库扫码量",
          unit: "%",
        },
        {
          key: "outScanRate",
          title: "出库扫码率",
          fixed: false,
          width: "",
          tooltip: "客户出库扫码量（与下游入库单中相同的追溯码）/下游企业入库扫码量",
          unit: "%",
        },
        // {
        //   key: "selfExaminationRate",
        //   title: "自验证率",
        //   fixed: false,
        //   width: "",
        //   tooltip: "客户出库扫码量（与入库单中相同的追溯码）/入库扫码量",
        //   unit: "%",
        // },
      ],
    },
  },
  data() {
    return {
      dropdownOpen: false,
      dropdownRegionOpen: false,
      dropdownManufacturerOpen: false,
      dropdownSpecOpen: false,
      list: [],
      totalCount: 0,
      hasmore: true,
      loading: true,
      fetchLoading: false,
      loadingImg,
      selectedProduct: { drugEntBaseInfoId: null, physicName: "全品种" },
      activeProductForSpec: { drugEntBaseInfoId: null, physicName: "全品种" },
      region: null,
      manufacturer: { manufacturerId: null, produceEntName: "全厂家" },
      selectedSpec: { specId: null, pkgSpec: "全规格" },
      tablePage: 1,
      tablePageSize: this.pageSize,
      summaryData: [],
      headerTooltip: {},
      regionSearchText: "",
      productSearchText: "",
      manufacturerSearchText: "",
      specSearchText: "",
      regionList: [],
      productList: [],
      manufacturerList: [],
      specList: [],
      allProductOption: { drugEntBaseInfoId: null, physicName: "全品种" },
      allManufacturerOption: {
        manufacturerId: null,
        produceEntName: "全厂家",
      },
      allSpecOption: { specId: null, pkgSpec: "全规格" },
      mockProductManufacturerSpecMap: {
        感冒灵颗粒: [
          {
            manufacturerId: "m1",
            produceEntName: "华润三九医药股份有限公司",
            specs: [
              { specId: "s1", pkgSpec: "10g*9袋/盒" },
              { specId: "s2", pkgSpec: "10g*12袋/盒" },
            ],
          },
          {
            manufacturerId: "m2",
            produceEntName: "昆明华润圣火药业有限公司",
            specs: [{ specId: "s3", pkgSpec: "6g*10袋/盒" }],
          },
        ],
        阿莫西林胶囊: [
          {
            manufacturerId: "m3",
            produceEntName: "华润双鹤药业股份有限公司",
            specs: [
              { specId: "s4", pkgSpec: "0.25g*24粒/盒" },
              { specId: "s5", pkgSpec: "0.5g*12粒/盒" },
            ],
          },
        ],
      },
      mockProducts: [
        { drugEntBaseInfoId: "p1", physicName: "感冒灵颗粒" },
        { drugEntBaseInfoId: "p2", physicName: "阿莫西林胶囊" },
      ],
    };
  },
  computed: {
    filteredRegions() {
      if (!this.regionSearchText) return this.regions;
      const lower = this.regionSearchText.toLowerCase();
      return this.regions.filter((r) => (r.regionName || r.name || r || "").toString().toLowerCase().indexOf(lower) > -1);
    },
    filteredProducts() {
      const rawProducts = this.products && this.products.length ? this.products : this.mockProducts || [];
      const hasAllOption = rawProducts.some((p) => !p.drugEntBaseInfoId);
      const source = hasAllOption ? rawProducts : [this.allProductOption, ...rawProducts];
      if (!this.productSearchText) return source;
      const lower = this.productSearchText.toLowerCase();
      return source.filter((p) => (p.physicName || "").toLowerCase().indexOf(lower) > -1);
    },
    filteredManufacturers() {
      const source = this.getManufacturerSource();
      if (!this.manufacturerSearchText) return source;
      const lower = this.manufacturerSearchText.toLowerCase();
      return source.filter((m) => (m.produceEntName || "").toLowerCase().includes(lower));
    },
    filteredSpecs() {
      const source = this.getSpecSource();
      if (!this.specSearchText) return source;
      const lower = this.specSearchText.toLowerCase();
      return source.filter((s) => (s.pkgSpec || "").toLowerCase().includes(lower));
    },
    cascaderDisplayText() {
      const productName = this.selectedProduct?.drugEntBaseInfoId ? this.selectedProduct.physicName : "";
      const pkgSpec = this.selectedSpec?.specId ? this.selectedSpec.pkgSpec : "";
      if (productName && pkgSpec) return `${productName}/${pkgSpec}`;
      if (productName) return productName;
      if (pkgSpec) return pkgSpec;
      return "选择药品";
    },
    shouldShowAreaSearch() {
      return this.showAreaSearch !== false && this.showAreaSearch !== "false";
    },
    _tableBodyHeight() {
      if (this.tableBodyHeight) return this.tableBodyHeight;
      return 6 * 80;
    },
    columnList() {
      if (this.params) {
        const type = this.params?.type;
        if (type === "1" || type === "2") return this.columns.filter((i) => i.key !== "selfExaminationRate");
      }
      return this.columns;
    },
  },
  watch: {
    dropdownRegionOpen(val) {
      if (val) {
        this.regionSearchText = "";
        this.initRegionList();
      }
    },
    dropdownOpen(val) {
      if (val) {
        this.productSearchText = "";
        this.initProductList();
      }
    },
    dropdownManufacturerOpen(val) {
      if (val) {
        this.manufacturerSearchText = "";
        this.initManufacturerList();
      }
    },
    dropdownSpecOpen(val) {
      if (val) {
        this.specSearchText = "";
        this.initSpecList();
      }
    },
    product() {
      this.applyInitialFilters();
    },
    drugEntBaseInfoId() {
      this.applyInitialFilters();
    },
    spec() {
      this.applyInitialFilters();
    },
    entName() {
      this.applyInitialFilters();
    },
    regionCode() {
      this.applyInitialFilters();
    },
    regionName() {
      this.applyInitialFilters();
    },
    selectedProduct(val) {
      this.resetFetch();
    },
    region: {
      handler(val) {
        this.resetFetch();
      },
      deep: true,
    },
    params: {
      handler(newVal, oldVal) {
        if (newVal !== oldVal && JSON.stringify(newVal) === JSON.stringify(oldVal)) return;
        this.resetFetch();
      },
      deep: true,
    },
    products: {
      handler(newVal, oldVal) {
        this.applyInitialFilters();
        if (this.dropdownOpen) {
          this.initProductList();
        }
      },
      deep: true,
    },
    regions: {
      handler(newVal, oldVal) {
        this.applyInitialFilters();
        if (this.dropdownRegionOpen) {
          this.initRegionList();
        }
      },
      deep: true,
    },
    entNames: {
      handler() {
        this.applyInitialFilters();
        if (this.dropdownManufacturerOpen) {
          this.initManufacturerList();
        }
      },
      deep: true,
    },
    manufacturer(val) {
      this.resetFetch();
    },
    selectedSpec(val) {
      this.resetFetch();
    },
  },
  created() {
    // this.fetchLoading = false;
    // this.isLoading = false;
    // this.loading = false;
    // this.list =
    //   this.initial && this.initial.length ? this.initial : this.genRows(7);
    // if (this.list.length > this.totalCount) {
    //   this.list = this.list.slice(0, this.totalCount);
    // }
    // if (!this.showHeader) {
    //   this.fetchList();
    // } else {
    //   Promise.all([this.getProviceList(), this.getDrugInfoName()]).then(
    //     () => { }
    //   );
    // }
    this._suppressFetch = true;
    this.applyInitialFilters();
    this._suppressFetch = false;
    this.initProductList();
    this.initManufacturerList();
    this.initSpecList();
    this.fetchList();
  },
  methods: {
    renderCell(item, col) {
      const raw = item[col.key];
      if (raw === undefined || raw === null || raw === "") return "--";
      if (raw === "NA") return "NA";
      const reg = /rate/i;
      if (reg.test(col.key)) {
        const num = Number(raw);
        if (!Number.isFinite(num)) return "--";
        return Math.floor(num) + (col.unit || "");
      }
      return raw;
    },
    initRegionList() {
      this.regionList = this.filteredRegions.slice(0, 10);
    },
    loadMoreRegions(e) {
      if (this.regionList.length >= this.filteredRegions.length) return;
      const currentLen = this.regionList.length;
      const more = this.filteredRegions.slice(currentLen, currentLen + 10);
      this.regionList = this.regionList.concat(more);
    },
    onRegionSearch() {
      this.initRegionList();
    },
    initProductList() {
      this.productList = this.filteredProducts.slice(0, 10);
    },
    loadMoreProducts() {
      if (this.productList.length >= this.filteredProducts.length) return;
      const currentLen = this.productList.length;
      const more = this.filteredProducts.slice(currentLen, currentLen + 10);
      this.productList = this.productList.concat(more);
    },
    onProductSearch() {
      this.initProductList();
    },
    applyInitialFilters() {
      const regionCode = this.regionCode == null ? "" : String(this.regionCode);
      if (regionCode || this.regionName) {
        const region = (this.regions || []).find((item) => String(item.regionCode || "") === regionCode || item.regionName === this.regionName);
        this.region = region || { regionCode: this.regionCode || null, regionName: this.regionName || "全片区" };
      }

      const productName = this.product || "";
      const drugEntBaseInfoId = this.drugEntBaseInfoId == null ? "" : String(this.drugEntBaseInfoId);
      if (productName || drugEntBaseInfoId) {
        const product = this.filteredProducts.find((item) => String(item.drugEntBaseInfoId || "") === drugEntBaseInfoId || item.physicName === productName);
        this.selectedProduct = product || {
          drugEntBaseInfoId: this.drugEntBaseInfoId || null,
          physicName: productName || "全品种",
          pkgSpec: [],
        };
        this.activeProductForSpec = this.selectedProduct;
      }

      if (this.spec) {
        const spec = this.getSpecSource().find((item) => item.pkgSpec === this.spec || String(item.specId || "") === String(this.spec));
        this.selectedSpec = spec || { specId: this.spec, pkgSpec: this.spec };
      }

      if (this.entName) {
        const manufacturer = this.getManufacturerSource().find(
          (item) => item.produceEntName === this.entName || String(item.manufacturerId || "") === this.entName,
        );
        this.manufacturer = manufacturer || { manufacturerId: this.entName, produceEntName: this.entName };
      }
    },
    getManufacturerSource() {
      if (this.entNames && this.entNames.length) {
        return this.entNames.map((item) => ({
          manufacturerId: item.manufacturerId || item.entNameId || item.produceEntName || item.entName || null,
          produceEntName: item.produceEntName || item.entName || String(item),
        }));
      }
      const key = this.selectedProduct.physicName || "";
      const manufacturers = this.mockProductManufacturerSpecMap[key] || [];
      return [this.allManufacturerOption, ...manufacturers];
    },
    getSpecSource() {
      const activeProduct = this.activeProductForSpec || this.selectedProduct;
      if (!activeProduct || !activeProduct.drugEntBaseInfoId) {
        return [this.allSpecOption];
      }
      const specs = (activeProduct.pkgSpec || activeProduct.specs || []).map((item, index) => {
        if (typeof item === "string" || typeof item === "number") {
          return {
            specId: item,
            pkgSpec: String(item),
          };
        }
        const specValue = item.specId || item.pkgSpec || item.pkgSpec || item.pkgpkgSpec || index;
        return {
          ...item,
          specId: specValue,
          pkgSpec: item.pkgSpec || item.pkgpkgSpec || item.pkgSpec || String(specValue),
        };
      });
      return [this.allSpecOption, ...specs];
    },
    initManufacturerList() {
      this.manufacturerList = this.filteredManufacturers.slice(0, 10);
    },
    loadMoreManufacturers() {
      if (this.manufacturerList.length >= this.filteredManufacturers.length) return;
      const currentLen = this.manufacturerList.length;
      const more = this.filteredManufacturers.slice(currentLen, currentLen + 10);
      this.manufacturerList = this.manufacturerList.concat(more);
    },
    onManufacturerSearch() {
      this.initManufacturerList();
    },
    initSpecList() {
      this.specList = this.filteredSpecs.slice(0, 10);
    },
    loadMoreSpecs() {
      if (this.specList.length >= this.filteredSpecs.length) return;
      const currentLen = this.specList.length;
      const more = this.filteredSpecs.slice(currentLen, currentLen + 10);
      this.specList = this.specList.concat(more);
    },
    onSpecSearch() {
      this.initSpecList();
    },
    getUid,
    getSummary(col, ci) {
      if (ci == 0) return "合计";
      const raw = this.summaryData[ci];
      if (raw === undefined || raw === null || raw === "") return "--";
      if (raw === "NA") return "NA";
      const num = Number(raw);
      if (!Number.isFinite(num)) return "--";
      return Math.floor(num) + (col.unit || "");
    },
    closeAllTooltip() {
      this.headerTooltip = {};
    },
    toggleHeaderTooltip(i) {
      const value = !this.headerTooltip[i];
      this.headerTooltip = {};
      this.$set(this.headerTooltip, i, value);
    },
    // getUid(len = 16) {
    //   const ts = Date.now().toString(36);
    //   const rand = Math.random().toString(36).slice(2);
    //   return (ts + rand).slice(0, len);
    // },
    // getProviceList() {
    //   request('/common/getProviceList', {
    //     path: 'customerScanningRate/wigets/ScanRateTable.vue',
    //   }).then(res => {
    //     if (res.code == 200) {
    //       const _data = res.data;
    //       this.regions = _data;
    //       this.region = this.regions[0];
    //     }
    //   })
    // },
    // getDrugInfoName() {
    //   request('/bills/getDrugInfoName', {
    //     path: 'customerScanningRate/wigets/ScanRateTable.vue',
    //   }).then(res => {
    //     if (res.code == 200) {
    //       const _data = res.data;
    //       this.products = _data;
    //       this.product = this.products[0];
    //     }
    //   })
    // },
    toggleDropdown() {
      if (this.fetchLoading) return;
      const next = !this.dropdownOpen;
      if (!next) {
        this.dropdownOpen = false;
        return;
      }
      this.$emit("dropdown-open", this);
      this.$nextTick(() => {
        this.dropdownRegionOpen = false;
        this.dropdownManufacturerOpen = false;
        this.dropdownSpecOpen = false;
        this.dropdownOpen = true;
      });
    },
    toggleDropdownRegion() {
      if (this.fetchLoading) return;
      const next = !this.dropdownRegionOpen;
      if (!next) {
        this.dropdownRegionOpen = false;
        return;
      }
      this.$emit("dropdown-open", this);
      this.$nextTick(() => {
        this.dropdownOpen = false;
        this.dropdownManufacturerOpen = false;
        this.dropdownSpecOpen = false;
        this.dropdownRegionOpen = true;
      });
    },
    toggleDropdownManufacturer() {
      if (this.fetchLoading) return;
      const next = !this.dropdownManufacturerOpen;
      if (!next) {
        this.dropdownManufacturerOpen = false;
        return;
      }
      this.$emit("dropdown-open", this);
      this.$nextTick(() => {
        this.dropdownOpen = false;
        this.dropdownRegionOpen = false;
        this.dropdownSpecOpen = false;
        this.dropdownManufacturerOpen = true;
      });
    },
    toggleDropdownSpec() {
      if (this.fetchLoading) return;
      const next = !this.dropdownSpecOpen;
      if (!next) {
        this.dropdownSpecOpen = false;
        return;
      }
      this.$emit("dropdown-open", this);
      this.$nextTick(() => {
        this.dropdownOpen = false;
        this.dropdownRegionOpen = false;
        this.dropdownManufacturerOpen = false;
        this.dropdownSpecOpen = true;
      });
    },
    selectProduct(type, p) {
      // this.$emit("change-product", p);
      if (type === "product") {
        this.selectedProduct = p;
        this.activeProductForSpec = p;
        this.dropdownOpen = false;
        this.manufacturer = this.allManufacturerOption;
        this.selectedSpec = this.allSpecOption;
        this.manufacturerSearchText = "";
        this.specSearchText = "";
        this.initManufacturerList();
        this.initSpecList();
      } else if (type === "region") {
        this.region = p;
        this.dropdownRegionOpen = false;
      } else if (type === "manufacturer") {
        this.manufacturer = p;
        this.dropdownManufacturerOpen = false;
        this.selectedSpec = this.allSpecOption;
        this.specSearchText = "";
        this.initSpecList();
      } else if (type === "spec") {
        this.selectedSpec = p;
        this.dropdownSpecOpen = false;
      }
      this.emitFilterChange();
    },
    selectCascadeProduct(p) {
      this.activeProductForSpec = p || this.allProductOption;
      this.selectedProduct = this.activeProductForSpec;
      // this.manufacturer = this.allManufacturerOption;
      this.selectedSpec = this.allSpecOption;
      // this.manufacturerSearchText = "";
      this.specSearchText = "";
      this.initManufacturerList();
      this.initSpecList();
      this.emitFilterChange();
    },
    selectCascadeSpec(s) {
      this.selectedProduct = this.activeProductForSpec || this.allProductOption;
      this.selectedSpec = s || this.allSpecOption;
      this.dropdownOpen = false;
      this.emitFilterChange();
    },
    emitFilterChange() {
      this.$emit("filter-change", {
        regionCode: this.region?.regionCode || "",
        regionName: this.region?.regionName || "",
        drugEntBaseInfoId: this.selectedProduct?.drugEntBaseInfoId || "",
        physicName: this.selectedProduct?.physicName === "全品种" ? "" : this.selectedProduct?.physicName || "",
        spkSpec: this.selectedSpec?.pkgSpec === "全规格" ? "" : this.selectedSpec?.pkgSpec || "",
        produceEntName: this.manufacturer?.produceEntName === "全厂家" ? "" : this.manufacturer?.produceEntName || "",
      });
    },
    closeDropdown() {
      this.dropdownOpen = false;
      this.dropdownRegionOpen = false;
      this.dropdownManufacturerOpen = false;
      this.dropdownSpecOpen = false;
    },
    // genRows(n) {
    //   const regions = ["广东", "广西", "湖南", "湖北", "四川", "浙江", "江苏"];
    //   const res = [];
    //   for (let i = 0; i < n; i++) {
    //     const r = regions[i % regions.length];
    //     res.push({
    //       regionName: r,
    //       outScanRate: `${(95 + (i % 5) * 0.5).toFixed(1)}%`,
    //       inScanRate: `${(94 + (i % 5) * 0.6).toFixed(1)}%`,
    //     });
    //   }
    //   return res;
    // },
    onScrollToLower(e) {
      if (e?.detail?.direction === "right") return;
      // if (!Array.isArray(this.list)) this.list = [];
      // if (this.list.length - 1 >= this.totalCount) return;
      // if (this.isLoading) return;
      // this.isLoading = true;
      // const remain = this.totalCount - this.list.length;
      // const toAdd = Math.min(7, remain);
      // setTimeout(() => {
      //   if (this.list.length < this.totalCount) {
      //     const more = this.genRows(toAdd);
      //     this.list = this.list.concat(more);
      //   }
      //   this.isLoading = false;
      // }, 1000);
      this.fetchList();
    },
    resetFetch() {
      if (this._suppressFetch) return;
      this.tablePage = 1;
      this.list = [];
      this.loading = true;
      this.hasmore = true;
      this.fetchList();
    },
    fetchList() {
      if (this._fetchDebounceTimer) clearTimeout(this._fetchDebounceTimer);
      const delay = 500;
      this._fetchDebounceTimer = setTimeout(() => {
        if (!this.hasmore) {
          setTimeout(() => {
            this.fetchLoading = false;
            this.loading = false;
          }, 500);
          return;
        }
        if (this.fetchLoading) return;
        this.fetchLoading = true;
        const params = this.params || {};
        request(this.api, {
          ...params,
          physicName: this.selectedProduct ? (this.selectedProduct?.physicName == "全品种" ? "" : this.selectedProduct?.physicName) : "",
          produceEntName: this.manufacturer ? (this.manufacturer?.produceEntName === "全厂家" ? "" : this.manufacturer?.produceEntName) : "",
          pkgSpec: this.selectedSpec ? (this.selectedSpec?.pkgSpec === "全规格" ? "" : this.selectedSpec?.pkgSpec) : "",
          regionCode: this.region ? this.region?.regionCode || "" : "",
          pageNum: this.tablePage,
          pageSize: params.pageSize || this.tablePageSize,
          path: "customerScanningRate/wigets/ScanRateTable.vue",
        }).then((res) => {
          if (res.code == 200) {
            const _data = res.data || {};
            let pageInfo = _data || {};

            if (this.tableType !== "variety") {
              this.summaryData = [];
              this.summaryData[0] = undefined;
              this.summaryStructure.forEach((item) => {
                this.summaryData.push(_data[item.key] || "--");
              });
              pageInfo = _data?.pageInfo || {};
            }

            const { list, total } = pageInfo;
            this.totalCount = total || 0;
            if (this.list.length >= this.totalCount) {
              this.fetchLoading = false;
              this.hasmore = false;
              this.loading = false;
              return;
            }
            this.list = Array.isArray(list) ? [...this.list, ...list] : [...this.list];
            if (this.list.length < this.totalCount) {
              this.hasmore = true;
              this.tablePage++;
            } else {
              this.hasmore = false;
            }
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
            // this.list.push(this.list[0]);
          }
          this.fetchLoading = false;
          this.loading = false;
        });
      }, delay);
    },
    headerCellStyle(ci, col) {
      const base = this.cellBaseStyle(ci, col);
      base.height = this.cellHeight;
      base.fontSize = this.headerFontSize;
      base.position = "sticky";
      base.zIndex = 2;
      base.top = "0rpx";
      base.background = "#eaf2ff";
      // base.display = 'flex';
      // base.alignItems = 'center';
      // base.justifyContent = 'center';
      if (ci === 0) {
        base.zIndex = 3;
      }
      if (col.fixed) {
        base.left = this.stickyLeft(ci);
      }
      return base;
    },
    bodyCellStyle(ci, col) {
      const base = this.cellBaseStyle(ci, col);
      // base.lineHeight = this.cellHeight;
      base.padding = "12rpx";
      base.fontSize = this.bodyFontSize;
      if (this.bodyFontColor) {
        base.color = this.bodyFontColor;
      }
      if (col.fixed) {
        base.position = "sticky";
        base.left = this.stickyLeft(ci);
        base.zIndex = 2;
      }
      return base;
    },
    cellBaseStyle(ci, col) {
      const style = {};
      // style.height = this.cellHeight;
      if (col && col.width) {
        style.width = col.width;
        style.flex = `0 0 ${col.width}`;
      } else {
        style.flex = 1;
      }
      return style;
    },
    stickyLeft(ci) {
      const parts = [];
      for (let i = 0; i < ci; i++) {
        const c = this.columns[i];
        if (c && c.fixed && c.width) parts.push(c.width);
      }
      if (!parts.length) return "0rpx";
      if (parts.length === 1) return parts[0];
      return `calc(${parts.join(" + ")})`;
    },
    isPlainTitle(t) {
      return typeof t === "string" ? t.indexOf("<") === -1 : true;
    },
    titleNodes(t) {
      if (typeof t !== "string") return t;
      let html = String(t);
      html = html.replace(/<\s*view/g, "<div").replace(/<\/\s*view\s*>/g, "</div>");
      html = html.replace(/:style=\"\{\s*textAlign:\s*'center'\s*\}\"/g, 'style="text-align:center;"');
      return html;
    },
    handleClick(data, col) {
      if (this.tableType === "variety" || this.tableType === "customerDetail" || col.key !== "regionName") return;
      const drugEntBaseInfoId = this.selectedProduct?.drugEntBaseInfoId || data.drugEntBaseInfoId || data.druGentBaseInfoId || "";
      const physicName = this.selectedProduct?.physicName || "";
      const spkSpec = this.selectedSpec?.pkgSpec || "";
      const produceEntName = this.manufacturer?.produceEntName || "";
      uni.navigateTo({
        url:
          "/traceCodePackages/traceabilityReport/pages/customerScanningRate/detail/index?regionCode=" +
          data.regionCode +
          "&regionName=" +
          encodeURIComponent(data.regionName) +
          "&drugEntBaseInfoId=" +
          encodeURIComponent(drugEntBaseInfoId) +
          "&physicName=" +
          encodeURIComponent(physicName) +
          "&spkSpec=" +
          encodeURIComponent(spkSpec) +
          "&produceEntName=" +
          encodeURIComponent(produceEntName) +
          "&scanType=" +
          this.scanType +
          (this.params.type ? "&type=" + this.params.type : ""),
      });
    },
  },
};
</script>

<style scoped>
.section {
  margin-top: 24rpx;
  transform: translate3d(0, 0, 0);
  overflow: visible;
}

.section-header {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 8rpx 8rpx;
  overflow: visible;
  z-index: 95;
}

.noAreaHeader {
  flex-direction: row;
  align-items: center;
}

.section-title-row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.section-title {
  position: relative;
  font-size: 30rpx;
  font-weight: bold;
  color: #2c69ff;
}

.section-title::after {
  content: "";
  position: absolute;
  left: -20rpx;
  bottom: 13rpx;
  width: 8rpx;
  height: 50%;
  background: #2c69ff;
  border-radius: 10px;
}

.selector-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 40rpx;
  flex-wrap: nowrap;
  overflow: visible;
  justify-content: flex-end;
}

.selector-wrap {
  position: relative;
  flex-shrink: 0;
  z-index: 96;
}

.selector {
  position: relative;
  display: flex;
  align-items: center;
  color: #2c69ff;
  padding-right: 30rpx;
}

.selector-text {
  font-size: 30rpx;
  max-width: 160rpx;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  display: inline-block;
}

.selector-arrow {
  position: absolute;
  right: 0rpx;
  bottom: 14rpx;
  font-size: 30rpx;
  display: inline-block;
  width: 15rpx;
  height: 15rpx;
  border: 5rpx solid #2c69ff;
  border-top: none;
  border-left: none;
  transform-origin: 50% 50%;
  transform: rotate(45deg);
  transition: transform 0.2s;
}

.selector-arrow.open {
  bottom: 7rpx;
  transform: rotate(225deg);
}

.dropdown {
  position: absolute;
  left: 0rpx;
  top: 54rpx;
  width: 310rpx;
  max-height: 380rpx;
  background: #fff;
  border: 1rpx solid #eef0f4;
  border-radius: 12rpx;
  box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
  z-index: 999;
  overflow: hidden;
}

.cascader-dropdown {
  left: -84%;
  right: auto;
  width: 560rpx;
  max-width: calc(100vw - 48rpx);
  max-height: 460rpx;
  transform: translateX(-50%);
}

.cascader-search-row {
  display: flex;
  width: 100%;
}

.cascader-search {
  flex: 1;
  box-sizing: border-box;
}

.cascader-body {
  display: flex;
  width: 100%;
}

.cascader-col {
  width: 50%;
  max-height: 320rpx;
}

.cascader-col-right {
  border-left: 1rpx solid #f0f2f5;
  box-sizing: border-box;
}

.dropdown-search-bar {
  padding: 10rpx;
  border-bottom: 1rpx solid #f0f2f5;
  background: #fff;
  z-index: 94;
}

.dropdown-search-input {
  width: 100%;
  height: 60rpx;
  background: #f5f7fa;
  border-radius: 8rpx;
  padding: 0 20rpx;
  font-size: 28rpx;
  box-sizing: border-box;
}

.dropdown-scroll-view {
  flex: 1;
  width: 100%;
  max-height: 260rpx;
  /* Adjusted height to fit search bar */
  overflow-y: auto;
}

.cascader-body .cascader-col {
  flex: 0 0 50%;
  width: 50%;
  max-height: 320rpx;
}

.dropdown-item {
  padding: 16rpx 24rpx;
  font-size: 28rpx;
  color: #333;
  text-wrap: wrap;
}

.dropdown-item + .dropdown-item {
  border-top: 1rpx solid #f0f2f5;
}

.table-scroll-x {
  position: relative;
  margin-top: 12rpx;
  width: 100%;
  min-height: 120rpx;
  border-radius: 16rpx;
  overflow: visible;
}

.card {
  background: #fff;
  font-size: 32rpx;
}

.table-header {
  display: flex;
  background: #eaf2ff;
  font-weight: bold;
  color: #2c69ff;
  border-top-left-radius: 16rpx;
  border-top-right-radius: 16rpx;
}

/* .table-body {
  margin-top: 8rpx;
} */
.row {
  display: flex;
  align-items: stretch;
  border-bottom: 1rpx solid #eef0f4;
}

.row:last-child,
.row:nth-last-child(2) {
  border-bottom: none;
}

.loading-row {
  justify-content: flex-start;
}

.loading-wrapper {
  width: calc(100vw - 60rpx);
  height: 76rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  position: sticky;
  top: 50%;
  left: 0;
}

.loading-icon {
  width: 40rpx;
  height: 40rpx;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

.cell {
  flex: 1;
  box-sizing: border-box;
  width: 0;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  /* text-align: center; */
  word-break: break-all;
}

.table-body .cell {
  background-color: #fff;
  text-align: center;
}

.table-body .striped {
  background: #f7f7f7;
}

.underline {
  text-decoration: underline;
  color: #2c69ff;
}

/* hide scrollbars for H5/App while preserving scroll behavior */
.no-scrollbar {
  position: relative;
  -ms-overflow-style: none;
  scrollbar-width: none;
  z-index: 2;
}

::v-deep .no-scrollbar::-webkit-scrollbar {
  display: none !important;
  width: 0 !important;
  height: 0 !important;
  -webkit-appearance: none;
  background: transparent;
}

.header-tooltip-wrap {
  position: absolute;
  top: 60rpx;
  right: 0rpx;
  z-index: 93;
}

.header-tooltip {
  background: #000;
  color: #fff;
  border-radius: 8rpx;
  padding: 8rpx 12rpx;
  font-size: 24rpx;
  width: 270rpx;
}

.header-tooltip-arrow {
  position: absolute;
  top: -11rpx;
  right: 20rpx;
  width: 0;
  height: 0;
  border-left: 10rpx solid transparent;
  border-right: 10rpx solid transparent;
  border-bottom: 12rpx solid #000;
  margin: 0 auto;
}

.no-data-placeholder {
  opacity: 0;
}

.no-data {
  position: absolute;
  top: 76rpx;
  left: 0;
  width: 100%;
  z-index: 1;
}
</style>
