cloudroam
12 小时以前 500078714411487af00161e01bd7e0b5efdc3414
add:热门景点
已修改2个文件
已添加5个文件
931 ■■■■■ 文件已修改
pages.json 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
static/common/item-films.png 补丁 | 查看 | 原始文档 | blame | 历史
static/common/item-map.png 补丁 | 查看 | 原始文档 | blame | 历史
static/common/item-route.png 补丁 | 查看 | 原始文档 | blame | 历史
sub-pages/hot-city/hot-city-detail.vue 375 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sub-pages/hot-city/index.vue 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json
@@ -86,6 +86,25 @@
                    }
                }
            ]
        },
        {
            "root": "sub-pages/hot-city",
            "pages": [
                {
                    "path": "index",
                    "style": {
                        "navigationBarTitleText": "城市",
                        "enablePullDownRefresh": true
                    }
                }
                ,{
                    "path": "hot-city-detail",
                    "style": {
                        "navigationBarTitleText": "城市详情",
                        "enablePullDownRefresh": true
                    }
                }
            ]
        }
        ,{
            "root": "sub-pages/mine",
pages/home/home.vue
@@ -23,7 +23,7 @@
      </view>
      <view class="trip-card-swiper">
        <swiper :current="currentPage" @change="onSwiperChange" circular style="min-height: 1850rpx;">
        <swiper :current="currentPage" @change="onSwiperChange" circular style="min-height: 1650rpx;">
          <swiper-item v-for="(group, pageIndex) in pagedTripCards" :key="pageIndex">
            <TripCard v-for="(item, index) in group" :key="index" :tag="item.tag" :title="item.coverTitle"
              :subtitle="item.coverAlt" :score="item.collectCount" :imageUrl="item.coverUrl"
@@ -32,8 +32,34 @@
        </swiper>
      </view>
<!--      <SectionTitle title="全球影视地标" optitle="查看全部" goUrl="/pages/home/home-more" />-->
      <SectionTitle title="全球影视地标" optitle="查看全部" goUrl="/pages/home/home-more" />
<!--      <GlobalGeo />-->
      <view class="continent-section">
        <view class="continent-item all" @click="navigateToAll">全部</view>
        <view class="continents-container">
          <view class="continent-row" v-for="(row, index) in continentRows" :key="index">
            <view
                class="continent-item continent"
                v-for="(continent, colIndex) in row"
                :key="colIndex"
                @click="navigateToDetail(continent)"
            >
              {{ continent.name }}
            </view>
            <!-- 添加占位元素保持布局 -->
            <view
                v-for="n in (3 - row.length)"
                :key="'placeholder'+n"
                class="continent-placeholder"
            ></view>
          </view>
        </view>
        <view class="continent-item separator"></view>
        <view class="continent-item nearby" @click="navigateToNearby">
          <view>附</view>
          <view>近</view>
        </view>
      </view>
      <SectionTitle title="场景博物馆" optitle="查看全部" goUrl="/sub-pages/hot-spot/index" />
      <SceneMuseumCard v-for="(item, index) in cardList" :key="index" :image="item.image" :title="item.title"
@@ -57,7 +83,6 @@
import HomeMain from './home-main.vue'
import TripCard from './trip-card.vue'
import GlobalGeo from './global-geo.vue'
import SceneMuseumCard from './scene-museum-card.vue'
import Community from './community.vue'
import { SwiperChangeEvent } from '@dcloudio/uni-app'
@@ -70,6 +95,54 @@
// 主题
const theme = ref('light')
const continents = ref([])
const getContinents = async () => {
  try {
    const {code, data} = await $http.request('get', '/api/code/value?type=CONTINENT_TYPE')
    if (code == 0 && data) {
      continents.value = data.map(item => (
          {
            id: item.id,
            name: item.label
          })
      )
    }
  } catch (error) {
    console.log('获取洲数据失败', error)
    $message.showToast('获取洲数据失败')
  }
}
const continentRows = computed(() => {
  const rows = [];
  const continentsList = [...continents.value];
  // 将洲分成三行
  for (let i = 0; i < 3; i++) {
    const start = i * 3;
    const end = start + 3;
    rows.push(continentsList.slice(start, end));
  }
  return rows;
});
const navigateToDetail = (continent) => {
  //跳转到具体页面
  uni.navigateTo({
    url: `/sub-pages/hot-city/index?continentId=${continent.id}`
  })
}
const navigateToNearby = () => {
  //附近功能跳转
  uni.navigateTo({
    url: '/pages/nearby/nearby'
  })
}
// 当前页数
@@ -115,6 +188,7 @@
onMounted(() => {
  const localTheme = uni.getStorageSync('theme') || 'light'
  theme.value = localTheme
  getContinents()
})
onShow(() => {
@@ -255,6 +329,82 @@
  margin-top: 20rpx;
  margin-bottom: 20rpx;
}
.continent-section {
  display: flex;
  align-items: stretch;
  border-top: 1px dashed #ccc;
  border-bottom: 1px dashed #ccc;
  padding: 10rpx 0;
  height: 220rpx; /* 固定高度容纳三行 */
}
.all, .nearby {
  flex-shrink: 0;
  width: 15%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 30rpx;
  font-weight: bold;
}
.continents-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.continent-row {
  display: flex;
  justify-content: flex-start; /* 改为左对齐 */
  height: 33.33%; /* 每行高度占三分之一 */
  padding: 5rpx 0;
}
.continent {
  flex: 0 0 30%; /* 固定宽度30% */
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  font-size: 28rpx;
  padding: 5rpx 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-right: 5%; /* 元素间间距 */
}
/* 最后一个元素不需要右边距 */
.continent:last-child {
  margin-right: 0;
}
.continent-placeholder {
  flex: 0 0 30%; /* 占位元素宽度 */
  margin-right: 5%; /* 保持与正常元素相同的间距 */
}
/* 最后一个占位元素不需要右边距 */
.continent-placeholder:last-child {
  margin-right: 0;
}
.separator {
  width: 1px;
  background-color: #ccc;
  margin: 0 10rpx;
  align-self: center;
  height: 80%; /* 分隔线高度为父容器的80% */
}
.nearby {
  flex-direction: column;
  font-size: 30rpx;
}
</style>
<style scoped lang="scss">
static/common/item-films.png
static/common/item-map.png
static/common/item-route.png
sub-pages/hot-city/hot-city-detail.vue
对比新文件
@@ -0,0 +1,375 @@
<template>
  <view class="container">
    <view class="header-info">
      <image src="/static/common/earth.png" class="earth-icon"></image>
      <view class="city-info">
        <text class="city-name">{{cityInfo.cityName}}</text>
        <text class="city-pinyin">{{cityInfo.cityPinyin}}</text>
        <text class="city-continent">{{cityInfo.cityCountry}} {{cityInfo.cityContinent}}</text>
      </view>
    </view>
    <view class="main-image">
      <image :src="cityInfo.mainImage" mode="aspectFit" class="main-img" />
    </view>
    <view class="main-text">
      <text class="info-title1">{{cityInfo.infoTitle1}}</text>
      <text class="info-title2">
        {{cityInfo.infoTitle2}}
      </text>
    </view>
    <!-- 添加三个可点击块 -->
    <view class="tab-container">
      <view class="tab-item" @click="activeTab = 'films'">
        <image src="/static/common/item-films.png" class="tab-icon"></image>
        <text class="tab-text">影片</text>
      </view>
      <view class="tab-item" @click="activeTab = 'map'">
        <image src="/static/common/item-map.png" class="tab-icon"></image>
        <text class="tab-text">地图</text>
      </view>
      <view class="tab-item" @click="activeTab = 'route'">
        <image src="/static/common/item-route.png" class="tab-icon"></image>
        <text class="tab-text">路线</text>
      </view>
    </view>
    <!-- 根据 activeTab 展示不同内容 -->
    <view v-if="activeTab === 'films'" class="content-container">
      <text class="content-title">影片列表</text>
      <!-- 影片列表内容 -->
      <view v-for="(film, index) in films" :key="index" class="film-item"  @click="goToFilmDetail(film.id)">
        <image :src="film.coverUrl" class="film-poster"></image>
        <text class="film-name">{{ film.nameCn }}</text>
      </view>
    </view>
    <view v-if="activeTab === 'map'" class="content-container">
      <text class="content-title">景点列表和地图</text>
      <!-- 地图内容 -->
      <map
          class="map-content"
          :latitude="mapCenter.latitude"
          :longitude="mapCenter.longitude"
          :scale="mapCenter.scale"
          :markers="mapMarkers"
      ></map>
      <view v-for="(spot, index) in spots" :key="index" class="spot-item"  @click="goToSpotDetail(spot.id)">
        <text class="spot-name">{{ spot.locationName }}</text>
        <text class="spot-desc">{{ spot.landmarkDesc }}</text>
      </view>
    </view>
    <view v-if="activeTab === 'route'" class="content-container">
      <text class="content-title">路线</text>
      <!-- 路线内容(暂时为空) -->
      <text>暂无内容</text>
    </view>
  </view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app'
import { useGlobal } from '@/composables/useGlobal'
const { $http, $message } = useGlobal()
import {FilmWorks,FilmLocationVO} from "@/types/index";
// 定义 activeTab 并设置默认值为 'films'
const activeTab = ref('films');
const films = ref<FilmWorks[]>();
const cityInfo = ref({
  cityName: '北京',
  cityPinyin: 'Beijing',
  cityCountry: '中国',
  cityContinent: 'Asia',
  mainImage: 'https://ai-public.mastergo.com/ai/img_res/6a226f9e9652c51cd535c3490535dfeb.jpg',
  infoTitle1: '',
  infoTitle2: '',
})
onLoad(async (options: any) => {
  const name = options.name
  const pinyin = options.pinyin
  const country = options.country
  const continent = options.continent
  // 修复后的代码 - 确保所有必需的属性都被设置
  cityInfo.value = {
    cityName: name || '北京',  // 提供默认值
    cityPinyin: pinyin || '',
    cityCountry: country || '中国',
    cityContinent: continent || 'Asia',
    mainImage: 'https://ai-public.mastergo.com/ai/img_res/6a226f9e9652c51cd535c3490535dfeb.jpg',
    infoTitle1: '',
    infoTitle2: ''
  }
  if (name) {
    await getRelatedFilms(name)
    await getLocations(name)
  }
})
const getRelatedFilms = async (name: string) => {
  const { code, data } = await $http.request('get', '/api/filmLocation/city', {
    params: { name }
  })
  if (code === 0 && Array.isArray(data)) {
    films.value = data
  } else {
    films.value = []
  }
}
const getLocations = async (name: string) => {
  const { code, data } = await $http.request('get', '/api/filmLocation/location', {
    params: { name }
  })
  if (code === 0 && Array.isArray(data)) {
    spots.value = data
    if (data.length > 0) {
      // 使用第一个景点的数据更新cityInfo
      const firstSpot = data[0];
      // 更新主图,如果没有locationUrl则使用默认图
      cityInfo.value.mainImage = firstSpot.locationUrl || cityInfo.value.mainImage;
      // 更新infoTitle1,使用locationName
      if (firstSpot.locationName) {
        cityInfo.value.infoTitle1 = firstSpot.locationName;
      }
      // 更新infoTitle2,组合address、sceneType、classicScene和landmarkDesc
      let infoTitle2Content = '';
      if (firstSpot.address) {
        infoTitle2Content += firstSpot.address;
      }
      if (firstSpot.sceneType) {
        infoTitle2Content += (infoTitle2Content ? ' ' : '') + firstSpot.sceneType;
      }
      if (firstSpot.classicScene) {
        infoTitle2Content += (infoTitle2Content ? ' ' : '') + firstSpot.classicScene;
      }
      if (firstSpot.landmarkDesc) {
        infoTitle2Content += (infoTitle2Content ? ' ' : '') + firstSpot.landmarkDesc;
      }
      if (infoTitle2Content) {
        cityInfo.value.infoTitle2 = infoTitle2Content;
      }
      // 设置中心点为第一个景点的位置
      mapCenter.value.latitude = data[0].gpsLat || 39.9042
      mapCenter.value.longitude = data[0].gpsLng || 116.4074
      mapCenter.value.scale = 12
      // 创建标记点数组
      mapMarkers.value = data.map((spot, index) => ({
        id: index,
        latitude: spot.gpsLat,
        longitude: spot.gpsLng,
        title: spot.locationName,
        iconPath: '/static/common/marker.png', // 可以替换为实际的标记图标路径
        width: 30,
        height: 30
      })).filter(marker => marker.latitude && marker.longitude) // 过滤掉没有坐标的标记
    }
  } else {
    spots.value = []
  }
}
const spots = ref<FilmLocationVO[]>();
// 添加地图中心点和标记数据
const mapCenter = ref({
  latitude: 39.9042,
  longitude: 116.4074,
  scale: 10
});
const mapMarkers = ref([]);
// 跳转到影片详情页
const goToFilmDetail = (id: number) => {
  uni.navigateTo({
    url: `/sub-pages/film-list/film-detail?id=${id}`
  });
};
// 跳转到景点详情页
const goToSpotDetail = (id: number) => {
  uni.navigateTo({
    url: `/sub-pages/hot-spot/spot-detail?id=${id}`
  });
};
</script>
<style scoped>
.container {
  padding: 20rpx;
}
.header-info {
  display: flex;
  align-items: center;
  margin-bottom: 30rpx;
  padding: 20rpx;
  background-color: #f8f8f8;
  border-radius: 16rpx;
}
.earth-icon{
  width: 180rpx;
  height: 180rpx;
  margin-right: 30rpx;
}
.city-info {
  display: flex;
  flex-direction: column;
}
.city-name {
  font-size: 40rpx;
  font-weight: bold;
  margin-bottom: 10rpx;
}
.city-pinyin {
  font-size: 32rpx;
  color: #666;
  margin-bottom: 10rpx;
}
.city-continent {
  font-size: 28rpx;
  color: #999;
}
.main-image {
  width: 100%;
  height: 400rpx;
  margin-bottom: 30rpx;
  border-radius: 16rpx;
  overflow: hidden;
}
.main-img {
  width: 100%;
  height: 100%;
}
.main-text {
  padding: 20rpx;
  margin-bottom: 30rpx;
  background-color: #f8f8f8;
  border-radius: 16rpx;
}
.info-title1 {
  font-size: 32rpx;
  font-weight: bold;
  margin-bottom: 15rpx;
  display: block;
}
.info-title2 {
  font-size: 28rpx;
  line-height: 1.6;
  color: #333;
}
.tab-container {
  display: flex;
  justify-content: space-around;
  padding: 20rpx 0;
  margin-bottom: 30rpx;
  border-top: 1rpx solid #eee;
  border-bottom: 1rpx solid #eee;
}
.tab-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20rpx;
}
.tab-icon {
  width: 60rpx;
  height: 60rpx;
  margin-bottom: 10rpx;
}
.tab-text {
  font-size: 28rpx;
}
.content-container {
  padding: 20rpx;
  background-color: #f8f8f8;
  border-radius: 16rpx;
  margin-bottom: 20rpx;
}
.content-title {
  font-size: 36rpx;
  font-weight: bold;
  margin-bottom: 30rpx;
  display: block;
}
.film-item {
  display: flex;
  align-items: center;
  margin-bottom: 30rpx;
  padding: 20rpx;
  background-color: #fff;
  border-radius: 12rpx;
}
.film-poster {
  width: 120rpx;
  height: 160rpx;
  margin-right: 20rpx;
  border-radius: 8rpx;
}
.film-name {
  font-size: 32rpx;
}
.map-content {
  width: 100%;
  height: 400rpx;
  margin-bottom: 30rpx;
  border-radius: 16rpx;
}
.spot-item {
  margin-bottom: 30rpx;
  padding: 20rpx;
  background-color: #fff;
  border-radius: 12rpx;
}
.spot-name {
  font-size: 32rpx;
  font-weight: bold;
  margin-bottom: 10rpx;
  display: block;
}
.spot-desc {
  font-size: 28rpx;
  color: #666;
}
</style>
sub-pages/hot-city/index.vue
对比新文件
@@ -0,0 +1,381 @@
<template>
  <view :class="['app', theme]">
    <!-- 搜索框部分 -->
    <view style="padding-top: 10rpx;">
      <up-search
          height="70rpx"
          placeholder="搜索城市"
          search-icon-size="40rpx"
          margin="0rpx 30rpx"
          v-model="search"
          :show-action="true"
          @search="onSearch"
          @custom="onSearch"
          @click-icon="onSearch"
      />
    </view>
    <!-- 标签切换部分 -->
    <up-tabs :list="tabList" @click="click">
      <template #right>
        <view style="padding-left: 4px;" @tap="() => showToast('插槽被点击')">
          <up-icon name="list" size="40rpx" bold></up-icon>
        </view>
      </template>
    </up-tabs>
    <!-- 城市列表 -->
    <view class="city-items">
      <!-- 搜索状态下的列表 -->
      <template v-if="search">
        <view
            class="city-item"
            v-for="city in displayedCities"
            :key="city.id"
            @click="handleCityClick(city)"
        >
          {{ city.name }}
        </view>
      </template>
      <!-- 非搜索状态下的列表 -->
      <template v-else>
        <!-- 热门城市部分 -->
        <view class="section" v-if="filteredHotCities.length">
          <view class="section-title">热门城市</view>
          <view class="hot-city-list">
            <view
                class="hot-city-item"
                v-for="city in filteredHotCities"
                :key="'hot-'+city.id"
                @click="handleCityClick(city)"
            >
              {{ city.name }}
            </view>
          </view>
        </view>
        <!-- A-Z城市列表 -->
        <view class="section" v-for="group in groupedCities" :key="group.letter">
          <view class="section-title">{{ group.letter }}</view>
          <view
              class="city-detail-item"
              v-for="city in group.cities"
              :key="'az-'+city.id"
              @click="handleCityClick(city)"
          >
            <view class="city-name">{{ city.name }}</view>
            <view class="city-sub-info">
              <text class="city-pinyin">{{ city.pinyin }}</text>
              <text class="city-country"> · {{ city.country }}</text>
            </view>
          </view>
        </view>
      </template>
    </view>
  </view>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useGlobal } from '@/composables/useGlobal'
const { $http, $message, $store } = useGlobal()
const theme = ref('light')
const search = ref('')
// 响应式数据
const tabList = ref([])
const currentTab = ref('Asia')
// 更新热门城市数据结构,添加国家字段
// const hotCities = ref([
//   { id: 1, name: '北京市', pinyin: 'Beijing', country: '中国', continent: 'asia' },
//   { id: 2, name: '上海市', pinyin: 'Shanghai', country: '中国', continent: 'asia' },
//   { id: 3, name: '纽约', pinyin: 'New York', country: '美国', continent: 'northAmerica' },
//   { id: 4, name: '伦敦', pinyin: 'London', country: '英国', continent: 'europe' },
// ])
const hotCities = ref([])
// 更新所有城市数据结构,添加国家字段
const allCities = ref([])
// 当前洲的热门城市
const filteredHotCities = computed(() => {
  if (currentTab.value === 'all') {
    return hotCities.value;
  }
  return hotCities.value.filter(city => city.continent === currentTab.value);
});
// 当前洲的所有城市(按拼音分组)
const groupedCities = computed(() => {
  // 获取当前洲的城市列表
  let cities = [];
  if (currentTab.value === 'all') {
    cities = [...allCities.value];
  } else {
    cities = allCities.value.filter(city => city.continent === currentTab.value);
  }
  // 按拼音首字母分组
  const groups: Record<string, any[]> = {};
  cities.forEach(city => {
    const firstLetter = city.pinyin.charAt(0).toUpperCase();
    if (!groups[firstLetter]) {
      groups[firstLetter] = [];
    }
    groups[firstLetter].push(city);
  });
  // 转换为数组并按字母排序
  return Object.keys(groups)
      .sort()
      .map(letter => ({
        letter,
        cities: groups[letter].sort((a, b) =>
            a.pinyin.localeCompare(b.pinyin))
      }));
});
// 根据当前标签显示对应的城市(用于搜索状态)
const displayedCities = computed(() => {
  let cities = [];
  if (currentTab.value === 'all') {
    cities = [...hotCities.value, ...allCities.value];
  } else {
    cities = allCities.value.filter(city => city.continent === currentTab.value);
  }
  // 添加搜索过滤功能
  if (search.value) {
    return cities.filter(city =>
        city.name?.includes(search.value) ||
        city.pinyin?.toLowerCase().includes(search.value.toLowerCase())
    )
  }
  return cities
})
// 标签点击事件
// const click = (item: { name: string; value: string }) => {
//   currentTab.value = item.value
//   console.log('currentTab:', currentTab.value)
// }
const click = async (item: { name: string; value: string }) => {
  currentTab.value = item.value;
  console.log('currentTab:', currentTab.value);
  // 显示加载状态
  uni.showLoading({ title: '加载中...' });
  try {
    await getHotCities();
    await getAllCities();
  } finally {
    uni.hideLoading();
  }
};
// 搜索事件
const onSearch = (value: string) => {
  const searchValue = typeof value === 'string' ? value : search.value
  search.value = searchValue
}
const handleCityClick = (city: any) => {
  console.log('City clicked:', city)
  // 实际应用中这里可以添加选择城市后的逻辑
  uni.navigateTo({
    url: `/sub-pages/hot-city/hot-city-detail?name=${city.name}`
  })
}
const showToast = (msg: string) => {
  uni.showToast({ title: msg, icon: 'none' })
}
onLoad(async(options) => {
  const storedTheme = uni.getStorageSync('theme') || 'light'
  theme.value = storedTheme
  console.log("options", options)
  if (options && options.continentId) {
    // 等待获取 tab 列表完成
    await getTabList()
    const continentId = options.continentId.toString()
    console.log('continentId:', continentId);
    console.log("tabList.value", tabList.value)
    const tab = tabList.value.find(t => {
      console.log(`Comparing "${t.id}" with "${continentId}"`);
      return t.id.toString() === continentId.toString();
    });
    console.log("tab", tab)
    if (tab) {
      console.log('  currentTab.value ',   currentTab.value )
      currentTab.value = tab.value
      console.log('  currentTab.value ',   currentTab.value )
      console.log('Tab found and set:', tab)
      // 关键:在设置完 currentTab 后,立即获取对应的数据
      await getHotCities();
      await getAllCities();
    } else {
      console.log('Tab not found for continentId:', options.continentId)
      console.log('Available tabs:', tabList.value)
    }
  } else {
    // 如果没有传参,正常获取 tab 列表和数据
    await getTabList()
    await getHotCities();
    await getAllCities();
  }
})
// onMounted(() => {
//   // 初始化数据
//   // getTabList();
//   getHotCities();
//   getAllCities();
// })
// 监听currentTab变化,重新获取数据
// 确保 watch 能够深度监听并正确处理异步操作
watch(currentTab, async (newVal, oldVal) => {
  console.log('Tab changed from', oldVal, 'to', newVal);
  await getHotCities();
  await getAllCities();
}, { flush: 'post' });
const getAllCities = async () => {
  // 获取所有城市
  try{
    const { code, data } = await $http.request('get', '/api/filmLocation/info',{
      params: {
        continent: currentTab.value,
      }
    })
    if (code === 0 && data) {
      allCities.value = data.map(item => ({
        id: item.id,
        name: item.city,
        pinyin: item.pinyin,
        country: item.country,
        continent: item.continent
      }))
    }
  }catch (e) {
    console.log("获取热门城市失败", e)
    $message.showToast("获取热门城市失败")
  }
}
 const getHotCities = async () => {
  //获取热门城市
   try{
     const { code, data } = await $http.request('get', '/api/filmHotCity/list',{
       params: {
         size: 10,
         continent: currentTab.value=='all'?'':currentTab.value,
         current: 1
       }
     })
     if (code === 0 && data) {
       hotCities.value = data.records.map(item => ({
         id: item.id,
         name: item.name,
         country: item.country,
         continent: item.continent
       }))
     }
   }catch (e) {
     console.log("获取热门城市失败", e)
     $message.showToast("获取热门城市失败")
   }
}
const getTabList = async () => {
  // 获取洲列表
  try {
    const {code, data} = await $http.request('get', '/api/code/value?type=CONTINENT_TYPE')
    if (code == 0 && data) {
      tabList.value = data.map((item: any) => ({
        id: item.id,
        name: item.label,
        value: item.value // 确保这里返回洲的标识符
      }))
    }
  } catch (e) {
    console.log("获取洲数据失败", e)
    $message.showToast("获取洲数据失败")
  }
}
</script>
<style scoped>
.city-items {
  padding: 0 30rpx;
}
.section {
  margin-bottom: 30rpx;
}
.section-title {
  font-size: 28rpx;
  color: #666;
  padding: 20rpx 0;
  border-bottom: 1rpx solid #eee;
  margin-bottom: 15rpx;
}
.hot-city-list {
  display: flex;
  flex-wrap: wrap;
  gap: 20rpx;
}
.hot-city-item {
  background-color: #f5f5f5;
  padding: 15rpx 25rpx;
  border-radius: 10rpx;
  font-size: 28rpx;
}
.city-detail-item {
  padding: 25rpx 0;
  border-bottom: 1rpx solid #f5f5f5;
}
.city-name {
  font-size: 32rpx;
  font-weight: 500;
  margin-bottom: 8rpx;
}
.city-sub-info {
  display: flex;
  font-size: 26rpx;
  color: #888;
}
.city-pinyin {
  font-style: italic;
}
.city-country {
  margin-left: 5rpx;
}
/* 搜索状态下的简单列表样式 */
.city-item {
  padding: 25rpx 0;
  border-bottom: 1rpx solid #f5f5f5;
  font-size: 32rpx;
}
</style>