<template>
  <view class="home2" v-if="loading">
    <!-- ===== 顶部红色头区（状态栏 + 定位 + 搜索 + 分类条） ===== -->
    <view class="hd" :style="{ paddingTop: top + 'px' }">
      <!-- 定位 -->
      <view class="hd-loc" @tap="map">
        <image class="hd-loc-icon" src="https://static.hshuishang.com/Index_add.png" mode="widthFix" />
        <text class="hd-loc-txt">{{ currentCity.cityName || '选择城市' }}</text>
        <text class="hd-loc-arrow">▾</text>
      </view>

      <!-- 搜索框（新增，本轮仅 UI + 占位，后台好店搜索接口回头接入 handleSearch） -->
      <view class="hd-search">
        <image class="hd-search-icon"
          src="https://static.hshuishang.com/property-img-file/com_communitySearchIcon.png" mode="aspectFill" />
        <input class="hd-search-input" v-model="keyword" :placeholder="searchPlaceholder"
          confirm-type="search" @confirm="handleSearch" />
        <view class="hd-search-btn" @tap="handleSearch">搜索</view>
      </view>

    </view>

    <!-- ===== 主体（白底圆角上浮） ===== -->
    <view class="bd">
      <!-- 轮播图 -->
      <view class="banner" v-if="isRecommend && bannerList.length">
        <swiper class="banner-swiper" @animationfinish="swipers" autoplay circular>
          <swiper-item v-for="(item, index) in bannerList" :key="index" @click="handleAdClick(item)">
            <image class="banner-img" :src="item.pic_src" mode="aspectFill" />
          </swiper-item>
        </swiper>
        <view class="banner-dots">
          <view :class="['dot', currentIdx == index ? 'on' : '']" v-for="(item, index) in bannerList" :key="index">
          </view>
        </view>
      </view>

      <!-- 金刚区（自绘 flex 布局，间距完全可控，不用 u-grid 以免组件自带底部空间） -->
      <view class="grid" v-if="isRecommend && tabList.length">
        <view class="grid-item" :style="{ width: (100 / (rowNum || 5)) + '%' }"
          v-for="(item, index) in tabList" :key="index" @tap="headerServerClick(item)">
          <image class="grid-icon" :src="item.icon_src" mode="aspectFill"></image>
          <text class="grid-txt">{{ item.title }}</text>
        </view>
      </view>

      <!-- 广告栏：固定三格（左大 + 右上 + 右下），空位显示招商占位 -->
      <view class="ads" v-if="isRecommend">
        <view class="ads-left">
          <image v-if="isRealAd(serverLeftList[0])" :src="serverLeft" mode="aspectFill"
            @tap="handleAdClick(serverLeftList[0])" />
          <view v-else class="ad-ph">广告招商中</view>
        </view>
        <view class="ads-right">
          <view class="ads-right-item" v-for="(item, index) in serverRightList" :key="index">
            <image v-if="isRealAd(item)" :src="item.pic_src" mode="aspectFill" @tap="handleAdClick(item)" />
            <view v-else class="ad-ph">广告招商中</view>
          </view>
        </view>
      </view>

      <!-- 好店列表标题 -->
      <view class="wf-title" v-if="isRecommend">
        <!--view class="wf-title-main">
          <text class="wf-title-loc" v-if="currentCity.district">{{ currentCity.district }}</text>
          附近好店
        </view>
        <view class="wf-title-tag">一刻钟便利生活圈</view-->
      </view>

      <!-- 分类条：移到瀑布上方，上滑时吸顶(top=页头高度)，仅瀑布在其下滚动 -->
      <scroll-view scroll-x class="hd-cate" v-if="categoryList.length" :style="{ top: cateTop + 'px' }">
        <view class="hd-cate-item" :class="{ on: currentTab === 'recommend' }" @tap="selectRecommend">附近</view>
        <!-- 分类条改用商家分类表数据(categoryList)，与下方好店(merchant_cate_id)一一对应 -->
        <view class="hd-cate-item" v-for="(item, index) in categoryList" :key="index"
          :class="{ on: currentTab === item.id }" @tap="selectCircle(item)">
          {{ item.cate_name }}
        </view>
        <view class="hd-cate-item" @tap="goMoreLocalLife">更多</view>
      </scroll-view>

      <!-- 好店瀑布（两列，图片按原始宽高比制造瀑布效果） -->
      <view class="wf">
        <view class="wf-col">
          <view class="wf-card" v-for="item in leftCol" :key="item.id" @click="Info(item)">
            <image class="wf-img" :src="item.showImg" :style="{ height: item.imgH + 'rpx' }" mode="aspectFill" />
            <view class="wf-meta">
              <view class="wf-name">{{ item.merchant_name }}</view>
              <view class="wf-sub">
                <view class="wf-stars">
                  <image v-for="i in 5" :key="i" :src="i < item.rating
                    ? 'https://static.hshuishang.com/property-img-file/local_start1.png'
                    : 'https://static.hshuishang.com/property-img-file/local_start2.png'" mode="aspectFill"></image>
                </view>
                <text class="wf-dist">{{ item.distances }}</text>
              </view>
              <view class="wf-tags">
                <text class="wf-tag" v-if="item.refund_property_fee_ratio">买单返岁银</text>
                <text class="wf-tag" v-if="item.refund_user_points_ratio">买单返积分</text>
              </view>
              <view class="wf-addr">{{ item.comAddress }}</view>
            </view>
          </view>
        </view>
        <view class="wf-col">
          <view class="wf-card" v-for="item in rightCol" :key="item.id" @click="Info(item)">
            <image class="wf-img" :src="item.showImg" :style="{ height: item.imgH + 'rpx' }" mode="aspectFill" />
            <view class="wf-meta">
              <view class="wf-name">{{ item.merchant_name }}</view>
              <view class="wf-sub">
                <view class="wf-stars">
                  <image v-for="i in 5" :key="i" :src="i < item.rating
                    ? 'https://static.hshuishang.com/property-img-file/local_start1.png'
                    : 'https://static.hshuishang.com/property-img-file/local_start2.png'" mode="aspectFill"></image>
                </view>
                <text class="wf-dist">{{ item.distances }}</text>
              </view>
              <view class="wf-tags">
                <text class="wf-tag" v-if="item.refund_property_fee_ratio">买单返岁银</text>
                <text class="wf-tag" v-if="item.refund_user_points_ratio">买单返积分</text>
              </view>
              <view class="wf-addr">{{ item.comAddress }}</view>
            </view>
          </view>
        </view>
      </view>

      <view class="wf-more" v-if="merchantHasMore">上拉加载更多</view>
      <view class="wf-more" v-else-if="leftCol.length || rightCol.length">没有更多了</view>

      <nav-footer :current="0" />
    </view>
  </view>
</template>

<script>
import {
  NavgateTo,
  calculateDistance,
} from '../../utils/index';

import {
  util,
  picUrl,
  request,
  menuButtonInfo
} from '../../utils/index.js';
import {
  apiArr
} from '../../api/community.js';
import {
  apiArr as apiArr2
} from '../../api/v2Home.js'

import nav from '../../components/nav/nav';

// 首页广告位常量（对应后台 home_banner_region.ad_position），与旧首页保持一致
const AD_POS = {
  TOP_BANNER: 1,        // 顶部轮播
  CARD_LEFT: 2,         // 广告栏左（大图）
  CARD_RIGHT_TOP: 3,    // 广告栏右上
  CARD_RIGHT_BOTTOM: 4, // 广告栏右下
  MID_LEFT: 5,          // 中部广告位左
  MID_CENTER_TOP: 6,    // 生活圈：中部中上
  MID_CENTER: 7,        // 生活圈：中部中
  MID_CENTER_BOTTOM: 8, // 生活圈：中部中下
  MID_RIGHT_TOP: 9,     // 生活圈：中部右上
  MID_RIGHT_CENTER: 10, // 生活圈：中部右中
  MID_RIGHT_BOTTOM: 11, // 生活圈：中部右下
  POPUP: 12,
  BOTTOM_RECOMMEND: 13,
};

// 瀑布单列图片宽度（rpx）：页面左右各 20rpx 内边距 + 两列间距 20rpx → (750-60)/2 = 345
const WF_COL_W = 345;
// 卡片图片下方文字区的估算高度（rpx），仅用于两列高度均衡，不影响真实布局
const WF_META_H = 150;

export default {
  components: { nav },
  data() {
    return {
      loading: false,
      top: 0,
      localHeight: 44,
      cateTop: 0,             // 分类条吸顶位置 = 页头(.hd)高度(px)

      currentCity: '',        // 定位信息
      qqmap_key: '',

      keyword: '',            // 搜索关键字（本轮仅占位）
      hotWord: [],            // 搜索热词（取第一条做 placeholder）

      currentIdx: 0,
      bannerList: [],         // 轮播图（位1）
      tabList: [],            // 金刚区
      rowNum: 0,
      colNum: 0,

      // 广告栏（位2 / 位3 / 位4）
      serverLeft: '',
      serverLeftList: [],
      serverRightList: [],

      // 分类条：生活圈（位6-11）
      currentTab: 'recommend', // 当前分类条选中项：'recommend' 或某生活圈标题

      // 分类（驱动好店列表）
      categoryList: [],
      currentCategoryId: null,

      // 好店瀑布
      page_num: 1,
      page_size: 10,
      leftCol: [],
      rightCol: [],
      colHeights: [0, 0],
      merchantHasMore: false,
      loadingMore: false,

      _bannerGroups: null,
    }
  },

  computed: {
    searchPlaceholder() {
      return this.hotWord && this.hotWord.length ? this.hotWord[0] : '搜索好店 / 商家 / 优惠'
    },
    // 仅「附近」页展示轮播/金刚区/广告栏等；选中具体生活圈时只留瀑布列表
    isRecommend() {
      return this.currentTab === 'recommend'
    }
  },

  methods: {
    /* ---------- 顶部/通用 ---------- */
    map() {
      uni.navigateTo({ url: '/pages/shopcity/shopcity' });
    },

    // 搜索：本轮仅占位。后台好店搜索接口接入后，这里改为按 keyword 过滤 getMechantList。
    handleSearch() {
      const kw = (this.keyword || '').trim()
      // TODO: 接后台好店关键字搜索接口（给 getMerchantList 增加 keyword 参数）
      uni.showToast({
        title: kw ? `搜索「${kw}」功能即将开放` : '请输入关键字',
        icon: 'none'
      })
    },

    swipers(e) {
      this.currentIdx = e.detail.current
    },

    NotOpen() {
      uni.showModal({ title: '提示', content: '此功能暂未开通！', showCancel: false, complete: () => { } })
    },

    // 统一广告点击：按后台 promotion_type 分发（与旧首页一致）
    handleAdClick(item) {
      if (!item) return
      switch (item.promotion_type) {
        case 3:
          if (!item.link_url) return this.NotOpen()
          if (item.link_url === '/packages/shopEnter/index/index') return this.headershopEnterClick()
          return NavgateTo(item.link_url, { isLogin: false })
        case 4:
          if (!item.appid) return this.NotOpen()
          return uni.navigateToMiniProgram({ appId: item.appid, path: item.link_url || '', envVersion: 'release' })
        case 5:
          return NavgateTo('/packages/advertising/index/index?id=' + item.id, { isLogin: false })
        case 1:
        default:
          return this.NotOpen()
      }
    },

    // 金刚区点击（与旧首页 headerServerClick 一致）
    headerServerClick(e) {
      if (!e.link_url) return this.NotOpen()
      if (e.link_url === '/packages/shopEnter/index/index') return this.headershopEnterClick()
      // #ifdef APP-PLUS
      uni.navigateTo({ url: '/pages/webview/webview?url=' + encodeURIComponent(e.link_url) });
      // #endif
      // #ifdef H5
      window.open(e.link_url, '_blank');
      // #endif
      // #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU
      if (e.appid) {
        uni.navigateToMiniProgram({ appId: e.appid, path: e.link_url, extraData: { data1: 'test' } })
      } else {
        NavgateTo(e.link_url, { isLogin: false })
      }
      // #endif
    },

    // 「附近」对应的分类 id：取商家分类表第一个
    recommendCateId() {
      return this.categoryList.length ? this.categoryList[0].id : null
    },

    // 点击「附近」：显示默认(第一个)分类内容
    async selectRecommend() {
      this.currentTab = 'recommend'
      const id = this.recommendCateId()
      if (id) await this.switchCategory(id)
    },

    // 点击某商家分类：显示该分类对应的好店瀑布(merchant_cate_id = 该分类 id)
    async selectCircle(item) {
      this.currentTab = item.id
      await this.switchCategory(item.id)
    },

    // 「更多」：进入本地生活完整列表
    goMoreLocalLife() {
      NavgateTo('/packages/localLife/index/index', { isLogin: false })
    },

    async headershopEnterClick() {
      if (!uni.getStorageSync('userId')) {
        return NavgateTo('/packages/shopEnter/choose/index', { isLogin: false })
      }
      const res = await request(apiArr2.statusQuery, 'POST', {}, { silent: false })
      if (res.status) {
        NavgateTo('/packages/shopEnter/auditStatus/index?itemObj=' + JSON.stringify(res))
      } else {
        NavgateTo('/packages/shopEnter/choose/index')
      }
    },

    /* ---------- 定位 + 首屏取数 ---------- */
    init() {
      uni.showLoading({ title: '加载中', mask: true })
      this.qqmap_key = '55NBZ-MUQYW-EAJRL-YIWPA-ZXCR6-4NBPP'
      this.getUserLocation()
    },

    getUserLocation() {
      const that = this
      const { qqmap_key } = this
      const userlocat = uni.getStorageSync('location')
      uni.getLocation({
        type: 'wgs84',
        success: (res) => {
          const latitude = userlocat ? userlocat.lat : res.latitude
          const longitude = userlocat ? userlocat.lng : res.longitude
          uni.request({
            url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=${qqmap_key}&get_poi=0`,
            success: async (r) => {
              const { data: { result: { address_component, ad_info } } } = r
              const preciseLocation = {
                cityName: address_component.city,
                region: address_component.province + address_component.city + address_component.district,
                district: address_component.district + `${address_component.street_number ? address_component.street_number : address_component.street}`,
                address: address_component.city + address_component.district + address_component.street_number,
                lat: latitude,
                lng: longitude,
              }
              that.currentCity = preciseLocation
              uni.setStorageSync('location', preciseLocation)
              uni.setStorageSync('ad_code', ad_info.adcode)

              // 一次拉取各广告位（1-11），后续各 getHomeXxx 读缓存
              await this.prefetchBannerGroups()
              const [bannerList, serverLeft, serverRightList, tabList] = await Promise.all([
                this.getHomeBanner(),
                this.getServerLeft(),
                this.getServerRight(),
                this.getButtonNum(),    // 金刚区
              ])
              this.bannerList = bannerList
              this.serverLeft = serverLeft
              this.serverRightList = serverRightList
              this.tabList = tabList

              // 先渲染首屏（轮播/金刚/广告/分类条），好店瀑布再异步加载填充，
              // 避免整页等待瀑布——与原主页一致（原页 loading=true 后才单独加载好店列表）。
              this.loading = true
              uni.hideLoading()
              this.$nextTick(() => setTimeout(() => this.measureLayout(), 60))  // 量测吸顶高度 + 对齐金刚区上下间距
              this.getCateList().catch(e => console.warn('好店分类/瀑布加载失败:', e))  // 异步：拉分类 + 加载首个分类的好店瀑布
            },
            fail: (err) => {
              console.warn('地图API解析地址失败:', err)
              uni.showToast({ title: '定位失败，请检查网络', icon: 'none' })
              uni.hideLoading()
            }
          })
        },
        fail: (err) => {
          console.warn('获取位置信息失败:', err)
          if (err.errMsg && err.errMsg.indexOf('auth deny') >= 0) {
            uni.showModal({
              title: '提示', content: '需要您授权位置信息才能使用此功能', confirmText: '去授权',
              success: (res) => {
                if (res.confirm) {
                  // #ifdef MP-WEIXIN
                  wx.openSetting();
                  // #endif
                  // #ifdef APP-PLUS
                  uni.openSetting();
                  // #endif
                }
                uni.hideLoading()
              }
            })
          } else {
            uni.showToast({ title: '定位失败，请重试', icon: 'none' })
            uni.hideLoading()
          }
        }
      })
    },

    /* ---------- 广告位取数（沿用旧首页逻辑） ---------- */
    async prefetchBannerGroups(positions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) {
      try {
        const res = await request(apiArr2.getHomeBannerMulti, 'POST', {
          ad_code: Number(uni.getStorageSync('ad_code')),
          ad_positions: positions,
          longitude: uni.getStorageSync('location').lng,
          latitude: uni.getStorageSync('location').lat,
          page_size: 50
        }, { silent: false })
        this._bannerGroups = (res && res.groups) ? res.groups : {}
      } catch (e) {
        console.warn('批量拉取首页广告失败，回退逐个请求:', e)
        this._bannerGroups = null
      }
    },

    async getBannerRows(position) {
      if (this._bannerGroups) {
        return this._bannerGroups[String(position)] || []
      }
      const res = await request(apiArr2.getHomeBanner, 'POST', {
        ad_code: uni.getStorageSync('ad_code'),
        ad_position: position,
        longitude: uni.getStorageSync('location').lng,
        latitude: uni.getStorageSync('location').lat,
        page_num: 1,
        page_size: 50
      }, { silent: false })
      return (res && res.rows) ? res.rows : []
    },

    withPicUrl(list) {
      list.forEach(item => { item.pic_src = picUrl + item.pic_src })
      return list
    },

    filterShowList(list, type) {
      if (list && list.length) return list.filter(item => item.show_status == type)
      return []
    },

    async getBannerAt(position, { placeholder = false } = {}) {
      const rows = await this.getBannerRows(position)
      const [first] = this.withPicUrl(this.filterShowList(rows, 1))
      if (first) return first
      return placeholder ? { ad_position: position, pic_src: '' } : null
    },

    async getBannersAt(positions, opts) {
      return Promise.all(positions.map(p => this.getBannerAt(p, opts)))
    },

    async getHomeBanner() {
      const rows = await this.getBannerRows(AD_POS.TOP_BANNER)
      return this.withPicUrl(this.filterShowList(rows, 1))
    },

    // 广告栏固定三格：左大(位2) + 右上(位3) + 右下(位4)。
    // 某位无「已发布且在投放期」广告时用占位对象补齐，保证版式始终是设计稿的三格。
    async getServerLeft() {
      const item = await this.getBannerAt(AD_POS.CARD_LEFT, { placeholder: true })
      this.serverLeftList = [item]
      return item ? item.pic_src : ''
    },

    async getServerRight() {
      // placeholder:true → 始终返回两格（空位为占位对象，pic_src 为空串）
      return this.getBannersAt([AD_POS.CARD_RIGHT_TOP, AD_POS.CARD_RIGHT_BOTTOM], { placeholder: true })
    },

    // 是否为真实可点广告（有图）；占位格不可点
    isRealAd(item) {
      return !!(item && item.pic_src)
    },

    /* ---------- 金刚区 ---------- */
    async getButtonNum() {
      const res = await request(apiArr2.getButtonNum, 'POST', {}, { slice: false })
      this.rowNum = res.nav_row_num
      this.colNum = res.nav_row_total
      return await this.getHomeButton()
    },

    async getHomeButton() {
      const res = await request(apiArr2.getHomeButton, 'POST', {
        ad_code: Number(uni.getStorageSync('ad_code')),
        page_num: 1,
        page_size: 50
      }, { slice: false })
      const filterRes = this.filterShowList(res?.rows, 1)
      const newList = filterRes.slice(0, this.rowNum * this.colNum)
      if (newList.length) {
        newList.forEach(item => { item.icon_src = picUrl + item.icon_src })
        return newList
      }
      return []
    },

    /* ---------- 分类 + 好店瀑布 ---------- */
    async getCateList() {
      const res = await request(apiArr2.getCateList, 'POST', { isShop: 1 }, { slice: false })
      if (res.rows && res.rows.length) {
        this.categoryList = res.rows
        // 默认选中「附近」，内容暂取美食圈
        this.currentTab = 'recommend'
        this.currentCategoryId = this.recommendCateId() || res.rows[0].id
        await this.getMechantList(true)
      } else {
        this.categoryList = []
      }
    },

    async switchCategory(id) {
      if (this.currentCategoryId === id) return
      this.currentCategoryId = id
      await this.getMechantList(true)
      // 不再强制滚动：分类条常驻吸顶，切换时保持用户当前位置，避免突兀的自动滚动
    },

    // reset=true 表示重新加载（换分类/下拉刷新）；否则为触底追加
    async getMechantList(reset = false) {
      if (this.loadingMore) return
      this.loadingMore = true
      if (reset) {
        this.page_num = 1
        this.leftCol = []
        this.rightCol = []
        this.colHeights = [0, 0]
      }
      try {
        const res = await request(apiArr2.getMerchantList, 'POST', {
          merchant_cate_id: this.currentCategoryId,
          page_num: this.page_num,
          page_size: this.page_size,
        })
        const latitude = uni.getStorageSync('location').lat
        const longitude = uni.getStorageSync('location').lng
        const rows = (res && res.rows) ? res.rows : []
        rows.forEach((item) => {
          item.bigImg = item.album_images?.split(',')
          item.showImg = item.album_images ? picUrl + item.album_images.split(',')[0] : ''
          const distanceInKm = calculateDistance(latitude, longitude, item.latitude, item.longitude)
          item.distances = distanceInKm >= 1
            ? `${distanceInKm.toFixed(1)}km`
            : `${(distanceInKm * 1000).toFixed(1)}m`
          item.comAddress = item.ad ? item.ad.ad_name.replace(/,/g, '') + item.address : item.address
        })
        // 就近排序
        rows.sort((a, b) => {
          const va = parseFloat(a.distances) * (a.distances.includes('km') ? 1000 : 1)
          const vb = parseFloat(b.distances) * (b.distances.includes('km') ? 1000 : 1)
          return va - vb
        })

        this.merchantHasMore = rows.length === this.page_size
        if (this.merchantHasMore) this.page_num++

        await this.appendMasonry(rows)
      } catch (e) {
        console.warn('好店列表加载失败:', e)
      } finally {
        this.loadingMore = false
      }
    },

    // 并行量图（并发比串行快很多）→ 按两列累计高度均衡分列，避免一列过长、另一列底部大片留白。
    // 图片仍 mode="widthFix" 自适应显示；此处测量仅用于分列均衡。
    async appendMasonry(rows) {
      const ratios = await Promise.all(rows.map(item => new Promise(resolve => {
        if (!item.showImg) return resolve(0.8)
        uni.getImageInfo({
          src: item.showImg,
          success: info => resolve(info && info.width ? info.height / info.width : 0.8),
          fail: () => resolve(0.8)
        })
      })))
      rows.forEach((item, i) => {
        item.imgH = Math.round(WF_COL_W * ratios[i])   // 显式高度，即时到位不回流
        const target = this.colHeights[0] <= this.colHeights[1] ? 0 : 1
        if (target === 0) this.leftCol.push(item)
        else this.rightCol.push(item)
        this.colHeights[target] += item.imgH + WF_META_H
      })
    },

    // 量测页头真实高度，供分类条吸顶定位
    measureLayout() {
      uni.createSelectorQuery().in(this)
        .select('.hd').boundingClientRect(rect => {
          if (rect && rect.height) this.cateTop = Math.round(rect.height)
        }).exec()
    },

    Info(e) {
      uni.setStorageSync('merchantInfo', e)
      NavgateTo('/packages/localLife/detail/index', { isLogin: false })
    },

    async getSearchVal() {
      try {
        const res = await request(apiArr.hotWord, 'POST', {}, { slice: false })
        this.hotWord = res.search_hot_word ? res.search_hot_word.split(/[,，]/) : []
      } catch (e) { this.hotWord = [] }
    },
  },

  onLoad() {
    const menu = menuButtonInfo()
    this.top = menu.top
    this.localHeight = menu.height
    // 分类条吸顶位置 = 页头高度：状态栏 top(px) + 页头内容(定位64+搜索8+72+下内边距20=164rpx)换算 px
    const sys = uni.getSystemInfoSync()
    this.cateTop = Math.round(this.top + 164 * sys.windowWidth / 750)
    this.init()
    this.getSearchVal()
  },
  onReady() {
    // 用真实渲染高度校正吸顶位置（估算可能有偏差）
    this.$nextTick(() => {
      uni.createSelectorQuery().in(this).select('.hd').boundingClientRect(rect => {
        if (rect && rect.height) this.cateTop = Math.round(rect.height)
      }).exec()
    })
  },

  onShow() {
    const storageLocation = uni.getStorageSync('location')
    if (storageLocation && this.loading) {
      // 仅当定位城市/区域「真正变化」时才重新初始化。
      // 注意：不能拿 currentCity.address 和 storageLocation.district 比（两者是不同字段，
      // 几乎恒为不等），否则每次返回首页都会重载 → 回到顶部、丢失当前分类，体验很差。
      const changed = !this.currentCity ||
        this.currentCity.cityName !== storageLocation.cityName ||
        this.currentCity.district !== storageLocation.district
      if (changed) {
        this.currentCity = storageLocation
        this.init()
      }
    }
  },

  onPullDownRefresh() {
    this.init()
    uni.stopPullDownRefresh()
  },

  async onReachBottom() {
    if (this.merchantHasMore && !this.loadingMore) {
      await this.getMechantList(false)
    }
  }
}
</script>

<style>
@import url("./index2.css");
</style>
