home.vue 16 KB

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