index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. <template>
  2. <FlexCol>
  3. <FlexCol :gap="20" :padding="[30,30,0,30]" :innerStyle="{
  4. marginTop: '-80px',
  5. backgroundImage: `url(${appConfiguration?.banners.homeTop})`,
  6. backgroundSize: '100% auto',
  7. backgroundRepeat: 'no-repeat',
  8. backgroundPosition: 'top center',
  9. backgroundColor: themeContext.resolveThemeColor('background.primary'),
  10. }">
  11. <FlexCol position="absolute" :left="30" :top="0" :right="30">
  12. <StatusBarSpace />
  13. <FlexRow justify="space-between" align="flex-start">
  14. <Button
  15. @click="showCityPopup = true"
  16. icon="https://xy.wenlvti.net/app_static/images/home/IconSwitch.png"
  17. size="medium"
  18. :radius="40"
  19. :text="currentCity"
  20. />
  21. <Image
  22. :src="appConfiguration?.banners.homeTitle.url"
  23. :width="appConfiguration?.banners.homeTitle.width || 140"
  24. :height="appConfiguration?.banners.homeTitle.height || 75"
  25. :innerStyle="appConfiguration?.banners.homeTitle.innerStyle"
  26. />
  27. <Width :width="150" />
  28. </FlexRow>
  29. </FlexCol>
  30. <SimpleTransition name="fade" :show="currentScrollTop > 1000" :duration="300">
  31. <template #show="{ classNames }">
  32. <view
  33. :class="['top-nav-fade ',...classNames]"
  34. :style="{ backgroundColor: themeContext.resolveThemeColor('background.primary') }"
  35. :left="0" :top="0" :right="0" :zIndex="200"
  36. >
  37. <StatusBarSpace />
  38. </view>
  39. </template>
  40. </SimpleTransition>
  41. <Height height="80px" />
  42. <FlexCol :gap="20" align="center">
  43. <ImageSwiper
  44. :images="bannerLoader.content.value || []"
  45. :height="appConfiguration?.banners.home.height"
  46. :width="700"
  47. radius="radius.md"
  48. :innerStyle="{
  49. border: '1px solid #fff',
  50. overflow: 'hidden',
  51. clipPath: 'ellipse(100% 90% at 50% 0%)'
  52. }"
  53. />
  54. </FlexCol>
  55. <FlexRow justify="space-between" align="center" width="100%">
  56. <SearchBar
  57. v-model="searchKeywords"
  58. placeholder="搜索村社"
  59. :innerStyle="{
  60. backgroundColor: 'white',
  61. borderRadius: '20rpx',
  62. borderWidth: '1px',
  63. borderStyle: 'solid',
  64. borderColor: themeContext.resolveThemeColor('primary'),
  65. width: '630rpx',//490rpx
  66. }"
  67. @search="handleSearch"
  68. />
  69. <!-- <Button icon="ai-thinking" @click="handleGoAI" text="问AI" /> -->
  70. </FlexRow>
  71. <HomeTitle title="今日推荐" showMore @moreClicked="emit('goDiscover')" />
  72. <SimplePageContentLoader :loader="recommendLoader">
  73. <FlexRow gap="gap.lg" align="stretch" justify="space-between">
  74. <Touchable
  75. v-for="item in recommendLoader.content.value"
  76. :key="item.id"
  77. position="relative"
  78. radius="radius.md"
  79. shadow="default"
  80. gap="gap.lg"
  81. direction="row"
  82. align="center"
  83. overflow="hidden"
  84. border="1px solid #fff"
  85. :flexShrink="0"
  86. width="48%"
  87. @click="handleGoRecommendDetails(item)"
  88. >
  89. <Image :src="item.image" :width="400" :height="270" />
  90. <FlexCol position="absolute" :inset="{ b: -1, l: -1, r: -1 }" backgroundColor="background.primary" padding="padding.md" gap="gap.md">
  91. <Text fontConfig="contentSpeicalText" fontFamily="SongtiSCBlack" :lines="1" :wrap="false">{{ item.title }}</Text>
  92. <Text fontSize="fontSize.sm" :text="item.desc" :lines="1" :maxWidth="200" />
  93. </FlexCol>
  94. </Touchable>
  95. </FlexRow>
  96. </SimplePageContentLoader>
  97. <Height :height="10" />
  98. <LightMap
  99. small
  100. :city="currentCity"
  101. :cityCode="currentCityCode"
  102. :district="currentDistrict"
  103. :lonlat="currentLocation.currentLonlat.value"
  104. @getCurrentLonlat="currentLocation.getCurrentExactLocation"
  105. @mapClick="handleGoMap"
  106. >
  107. <NoticeBar
  108. v-if="currentNoticeContent"
  109. :content="currentNoticeContent"
  110. :innerStyle="{
  111. position: 'absolute',
  112. top: '20rpx',
  113. left: '20rpx',
  114. right: '20rpx',
  115. zIndex: 100,
  116. borderRadius: '30rpx',
  117. }"
  118. :textStyle="{
  119. fontSize: '26rpx',
  120. }"
  121. icon="https://xy.wenlvti.net/app_static/images/home/IconLightActive.png"
  122. :iconProps="{
  123. size: 34,
  124. }"
  125. textColor="#C9211F"
  126. backgroundColor="#D9492E10"
  127. />
  128. </LightMap>
  129. <FlexRow justify="space-between" :padding="[10, 16]" gap="gap.md">
  130. <Button
  131. icon="https://xy.wenlvti.net/app_static/images/home/IconSwitch.png"
  132. radius="radius.lg"
  133. :padding="[10, 30]"
  134. text="切换城市"
  135. :textProps="{ wrap: false }"
  136. @click="showCityPopup = true"
  137. />
  138. <Button
  139. icon="https://xy.wenlvti.net/app_static/images/home/IconFollow.png"
  140. radius="radius.lg" :padding="[10, 30]"
  141. @click="showMyFollowPopup = true"
  142. text="我的关注"
  143. :textProps="{ wrap: false }"
  144. />
  145. <BubbleTip
  146. v-model:show="showLightTip"
  147. content="没有加入村社?点击这里点亮村落"
  148. position="bottom"
  149. crossPosition="right"
  150. :arrowOffsetX="130"
  151. @contentClick="handleLightVillage"
  152. @close="handleCloseLightTip"
  153. >
  154. <Button
  155. icon="https://xy.wenlvti.net/app_static/images/home/IconLight.png"
  156. radius="radius.lg" :padding="[10, 30]"
  157. :textProps="{ wrap: false }"
  158. text="点亮村社"
  159. @click="handleLightVillage"
  160. />
  161. </BubbleTip>
  162. </FlexRow>
  163. <HomeTitle title="今日共建任务" showMore @moreClicked="navTo('/pages/home/village/task/index')" />
  164. <SimplePageContentLoader :loader="taskListLoader">
  165. <scroll-view scroll-x>
  166. <FlexRow gap="gap.lg" align="stretch">
  167. <Touchable
  168. v-for="item in taskListLoader.content.value"
  169. :key="item.id"
  170. backgroundColor="white"
  171. radius="radius.md"
  172. padding="padding.md"
  173. shadow="default"
  174. gap="gap.lg"
  175. direction="row"
  176. align="center"
  177. :flexShrink="0"
  178. :innerStyle="{ minWidth: '400rpx' }"
  179. @click="handleDoTask(item)"
  180. >
  181. <Icon :icon="item.image || 'space'" :size="100" />
  182. <FlexCol gap="gap.md">
  183. <Text fontConfig="contentSpeicalText" fontFamily="SongtiSCBlack">{{ item.name }}</Text>
  184. <Text fontSize="fontSize.sm" :text="item.desc" :lines="1" :maxWidth="400" />
  185. <Text v-if="item.points > 0" fontConfig="secondText">+{{ item.points }}文化积分</Text>
  186. <FlexRow>
  187. <Button v-if="item.rewardFruit > 0" icon="https://xy.wenlvti.net/app_static/images/village/IconFruit.png" size="mini" :text="`+${item.rewardFruit}乡源果`" />
  188. <Button v-if="item.rewardLight > 0" icon="https://xy.wenlvti.net/app_static/images/village/IconLight.png" size="mini" :text="`+${item.rewardLight}乡源光`" />
  189. <Button v-if="item.rewardWater > 0" icon="https://xy.wenlvti.net/app_static/images/village/IconWatering.png" size="mini" :text="`+${item.rewardWater}浇水次数`" />
  190. </FlexRow>
  191. </FlexCol>
  192. </Touchable>
  193. </FlexRow>
  194. </scroll-view>
  195. </SimplePageContentLoader>
  196. <HomeTitle title="最新动态" />
  197. <SimplePageContentLoader :loader="noticeListLoader">
  198. <FlexCol gap="gap.lg">
  199. <FlexRow
  200. v-for="item in noticeListLoader.content.value?.slice(0, 3) || [] "
  201. :key="item.item.id"
  202. backgroundColor="background.tertiary"
  203. radius="radius.md"
  204. :padding="[20, 30]"
  205. gap="gap.lg"
  206. align="center"
  207. >
  208. <Avatar
  209. :src="(item.item.avatar as string)"
  210. :size="80"
  211. :round="false"
  212. :radius="10"
  213. />
  214. <FlexCol>
  215. <Text :text="item.item.title" fontConfig="contentText" />
  216. <Text
  217. :text="`来自${item.item.villageName}`"
  218. fontConfig="secondText"
  219. />
  220. </FlexCol>
  221. </FlexRow>
  222. </FlexCol>
  223. </SimplePageContentLoader>
  224. <HomeTitle title="乡村排名" showMore @moreClicked="navTo('/pages/home/village/rank/village', {})" />
  225. <VillageRankList :list="villageRankListLoader.content.value ?? []" :jumpToSingle="false" @goDetails="handleGoVillageDetails" />
  226. <HomeTitle title="志愿者排名" showMore :lightCount="3" @moreClicked="navTo('/pages/home/village/rank/volunteer', {})" />
  227. <VillageUserRankList
  228. :list="villageUserRankListLoader.content.value ?? []"
  229. scoreSuffix="积分"
  230. @goDetails="navTo('/pages/home/village/volunteer/detail', { id: $event.id })"
  231. />
  232. </FlexCol>
  233. <view class="recommmend-header" :style="stickyStyle">
  234. <FlexCol :padding="[0,30]">
  235. <HomeTitle title="精选记忆">
  236. <template #right>
  237. <FrameButton
  238. size="small"
  239. icon="https://xy.wenlvti.net/app_static/images/village/IconLargeHistory.png"
  240. text="我也来写"
  241. @click="handleGoPublish()"
  242. />
  243. </template>
  244. </HomeTitle>
  245. </FlexCol>
  246. <Tabs
  247. v-model:currentIndex="recommendTabCurrent"
  248. :tabs="recommendTabs"
  249. />
  250. </view>
  251. <FlexCol :padding="30">
  252. <RecommendTab v-if="recommendTabCurrent === 0" @goDetails="handleGoRecommendDetails" />
  253. <GoodsTab v-else-if="recommendTabCurrent === 1" @goDetails="handleGoRecommendDetails" />
  254. <TravelTab v-else-if="recommendTabCurrent === 2" @goDetails="handleGoRecommendDetails" />
  255. <CulturalTab v-else-if="recommendTabCurrent === 3" @goDetails="handleGoRecommendDetails" />
  256. </FlexCol>
  257. <Height :height="200" />
  258. <Popup
  259. v-model:show="showCityPopup"
  260. closeable
  261. position="top"
  262. size="60vh"
  263. >
  264. <CitySelect @selectCity="handleSelectCity" />
  265. </Popup>
  266. <Popup
  267. v-model:show="showMyFollowPopup"
  268. closeable
  269. position="bottom"
  270. round
  271. size="80vh"
  272. >
  273. <VillageMyFollow @goDetails="handleGoVillageDetails" />
  274. </Popup>
  275. <PostIndex
  276. ref="postIndexRef"
  277. @goDig="emit('goDig')"
  278. />
  279. <IntroClamTip ref="introClamTipRef" @apply="handleLightVillage" />
  280. </FlexCol>
  281. </template>
  282. <script setup lang="ts">
  283. import { onMounted, ref, watch } from 'vue';
  284. import { useTheme } from '@/components/theme/ThemeDefine';
  285. import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
  286. import { useStorageVar } from '@/components/composeabe/StorageVar';
  287. import { useVillageStore } from '@/store/village';
  288. import { useGetCurrentLocation } from './composeabe/GetCurrentLocation';
  289. import { useAuthStore } from '@/store/auth';
  290. import { useRequireLogin } from '@/common/composeabe/RequireLogin';
  291. import { useUserTools } from '@/common/composeabe/UserTools';
  292. import { useGetNotice } from './village/composeabe/GetNotice';
  293. import { waitTimeOut } from '@imengyu/imengyu-utils';
  294. import { toast, loading, hideLoading } from '@/components/utils/DialogAction';
  295. import { navTo } from '@/components/utils/PageAction';
  296. import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
  297. import { DynamicColor, statusBarHeight } from '@/components/theme/ThemeTools';
  298. import Image from '@/components/basic/Image.vue';
  299. import FlexCol from '@/components/layout/FlexCol.vue';
  300. import FlexRow from '@/components/layout/FlexRow.vue';
  301. import Height from '@/components/layout/space/Height.vue';
  302. import SearchBar from '@/components/form/SearchBar.vue';
  303. import Button from '@/components/basic/Button.vue';
  304. import HomeTitle from '@/common/components/parts/HomeTitle.vue';
  305. import VillageRankList from './components/VillageRankList.vue';
  306. import VillageUserRankList from './components/VillageUserRankList.vue';
  307. import Popup from '@/components/dialog/Popup.vue';
  308. import CitySelect from './components/CitySelect.vue';
  309. import VillageMyFollow from './components/VillageMyFollow.vue';
  310. import LightMap from './components/LightMap.vue';
  311. import NoticeBar from '@/components/display/NoticeBar.vue';
  312. import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
  313. import LightVillageApi, { VillageListItem, type VillageMapItem } from '@/api/light/LightVillageApi';
  314. import Width from '@/components/layout/space/Width.vue';
  315. import IntroClamTip from './village/dialogs/IntroClamTip.vue';
  316. import MemoryTimeOut from '@/components/composeabe/MemoryTimeOut';
  317. import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
  318. import VillageInfoApi, { type CommonInfoModel } from '@/api/inhert/VillageInfoApi';
  319. import PostIndex from './village/dialogs/PostIndex.vue';
  320. import FrameButton from '@/common/components/FrameButton.vue';
  321. import type { RegionItem } from '@/api/map/RegionApi';
  322. import BubbleTip from '@/components/feedback/BubbleTip.vue';
  323. import BannerApi from '@/api/system/Banner';
  324. import Tabs from '@/components/nav/Tabs.vue';
  325. import SimpleTransition from '@/components/anim/SimpleTransition.vue';
  326. import RecommendTab from './recommend/RecommendTab.vue';
  327. import GoodsTab from './recommend/GoodsTab.vue';
  328. import TravelTab from './recommend/TravelTab.vue';
  329. import CulturalTab from './recommend/CulturalTab.vue';
  330. import Avatar from '@/components/display/Avatar.vue';
  331. import Text from '@/components/basic/Text.vue';
  332. import TreeApi from '@/api/light/TreeApi';
  333. import Touchable from '@/components/feedback/Touchable.vue';
  334. import Icon from '@/components/basic/Icon.vue';
  335. import SimplePageContentLoader from '@/components/loader/SimplePageContentLoader.vue';
  336. import { useTaskActions } from './village/composeabe/TaskActions';
  337. const props = defineProps({
  338. currentScrollTop: {
  339. type: Number,
  340. default: 0,
  341. },
  342. });
  343. const emit = defineEmits(['goVillage','goDig','goDiscover']);
  344. const authStore = useAuthStore();
  345. const villageStore = useVillageStore();
  346. const themeContext = useTheme();
  347. const { requireLogin } = useRequireLogin();
  348. const { getIsVolunteer } = useUserTools();
  349. const searchKeywords = ref('');
  350. const showCityPopup = ref(false);
  351. const showMyFollowPopup = ref(false);
  352. const introClamTipRef = ref();
  353. const introClamTipTimeout = new MemoryTimeOut('IntroClamTip', 1000 * 3600 * 30);//30h
  354. const postIndexRef = ref<InstanceType<typeof PostIndex>>();
  355. const appConfiguration = injectAppConfiguration();
  356. const { value: currentCity } = useStorageVar('currentCityName', '');
  357. const { value: currentCityCode } = useStorageVar('currentCityCode', 0);
  358. const { value: currentDistrict } = useStorageVar('currentDistrict', '');
  359. const currentLocation = useGetCurrentLocation({
  360. onCityChanged: (city, code, district) => {
  361. currentCity.value = city;
  362. currentCityCode.value = code;
  363. currentDistrict.value = district || '';
  364. },
  365. });
  366. const { currentNoticeContent, noticeListLoader } = useGetNotice();
  367. const bannerLoader = useSimpleDataLoader(async () => {
  368. return (await BannerApi.getBannerList({
  369. keywords: '亮乡源大众版首页头部',
  370. })).map(p => ({
  371. image: p.image,
  372. url: p.url,
  373. }));
  374. });
  375. const villageRankListLoader = useSimpleDataLoader(async () => {
  376. const res = await LightVillageApi.getVillageRankList({ num: 3 });
  377. return res.map((item, i) => ({
  378. image: item.image ?? '',
  379. title: item.name,
  380. rank: i + 1,
  381. id: item.id,
  382. }));
  383. });
  384. const villageUserRankListLoader = useSimpleDataLoader(async () => {
  385. const res = (await LightVillageApi.getVolunteerRankList({ num: 3 }))
  386. .map((item, i) => ({
  387. id: item.id,
  388. image: item.avatar ?? '',
  389. title: item.name,
  390. rank: i + 1,
  391. score: item.points,
  392. }));
  393. return res
  394. });
  395. const taskListLoader = useSimpleDataLoader(async () => {
  396. return (await TreeApi.getTaskList({
  397. page: 1,
  398. pageSize: 5,
  399. })).list;
  400. });
  401. const recommendLoader = useSimpleDataLoader(async () => {
  402. return (await VillageInfoApi.getListForDiscover({ page: 1, pageSize: 2 })).list;
  403. });
  404. const showLightTipTimeout = new MemoryTimeOut('LightTip', 1000 * 3600 * 2);//2h
  405. const showLightTip = ref(false);
  406. function handleShowLightTip() {
  407. if (showLightTipTimeout.isTimeout())
  408. showLightTip.value = true;
  409. }
  410. function handleCloseLightTip() {
  411. showLightTipTimeout.recordTime();
  412. }
  413. const { handleDoTask } = useTaskActions(() => villageStore.currentVillage?.id || 0, true);
  414. const recommendTabCurrent = ref(0);
  415. const recommendTabs = ref([
  416. {
  417. text: '推荐',
  418. value: 0,
  419. },
  420. {
  421. text: '好物',
  422. value: 1,
  423. },
  424. {
  425. text: '乡游',
  426. value: 2,
  427. },
  428. {
  429. text: '文化',
  430. value: 3,
  431. },
  432. ]);
  433. const stickyStyle = themeContext.useThemeStyle({
  434. position: 'sticky',
  435. top: (statusBarHeight - 10) + 'px',
  436. left: 0,
  437. right: 0,
  438. zIndex: '100',
  439. backgroundColor: DynamicColor('background.primary'),
  440. });
  441. function handleGoRecommendDetails(item: CommonInfoModel) {
  442. navTo(`/pages/home/discover/details`, { id: item.id });
  443. }
  444. async function handleGoVillageDetails(item: VillageListItem) {
  445. showMyFollowPopup.value = false;
  446. const details = await LightVillageApi.getVillageDetails(item.id);
  447. villageStore.setCurrentVillage(details);
  448. await waitTimeOut(100);
  449. emit('goVillage')
  450. }
  451. function handleSelectCity(city: RegionItem) {
  452. currentCity.value = city.name;
  453. currentCityCode.value = city.areaCode;
  454. showCityPopup.value = false;
  455. currentLocation.currentLonlat.value = {
  456. longitude: Number(city.longitude),
  457. latitude: Number(city.latitude),
  458. };
  459. }
  460. function handleGoAI() {
  461. requireLogin(async () => {
  462. navTo('/pages/chat/index');
  463. }, '暂时需要登录后才能使用AI助手');
  464. }
  465. async function handleGoPublish() {
  466. requireLogin(async () => {
  467. postIndexRef.value?.show();
  468. }, '欢迎您发布内容,登录后以便使用更多功能哦!');
  469. }
  470. async function handleLightVillage() {
  471. requireLogin(async () => navTo('/pages/home/light/create-village'), '登录后才能点亮村社哦!');
  472. }
  473. function handleGoMap() {
  474. navTo('/pages/home/light/map', {
  475. city: currentCity.value,
  476. cityCode: currentCityCode.value,
  477. district: currentDistrict.value,
  478. });
  479. }
  480. function handleSearch() {
  481. if (!searchKeywords.value) {
  482. toast('请输入搜索关键词');
  483. return;
  484. }
  485. navTo('/pages/home/search/index', {
  486. city: currentCity.value,
  487. cityCode: currentCityCode.value,
  488. searchValue: searchKeywords.value,
  489. });
  490. }
  491. async function loadInfo() {
  492. loading('载入数据中');
  493. //如果不是志愿者,则显示认领村庄提示
  494. const isVolunteer = await getIsVolunteer();
  495. if (!isVolunteer) {
  496. if (introClamTipTimeout.isTimeout()) {
  497. introClamTipRef.value?.show();
  498. introClamTipTimeout.recordTime();
  499. }
  500. }
  501. //加载我的关注村庄
  502. try {
  503. await villageStore.loadMyFollowVillages();
  504. } catch (error) {
  505. console.error(error);
  506. }
  507. try {
  508. await villageStore.loadMyJoinedVillages();
  509. } catch (error) {
  510. console.error(error);
  511. }
  512. handleShowLightTip();
  513. try {
  514. if (!villageStore.currentVillage && villageStore.myFollowVillages.length > 0) {
  515. const currentVillage = villageStore.loadCurrentVillage();
  516. const id = (villageStore.myFollowVillages.find(p => p.id === currentVillage) as VillageListItem || villageStore.myFollowVillages[0]).id;
  517. const res = await LightVillageApi.getVillageDetails(id)
  518. villageStore.setCurrentVillage(res);
  519. }
  520. } finally {
  521. hideLoading();
  522. }
  523. }
  524. watch(() => authStore.isLogged, async (newVal) => {
  525. if (newVal) {
  526. await loadInfo();
  527. }
  528. }, { immediate: true });
  529. onMounted(async () => {
  530. try {
  531. if (currentCity.value) {
  532. await currentLocation.setCurrentLocationWithCity(currentCity.value, currentDistrict.value);
  533. } else {
  534. await currentLocation.getCurrentFuzzyLocation();
  535. }
  536. } catch (error) {
  537. console.error(error);
  538. toast('获取当前位置失败,您可以手动选择城市');
  539. }
  540. });
  541. defineExpose({
  542. goMap() {
  543. handleGoMap();
  544. },
  545. onPageBack: (name: string, data: Record<string, unknown>) => {
  546. if (name === 'changeCurrentCity') {
  547. currentCity.value = data.city as string;
  548. currentCityCode.value = data.code as number;
  549. currentDistrict.value = '';
  550. currentLocation.currentLonlat.value = {
  551. longitude: Number(data.longitude),
  552. latitude: Number(data.latitude),
  553. };
  554. }
  555. }
  556. })
  557. </script>
  558. <style lang="scss">
  559. .top-nav-fade {
  560. position: fixed;
  561. top: 0;
  562. left: 0;
  563. right: 0;
  564. z-index: 200;
  565. transition: opacity 0.3s ease-in-out;
  566. &.fade-enter-active,
  567. &.fade-leave-active {
  568. opacity: 1;
  569. }
  570. &.fade-enter-from,
  571. &.fade-leave-to {
  572. opacity: 0;
  573. }
  574. }
  575. </style>