home.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. <template>
  2. <view class="index" :style="{ backgroundImage: `url(${bgImage.image1})` }">
  3. <view class="top-box" :class="showTopSearch ? '' : 'hide'">
  4. <view :style="[{ height: `${statusBarHeight}px` }]"></view>
  5. <view class="title" :style="[{ height: `${menuButtonHeight}px` }]">
  6. <text class="titlt-txt">商城</text>
  7. </view>
  8. <view class="input-box">
  9. <view class="status-bar" :style="[{ height: `${statusBarHeight}px` }]" @click="searchClick"></view>
  10. <view class="input-placeholder" @click="searchClick">请输入检索关键字</view>
  11. <view class="msgCenter" @click="goToMsg()">
  12. <!-- &#xe67c; -->
  13. <uv-icon name="chat" color="#ffffff" size="28"></uv-icon>
  14. <text v-if="msgCenter == 0 ? false : msgCenter">{{ msgCenter }}</text>
  15. </view>
  16. </view>
  17. </view>
  18. <view class="u-skeleton">
  19. <view class="swiper u-skeleton-rect" :class="showTopSearch ? '' : 'mt120'"
  20. v-if="(shopBanner && shopBanner.length > 0) || skeletonShow">
  21. <view class="uni-margin-wrap">
  22. <swiper class="swiper" :indicator-dots="true" :autoplay="true" :interval="2000" :duration="1000"
  23. circular="false">
  24. <swiper-item v-for="item in skeletonShow ? 1 : shopBanner" :key="item.id">
  25. <view class="swiper-item" @click="$mUtil.imgLink(item)">
  26. <image class="bannersize" :src="`${item.image}`" mode="aspectFill"></image>
  27. </view>
  28. </swiper-item>
  29. </swiper>
  30. </view>
  31. </view>
  32. <!-- 首页一级分类 -->
  33. <div class="one-cate">
  34. <!-- cateList.slice(0,4) -->
  35. <div class="item" v-for="item in skeletonShow ? 4 : cateList" @click="$mUtil.imgLink(item, 0)" :key="item.id">
  36. <!-- ?x-oss-process=style/w_350 -->
  37. <image class="u-skeleton-fillet" mode="widthFix " :src="`${item.icon}`">
  38. </image>
  39. <div class="word u-skeleton-fillet u-font26">
  40. {{ item.name || "加载中" }}
  41. </div>
  42. </div>
  43. </div>
  44. <view v-if="(homeBanner1 && homeBanner1.image) || skeletonShow" class="banner1Cls"
  45. @click="$mUtil.imgLink(homeBanner1)">
  46. <!-- ?x-oss-process=style/w_350 -->
  47. <image class="font u-skeleton-fillet" :src="`${homeBanner1.image}`" mode=""></image>
  48. </view>
  49. <!-- 惠选专区 hxCateList-->
  50. <ChoiceZone ref="choiceZoneRef" :skeletonShow="skeletonShow" @jumpHxCate="jumpHxCate" />
  51. <!-- 限时秒杀 -->
  52. <Seckill ref="seckillRef" :skeletonShow="skeletonShow" @goDetail="goDetail"
  53. @goProductDetails="goProductDetails" />
  54. <!-- 拼团购 -->
  55. <GroupBuy ref="groupBuyRef" :skeletonShow="skeletonShow" :bgImage="bgImage.image2" @goDetail="goDetail"
  56. @goProductDetails="goProductDetails" />
  57. <!-- 热门推荐 -->
  58. <HotRecommend ref="hotRecommendRef" :skeletonShow="skeletonShow" :bgImage="bgImage.image3" @goDetail="goDetail"
  59. @goProductDetails="goProductDetails" />
  60. <!-- 本月热销 -->
  61. <MonthlyBestSeller ref="monthlyBestSellerRef" :skeletonShow="skeletonShow" :bgImage="bgImage.image4"
  62. @goDetail="goDetail" @goProductDetails="goProductDetails" />
  63. <!-- 猜你喜欢 -->
  64. <GuessYouLike ref="guessYouLikeRef" :goodsList="goodsList" :skeletonShow="skeletonShow" :bgImage="bgImage.image5"
  65. @goDetail="goDetail" @goProductDetails="goProductDetails" />
  66. <view class="cart-entrance" @click="toCartPage()">
  67. <!-- <image :src="imgUrl + '/static/czd/car.png'" alt=""></image> -->
  68. <uv-icon name="shopping-cart" color="#000" size="32"></uv-icon>
  69. </view>
  70. <uv-skeleton :loading="skeletonShow" :animation="true" bgColor="#FFF"></uv-skeleton>
  71. </view>
  72. </view>
  73. </template>
  74. <script setup>
  75. import { ref, reactive } from "vue";
  76. import {
  77. onLoad,
  78. onShow,
  79. onPullDownRefresh,
  80. onPageScroll,
  81. onShareAppMessage
  82. } from "@dcloudio/uni-app";
  83. import { getAdList_Api, getQuickLinkList_Api } from "@/api/index.js";
  84. import { messageUnreadNum_Api } from "@/api/userInfo.js";
  85. import ChoiceZone from "./components/ChoiceZone.vue";
  86. import Seckill from "./components/Seckill.vue";
  87. import GroupBuy from "./components/GroupBuy.vue";
  88. import HotRecommend from "./components/HotRecommend.vue";
  89. import MonthlyBestSeller from "./components/MonthlyBestSeller.vue";
  90. import GuessYouLike from "./components/GuessYouLike.vue";
  91. import utils from "@/util/index.js";
  92. const choiceZoneRef = ref(null);
  93. const seckillRef = ref(null);
  94. const groupBuyRef = ref(null);
  95. const hotRecommendRef = ref(null);
  96. const monthlyBestSellerRef = ref(null);
  97. // const guessYouLikeRef = ref(null);
  98. // 响应式数据
  99. const statusBarHeight = ref(uni.getSystemInfoSync().statusBarHeight);
  100. const menuButtonHeight = ref(44);
  101. // #ifdef APP-PLUS
  102. try {
  103. let menuButtonInfo = uni.getMenuButtonBoundingClientRect()
  104. // console.log("menuButtonInfo", menuButtonInfo);
  105. menuButtonHeight.value = menuButtonInfo.height + 10;
  106. } catch (error) {
  107. console.log(error);
  108. }
  109. // #endif
  110. const showTopSearch = ref(true);
  111. const shopBanner = ref([]); //轮播图
  112. const goodsList = ref([]); //猜你喜欢
  113. const msgCenter = ref(null);
  114. const cateList = ref([]); // 一级分类
  115. const homeBanner1 = ref({});
  116. const skeletonShow = ref(true);
  117. // 背景图片
  118. const bgImage = reactive({
  119. // image1: "/static/home/home_bg1.png",
  120. // image2: "/static/home/home_bg2.png",
  121. // image3: "/static/home/home_bg3.png",
  122. // image4: "/static/home/home_bg4.png",
  123. // image5: "/static/home/home_bg5.png",
  124. image1:
  125. "https://chaonong-shop.oss-cn-beijing.aliyuncs.com/20260104/fc2943f1d3894cf6aebe9a4ed5455cec.png", // 顶部背景图
  126. image2:
  127. "https://chaonong-shop.oss-cn-beijing.aliyuncs.com/20260104/c99cd4841fca414bbc5bc0bb21b6e0f3.png", // 拼团购背景图
  128. image3:
  129. "https://chaonong-shop.oss-cn-beijing.aliyuncs.com/20260104/21296e0cec1e49e6aa44bca3d7758362.png", // 热门推荐背景图
  130. image4:
  131. "https://chaonong-shop.oss-cn-beijing.aliyuncs.com/20260104/afc6def5b92a41eaa243c557d73b588c.png", // 本月热销背景图
  132. image5:
  133. "https://chaonong-shop.oss-cn-beijing.aliyuncs.com/20260104/67d5c6eebace46f1abd3435352561968.png", // 猜你喜欢背景图
  134. });
  135. // 方法定义
  136. const getHomeBanner1 = () => {
  137. getAdList_Api("home_ad").then((res) => {
  138. if (res && res.data && res.data.length > 0) {
  139. homeBanner1.value = res.data[0];
  140. // console.log("homeBanner1", homeBanner1.value);
  141. }
  142. });
  143. };
  144. const init = () => {
  145. getBanner();
  146. getOneCate();
  147. getHomeBanner1();
  148. };
  149. // 跳转消息页面
  150. const goToMsg = () => {
  151. if (!utils.isLoginTo(true)) {
  152. uni.navigateTo({
  153. url: "/pages/user/myMsg",
  154. });
  155. }
  156. };
  157. const searchClick = () => {
  158. uni.navigateTo({
  159. url: "/pages/shop/goodSearch",
  160. });
  161. };
  162. const goProductDetails = (url) => {
  163. uni.navigateTo({
  164. url: url,
  165. });
  166. };
  167. /**获得消息数量 */
  168. const getmessageNum = () => {
  169. let token = uni.getStorageSync("apiToken");
  170. if (token) {
  171. messageUnreadNum_Api().then((res) => {
  172. if (res && res.code == 200) {
  173. msgCenter.value = res.data;
  174. }
  175. });
  176. } else {
  177. msgCenter.value = 0;
  178. }
  179. };
  180. // 一级分类
  181. const getOneCate = () => {
  182. getQuickLinkList_Api("home").then((res) => {
  183. if (res && res.code == 200) {
  184. cateList.value = res.data || [];
  185. // console.log("cateList", cateList.value);
  186. }
  187. });
  188. };
  189. const jumpHxCate = (item, area_feature) => {
  190. let url = `/pages/freeCollection/index`;
  191. if (area_feature == 0) {
  192. url += `?categoryId=${item.id}&title=${item.name}`;
  193. } else {
  194. url += `?hxCategoryId=${item.id}&title=${item.name}`;
  195. }
  196. uni.navigateTo({
  197. url: url,
  198. });
  199. };
  200. /**轮播图 */
  201. const getBanner = () => {
  202. getAdList_Api("home_banner")
  203. .then((res) => {
  204. uni.stopPullDownRefresh();
  205. if (res && res.code == 200) {
  206. shopBanner.value = res.data || [];
  207. }
  208. })
  209. .catch((err) => {
  210. console.log("err");
  211. console.log(err);
  212. });
  213. };
  214. const goDetail = (url, isNeedLogin, tabShow = false) => {
  215. if ((isNeedLogin && uni.getStorageSync("apiToken") == "") || null) {
  216. uni.$uv.toast("请先登录");
  217. return false;
  218. }
  219. if (tabShow) {
  220. uni.switchTab({
  221. url: url,
  222. });
  223. } else {
  224. uni.navigateTo({
  225. url: url,
  226. });
  227. }
  228. };
  229. const toCartPage = () => {
  230. uni.switchTab({
  231. url: "/pages/tabtar/shoppingCart",
  232. });
  233. };
  234. // 生命周期钩子
  235. onLoad((e) => {
  236. // uni.setStorageSync('invitationCode', 'UMMI5MDK');
  237. // console.log("e===>", e);
  238. skeletonShow.value = false;
  239. init();
  240. });
  241. onShow(() => {
  242. getmessageNum();
  243. });
  244. onPullDownRefresh(() => {
  245. init();
  246. if (choiceZoneRef.value) choiceZoneRef.value.init();
  247. if (seckillRef.value) seckillRef.value.init();
  248. if (groupBuyRef.value) groupBuyRef.value.init();
  249. if (hotRecommendRef.value) hotRecommendRef.value.init();
  250. if (monthlyBestSellerRef.value) monthlyBestSellerRef.value.init();
  251. // if(guessYouLikeRef.value) guessYouLikeRef.value.init();
  252. setTimeout(() => {
  253. uni.stopPullDownRefresh();
  254. }, 300);
  255. });
  256. // onReachBottom(() => {
  257. // return;
  258. // if (status.value == "more") {
  259. // page.value++;
  260. // guessLike();
  261. // }
  262. // });
  263. onPageScroll((e) => {
  264. //nvue暂不支持滚动监听,可用bindingx代替
  265. if (e.scrollTop > uni.upx2px(49 + 30)) {
  266. showTopSearch.value = false;
  267. } else {
  268. showTopSearch.value = true;
  269. }
  270. });
  271. onShareAppMessage(() => {
  272. const userInfo = uni.getStorageSync("personal") || {};
  273. return {
  274. title: "商城",
  275. path: `/pages/tabtar/home?invitationCode=${userInfo.invitationCode || ""}`,
  276. };
  277. });
  278. </script>
  279. <style scoped lang="scss">
  280. .swiper {
  281. width: 690rpx;
  282. height: 370rpx !important;
  283. // border-radius: 20rpx;
  284. overflow: hidden;
  285. margin: 0 auto;
  286. ::v-deep .uni-swiper-dot {
  287. width: 16rpx !important;
  288. height: 6rpx;
  289. border-radius: 4rpx !important;
  290. background-color: #ffffff !important;
  291. opacity: 0.5;
  292. }
  293. ::v-deep .uni-swiper-dot-active {
  294. width: 32rpx !important;
  295. height: 6rpx;
  296. border-radius: 4rpx !important;
  297. background-color: #ffffff !important;
  298. opacity: 1;
  299. }
  300. }
  301. ::v-deep.hx-navbar__content__main_search_hxicon {
  302. span {
  303. font-size: 30rpx;
  304. }
  305. }
  306. ::v-deep.hx-navbar__content__main_search_input {
  307. background-color: #4a705e;
  308. }
  309. .one-cate {
  310. display: flex;
  311. // width: 750rpx;
  312. flex-wrap: wrap;
  313. justify-content: space-between;
  314. padding: 0 31rpx;
  315. margin-top: 30rpx;
  316. color: #373737;
  317. .item {
  318. width: 120rpx;
  319. text-align: center;
  320. // margin-right: 40rpx;
  321. // &:last-child {
  322. // margin-right: 0;
  323. // }
  324. image {
  325. width: 94rpx !important;
  326. height: 94rpx !important;
  327. }
  328. .word {
  329. // margin-top: 17rpx;
  330. overflow: hidden;
  331. text-overflow: ellipsis;
  332. white-space: nowrap;
  333. }
  334. }
  335. .item:first-child {
  336. margin-left: 0;
  337. }
  338. .item:nth-child(5n + 1) {
  339. margin-left: 0;
  340. }
  341. }
  342. .bannersize {
  343. display: block;
  344. overflow: hidden;
  345. width: 100%;
  346. height: 100%;
  347. border-radius: 10rpx;
  348. }
  349. .classlist {
  350. margin: 30rpx;
  351. display: flex;
  352. justify-content: space-between;
  353. color: #373737;
  354. .item {
  355. width: 120rpx;
  356. text-align: center;
  357. // margin-right: 38rpx;
  358. // &:last-child {
  359. // margin-right: 0;
  360. // }
  361. .img-box {
  362. width: 100%;
  363. // height: 110rpx;
  364. display: flex;
  365. align-items: center;
  366. justify-content: center;
  367. image {
  368. width: 70rpx;
  369. height: 70rpx;
  370. margin-bottom: 8rpx;
  371. }
  372. text {
  373. font-size: 70rpx;
  374. }
  375. .word {
  376. overflow: hidden;
  377. text-overflow: ellipsis;
  378. white-space: nowrap;
  379. }
  380. .alarmClock {
  381. color: #eb963a;
  382. }
  383. .spell {
  384. color: #4581f6;
  385. }
  386. .integral {
  387. color: #4ea700;
  388. }
  389. .discounts {
  390. color: #f55f40;
  391. }
  392. .activeRegion {
  393. color: #4581f6;
  394. }
  395. }
  396. .font {
  397. // margin-top: 17rpx;
  398. }
  399. .imgbox {
  400. display: flex;
  401. justify-content: center;
  402. align-items: center;
  403. width: 100%;
  404. // height: 110rpx;
  405. image {
  406. width: 70rpx;
  407. height: 70rpx !important;
  408. margin-bottom: 8rpx;
  409. }
  410. }
  411. }
  412. }
  413. .swiper {
  414. // margin-top: 105rpx;
  415. height: 360rpx;
  416. .swiper-item {
  417. width: 100%;
  418. height: 100%;
  419. }
  420. }
  421. .index {
  422. position: relative;
  423. background-color: #f5f5f5;
  424. overflow-x: hidden;
  425. background-repeat: no-repeat;
  426. background-size: 100% 509rpx;
  427. }
  428. .cart-entrance {
  429. position: fixed;
  430. right: 30rpx;
  431. bottom: 180rpx;
  432. width: 50px;
  433. height: 50px;
  434. background-size: 100% 100%;
  435. border-radius: 50%;
  436. filter: drop-shadow(1px 2px 4px rgba(26, 58, 70, 0.3));
  437. background-color: #fff;
  438. display: flex;
  439. align-items: center;
  440. justify-content: center;
  441. image {
  442. width: 55%;
  443. height: 55%;
  444. margin-right: 5rpx;
  445. }
  446. }
  447. .top-box {
  448. width: 100%;
  449. &.hide {
  450. background: linear-gradient(180deg, #fbbb1b, #fbbd1c);
  451. }
  452. .title {
  453. display: flex;
  454. justify-content: center;
  455. align-items: center;
  456. position: relative;
  457. margin: 0 auto;
  458. // height: 45rpx;
  459. padding: 0 30rpx;
  460. font-size: 36rpx;
  461. font-family: PingFang SC, PingFang SC-Bold;
  462. font-weight: 700;
  463. color: #fff;
  464. // line-height: 45rpx;
  465. text-align: center;
  466. image {
  467. width: 41rpx;
  468. height: 31rpx;
  469. margin-right: 4rpx;
  470. }
  471. .titlt-txt {
  472. font-size: 36rpx;
  473. }
  474. }
  475. .input-box {
  476. display: flex;
  477. justify-content: space-between;
  478. align-items: center;
  479. position: sticky;
  480. top: 0;
  481. z-index: 100;
  482. width: 100%;
  483. padding: 0rpx 30rpx 30rpx;
  484. box-sizing: border-box;
  485. .text {
  486. margin-right: 20rpx;
  487. margin-left: 0rpx;
  488. font-weight: 500;
  489. font-size: 28rpx;
  490. color: #aed8b9;
  491. }
  492. .input-placeholder {
  493. // flex: 1;
  494. box-sizing: border-box;
  495. display: inline-block;
  496. vertical-align: middle;
  497. width: 630rpx;
  498. height: 70rpx;
  499. line-height: 66rpx;
  500. // background: rgba(2,81,43,0.3);
  501. background: rgba(255, 255, 255, 0.3);
  502. padding-left: 80rpx;
  503. // color: #666666;
  504. background: rgba(255, 255, 255, 0.3);
  505. background-image: url("/static/search.png");
  506. background-size: 40rpx 40rpx;
  507. background-position: 24rpx 50%;
  508. background-repeat: no-repeat;
  509. border: 1rpx solid rgba(255, 255, 255, 0.36);
  510. border-radius: 36rpx;
  511. }
  512. text {
  513. margin-left: 10rpx;
  514. display: inline-block;
  515. vertical-align: middle;
  516. font-size: 42rpx;
  517. font-weight: 400;
  518. text-align: right;
  519. color: #ffffff;
  520. line-height: 42rpx;
  521. &.iconfont2 {
  522. font-size: 55rpx;
  523. }
  524. }
  525. .msgCenter {
  526. position: relative;
  527. text {
  528. min-width: 50rpx;
  529. font-size: 20rpx;
  530. color: #ffffff;
  531. font-weight: 400;
  532. padding: 0 4rpx;
  533. background-color: #ff0000;
  534. border-radius: 13rpx;
  535. border: 2rpx solid #fff;
  536. text-align: center;
  537. position: absolute;
  538. left: 10rpx;
  539. top: -30rpx;
  540. line-height: normal;
  541. }
  542. }
  543. .shareBtn {
  544. margin-left: 10rpx;
  545. padding: 0;
  546. background: transparent;
  547. line-height: initial;
  548. }
  549. .shareBtn::after {
  550. border: none;
  551. }
  552. }
  553. .input-placeholder {
  554. color: #fee3cf;
  555. opacity: 0.74;
  556. font-size: 28rpx;
  557. font-family: PingFang SC, PingFang SC-Regular;
  558. font-weight: 400;
  559. text-align: left;
  560. line-height: 70rpx;
  561. }
  562. }
  563. .top-box.hide {
  564. position: fixed;
  565. z-index: 9999;
  566. }
  567. .notice-box {
  568. height: 92rpx;
  569. font-size: 28rpx;
  570. margin-bottom: 0;
  571. ::v-deep .uni-noticebar-icon {
  572. width: 40rpx;
  573. // background-image: url('/static/home/noticebar-icon.png');
  574. background-size: cover;
  575. color: transparent !important;
  576. }
  577. }
  578. .mt120 {
  579. margin-top: 240rpx;
  580. }
  581. .banner1Cls {
  582. text-align: center;
  583. margin-top: 20rpx;
  584. image {
  585. width: 690rpx;
  586. height: 200rpx;
  587. }
  588. }
  589. </style>