index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. <template>
  2. <view class="index">
  3. <view class="page-title" />
  4. <!-- 轮播图 -->
  5. <view class="banner_box">
  6. <view class="banner_list" v-if="bannerList.length">
  7. <swiper class="banner_swiper" :autoplay="true">
  8. <swiper-item v-for="(item, index) in bannerList" :key="index" style="border-radius: 8px">
  9. <image :src="item.thumb" class="image" @click="navLottery(item.link_url)"></image>
  10. </swiper-item>
  11. </swiper>
  12. </view>
  13. </view>
  14. <view class="icon-list">
  15. <icon-list mode="row8" :icons="icons" :gap="0" />
  16. </view>
  17. <!-- <view class="notice-list">
  18. <notice-list :noticeList="[{ text: '开邻智数新版本发布啦~' }, { text: '更多新功能敬请期待~' }]" gap="18" />
  19. </view> -->
  20. <view class="header-title">
  21. <components-header title="专区导航" />
  22. </view>
  23. <view class="banner-list">
  24. <banner-list :images="banners" mode="grid" :gap="16" />
  25. </view>
  26. <view class="header-title">
  27. <components-header title="推荐商品" />
  28. </view>
  29. <view class="product_box">
  30. <view class="to_bottom" v-if="!productList.length"> -----还没有产品啦-----</view>
  31. <!-- 产品列表 -->
  32. <view class="product_list">
  33. <!-- Vue3 项目部分小程序端事件延迟或调用失败 在执行事件的元素上添加 data-eventsync="true" 属性以解决此问题 -->
  34. <view @click="toDetail(item)" data-eventsync="true" class="product_item" v-for="(item, index) in productList" :key="index">
  35. <view class="product_item_content">
  36. <view class="product_image_content">
  37. <image class="product_image" :src="item.thumb" mode=""></image>
  38. </view>
  39. <view>
  40. <view class="product_name">
  41. <text v-if="item.promo_title" class="regiment_title">{{ item.promo_title }}</text>
  42. <text v-if="item.regiment_title" class="regiment_title">{{ item.regiment_title }}</text>
  43. <text>{{ item.name }}</text></view
  44. >
  45. <view class="product_spec"
  46. ><text>{{ item.spec }}</text></view
  47. ></view
  48. >
  49. </view>
  50. <view class="product_item_bottom">
  51. <view class="stock_price">
  52. <view class="product_price" v-if="isShowPrice">
  53. <text>¥{{ item.price }} </text>
  54. </view>
  55. <view class="product_stock">剩{{ item.stock }}个</view>
  56. </view>
  57. <view class="stock_button">立即抢购</view>
  58. </view>
  59. </view>
  60. </view>
  61. </view>
  62. <view class="search_fixed">
  63. <view class="search_box">
  64. <view class="city_name" v-if="!toSelectedCity">
  65. <navigator url="/pages/user/info" v-if="isManager">{{ cityName }}</navigator>
  66. <text v-if="!isManager">{{ cityName }}</text>
  67. </view>
  68. <navigator url="/pages/user/info" v-if="toSelectedCity" class="city_name uncheck">选城市</navigator>
  69. <input class="search_input" type="text" v-model="requestParam.name" @input="searchChange" placeholder="请输入产品名称搜索" />
  70. <button class="search_btn" @click.stop="searchOpen()" data-eventsync="true">搜索</button>
  71. </view>
  72. </view>
  73. <view class="to_bottom" v-if="isLast" style="display: flex; justify-content: center">
  74. -----
  75. <view :style="!productList.length && toSelectedCity ? 'font-weight:bold;font-size:36rpx' : ''">{{ !productList.length && toSelectedCity ? '请点击左上角选择你的城市' : '到底啦' }}</view> -----
  76. </view>
  77. <uni-popup ref="addFollow" type="center" class="center_popup">
  78. <FollowPopup :closePopup="closePopup" />
  79. </uni-popup>
  80. <cc-myTabbar :tabBarShow="0"></cc-myTabbar>
  81. </view>
  82. </template>
  83. <script>
  84. import FollowPopup from '@/components/FollowPopup/FollowPopup.vue';
  85. import IconList from '@/components/IconList';
  86. import NoticeList from '@/components/Notice';
  87. import BannerList from '@/components/Banner';
  88. import ComponentsHeader from '@/components/ComponentsHeader';
  89. const Icons = [
  90. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d3fed51fa2.ng', text: '全品', urlMap: { internal_url: '/pages/product/list' } },
  91. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d3ffdea775.ng', text: '医保价', urlMap: { internal_url: '/pages/wait/index?id=1&name=医保价' } },
  92. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d400fd5932.ng', text: '行业资讯', urlMap: { internal_url: '/pages/article/index' } },
  93. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d401d6a885.ng', text: '直播', urlMap: { internal_url: '/pages/wait/index?id=101&name=直播' } },
  94. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d402ddaeb6.ng', text: '促销活动', urlMap: { internal_url: '/pages/wait/index?id=2&name=促销活动' } },
  95. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d404366cf8.ng', text: '拼团包邮', urlMap: { internal_url: '/pages/wait/index?id=3&name=拼团包邮' } },
  96. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d404c65d9f.ng', text: '积分商城', urlMap: { internal_url: '/pages/score/index' } },
  97. { image: 'https://openwork-oss.oss-cn-shenzhen.aliyuncs.com/uploads/c/1/s/92/up/20250521/682d40561a23b.ng', text: '领券中心', urlMap: { internal_url: '/pages/coupon/index' } },
  98. ];
  99. const Banners = [
  100. { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/active.png', text: '区域活动', urlMap: { internal_url: '/pages/wait/index?id=4&name=区域活动' } },
  101. { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/b2b.png', text: 'B2B专供', urlMap: { internal_url: '/pages/wait/index?id=5&name=B2B专供' } },
  102. { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/exp.png', text: '近效期', urlMap: { internal_url: '/pages/wait/index?id=6&name=近效期' } },
  103. { image: 'https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/heath.png', text: '大健康', urlMap: { internal_url: '/pages/wait/index?id=11&name=大健康' } },
  104. ];
  105. export default {
  106. components: { FollowPopup, IconList, NoticeList, BannerList, ComponentsHeader },
  107. data() {
  108. return {
  109. // 轮播图
  110. bannerList: [],
  111. // 产品列表
  112. productList: [],
  113. // 请求参数
  114. requestParam: {
  115. name: '',
  116. page: 1,
  117. get_top: 1,
  118. },
  119. // 是否最后一页
  120. isLast: false,
  121. // 是否请求中
  122. isReqing: false,
  123. // 是否显示价格
  124. isShowPrice: false,
  125. // 城市名称
  126. cityName: '选城市',
  127. // 选择城市
  128. toSelectedCity: false,
  129. // 是否是管理员
  130. isManager: false,
  131. icons: Icons,
  132. banners: Banners,
  133. };
  134. },
  135. onLoad() {
  136. // #ifdef MP-WEIXIN
  137. uni.hideTabBar();
  138. //分享按钮
  139. uni.showShareMenu({
  140. withShareTicket: true,
  141. menus: ['shareAppMessage', 'shareTimeline'],
  142. });
  143. // #endif
  144. },
  145. onShareAppMessage(obj) {
  146. // 获取分享信息
  147. let shareList = getApp().globalData.shareList;
  148. // 获取分享信息
  149. let shareObj = {
  150. title: '999智控终端平台\n药优惠 得积分 兑豪礼',
  151. path: '/pages/index/index',
  152. imageUrl: '',
  153. };
  154. // 循环列表
  155. for (let i in shareList) {
  156. if (shareList[i].pages == 'pages/index/index') {
  157. shareObj.path = shareList[i].path ? shareList[i].path : shareObj.path;
  158. shareObj.title = shareList[i].title ? `999智控终端平台\n${shareList[i].title}` : shareObj.title;
  159. shareObj.imageUrl = shareList[i].image_url ? shareList[i].image_url : shareObj.imageUrl;
  160. }
  161. }
  162. // 返回分享信息
  163. return shareObj;
  164. },
  165. onShow() {
  166. // 是否显示价格
  167. this.isShowPrice = this.$checkAccess.checkShowPrice();
  168. // 城市名
  169. this.cityName = this.$checkAccess.getCity();
  170. // 选城市
  171. (this.cityName = this.cityName ? this.cityName : '选城市'),
  172. // 登录并且未选择城市,才可以选择城市
  173. (this.toSelectedCity = !this.$checkAccess.getCity() ? true : false);
  174. // 数据
  175. //未选城市先弹窗提醒选择城市
  176. if (!this.$checkAccess.getCity() && this.$checkAccess.checkLogin()) {
  177. uni.showModal({
  178. title: '',
  179. content: '请先选择城市',
  180. success: (res) => {
  181. if (res.confirm) {
  182. uni.navigateTo({
  183. url: '/pages/user/info',
  184. });
  185. }
  186. },
  187. });
  188. }
  189. //如果已选城市且没有添加客服每天弹窗一次
  190. if (this.$checkAccess.getCity() && this.$checkAccess.getFollowQrcode()) {
  191. // 获取弹出时间
  192. let followPopupTime = uni.getStorageSync('followPopupTime');
  193. // 现在的时候
  194. let nowTime = new Date().getTime();
  195. // 时间戳
  196. followPopupTime = followPopupTime ? followPopupTime : 0;
  197. // 弹出结果
  198. if (followPopupTime <= 0 || followPopupTime - nowTime > 86400000) {
  199. this.$refs.addFollow.open('center');
  200. uni.setStorageSync('followPopupTime', nowTime);
  201. }
  202. }
  203. this.isManager = this.$checkAccess.isManager();
  204. // 没有数据的话,或者请求中,不允许刷新
  205. if (this.isReqing) return;
  206. // 获取列表
  207. this.$http.request('/api/banner/get_list').then((re) => {
  208. if (re.code === 'success') {
  209. this.bannerList = re.data;
  210. }
  211. });
  212. // 请求参数
  213. this.requestParam.name = '';
  214. // 请求参数
  215. this.requestParam.page = 1;
  216. // 是否是最后一页
  217. this.isLast = false;
  218. // 设置请求中
  219. this.isReqing = true;
  220. // 请求
  221. this.$http.request('api/product/get_list', this.requestParam).then((re) => {
  222. // 设置非请求中
  223. this.isReqing = false;
  224. // 成功结果
  225. if (re.code == 'success') {
  226. // 如果是最后一页
  227. if (re.data.last_page <= this.requestParam.page) this.isLast = true;
  228. // 赋值
  229. this.productList = re.data.data;
  230. // 获取下一页
  231. this.getMore(re);
  232. }
  233. });
  234. },
  235. onPullDownRefresh() {
  236. // 如果请求中,不允许请求,
  237. if (this.isReqing) return false;
  238. // 初始化页码为1
  239. this.requestParam.page = 1;
  240. // 是否是最后一页
  241. this.isLast = false;
  242. // 设置请求中
  243. this.isReqing = true;
  244. // 请求列表
  245. this.$http.request('api/product/get_list', this.requestParam).then((re) => {
  246. // 设置非请求中
  247. this.isReqing = false;
  248. // 成功结果
  249. if (re.code == 'success') {
  250. // 如果是最后一页
  251. if (re.data.last_page <= this.requestParam.page) this.isLast = true;
  252. // 赋值
  253. this.productList = re.data.data;
  254. // 获取下一页
  255. this.getMore(re);
  256. }
  257. });
  258. uni.stopPullDownRefresh();
  259. },
  260. // onReachBottom() {
  261. // // 如果页码是0,避免第一页重复
  262. // if (this.requestParam.page < 1) return;
  263. // // 最后一页不再请求
  264. // if (this.isLast) return;
  265. // // 请求中,不再请求
  266. // if (this.isReqing) return;
  267. // // 增加一页
  268. // this.requestParam.page = this.requestParam.page + 1;
  269. // // 设置请求中
  270. // this.isReqing = true;
  271. // // 请求列表
  272. // this.$http.request('api/product/get_list', this.requestParam).then((re) => {
  273. // // 设置非请求中
  274. // this.isReqing = false;
  275. // // 成功结果
  276. // if (re.code == 'success') {
  277. // // 最后一页
  278. // if (re.data.last_page <= this.requestParam.page) this.isLast = true;
  279. // // 追加数据
  280. // this.productList.push(...re.data.data);
  281. // }
  282. // });
  283. // },
  284. methods: {
  285. // 请求加载下一页
  286. getMore(callback) {
  287. // 首页不足10个,并且下一页存在大于当前页
  288. if (this.productList.length < 10 && callback.data.last_page > this.requestParam.page) {
  289. // 最后一页不再请求
  290. if (this.isLast) return;
  291. // 增加一页
  292. this.requestParam.page = this.requestParam.page + 1;
  293. // 请求列表
  294. this.$http.request('api/product/get_list', this.requestParam).then((re) => {
  295. // 成功结果
  296. if (re.code == 'success') {
  297. // 最后一页
  298. if (re.data.last_page <= this.requestParam.page) this.isLast = true;
  299. // 追加数据
  300. this.productList.push(...re.data.data);
  301. // 获取下一页
  302. this.getMore(re);
  303. }
  304. });
  305. }
  306. },
  307. searchChange(e) {
  308. // 如果没有搜索词
  309. if (!this.requestParam.name) {
  310. this.searchOpen();
  311. }
  312. },
  313. searchOpen() {
  314. // 请求中,不再请求
  315. if (this.isReqing) return;
  316. // 是否是最后一页
  317. this.isLast = false;
  318. // 初始化页码为1
  319. this.requestParam.page = 1;
  320. // 设置请求中
  321. this.isReqing = true;
  322. // 请求列表
  323. this.$http.request('api/product/get_list', this.requestParam).then((re) => {
  324. // 设置非请求中
  325. this.isReqing = false;
  326. // 成功结果
  327. if (re.code == 'success') {
  328. this.productList = re.data.data;
  329. if (re.data.data.length && re.data.last_page >= this.requestParam.page) this.isLast = true;
  330. }
  331. });
  332. },
  333. toDetail(item) {
  334. uni.navigateTo({
  335. url: '/pages/product/index?product_id=' + item.id,
  336. });
  337. },
  338. navLottery(url) {
  339. // 没有路径,不跳转
  340. if (!url) return;
  341. // 判断是不是小程序链接
  342. if (url.includes('http')) {
  343. // 转码
  344. let link_url = encodeURIComponent(url);
  345. // 跳转到webview
  346. uni.redirectTo({
  347. url: `/pages/webview/index?link_url=${link_url}`,
  348. });
  349. } else {
  350. // 跳转到webview
  351. uni.navigateTo({
  352. url: url,
  353. });
  354. }
  355. },
  356. closePopup() {
  357. this.$refs.addFollow.close();
  358. //存key以及时间
  359. uni.setStorage({
  360. key: 'followPopupTime',
  361. data: new Date().getTime(),
  362. });
  363. },
  364. },
  365. };
  366. </script>
  367. <style lang="less">
  368. .index {
  369. // background-image: url(https://kailin-mp.oss-cn-shenzhen.aliyuncs.com/static/index/index_header.png);
  370. // background-position: 0% 0%;
  371. // background-repeat: no-repeat;
  372. // background-size: 750rpx 588rpx;
  373. }
  374. .page-title {
  375. //渐变加透明;
  376. // background: linear-gradient(to bottom, rgba(245, 52, 29, 1) 0%, rgba(255, 255, 255, 0) 100%);
  377. // background: linear-gradient(180deg, #ea310f 0%, #f5f5f5 100%);
  378. // background: url() no-repeat 100% 100%;
  379. position: absolute;
  380. top: 0;
  381. left: 0;
  382. width: 100%;
  383. height: 588rpx;
  384. z-index: -1;
  385. }
  386. .search_fixed {
  387. top: var(--window-top);
  388. left: 0rpx;
  389. width: 750rpx;
  390. display: block;
  391. position: fixed;
  392. margin: 0rpx auto;
  393. padding: 20rpx 0rpx;
  394. background-color: #ffffff;
  395. .search_box {
  396. width: 750rpx;
  397. height: 60rpx;
  398. display: block;
  399. position: relative;
  400. .city_name {
  401. float: left;
  402. width: 100rpx;
  403. height: 60rpx;
  404. display: block;
  405. font-size: 30rpx;
  406. overflow: hidden;
  407. margin-left: 35rpx;
  408. line-height: 60rpx;
  409. white-space: nowrap;
  410. text-overflow: ellipsis;
  411. }
  412. .city_name.uncheck {
  413. color: #f89c33;
  414. }
  415. .search_input {
  416. z-index: 0;
  417. float: left;
  418. width: 510rpx;
  419. height: 56rpx;
  420. display: block;
  421. font-size: 24rpx;
  422. padding-left: 20rpx;
  423. position: relative;
  424. border-top-left-radius: 40rpx;
  425. border-bottom-left-radius: 40rpx;
  426. border: 2rpx solid #dddddd;
  427. background-color: #ffffff;
  428. }
  429. .search_btn {
  430. top: 0rpx;
  431. z-index: 9;
  432. left: 610rpx;
  433. color: #ffffff;
  434. position: absolute;
  435. display: block;
  436. width: 120rpx;
  437. height: 60rpx;
  438. font-size: 24rpx;
  439. margin: 0rpx 0rpx;
  440. padding: 0rpx 0rpx;
  441. line-height: 60rpx;
  442. border-radius: 40rpx;
  443. background-color: #f89c33;
  444. }
  445. }
  446. }
  447. .banner_box {
  448. width: 680rpx;
  449. display: block;
  450. overflow: hidden;
  451. margin: 0rpx auto;
  452. margin-top: 120rpx;
  453. .banner_list {
  454. display: block;
  455. width: 680rpx;
  456. height: 382rpx;
  457. line-height: 382rpx;
  458. text-align: center;
  459. .banner_swiper {
  460. display: block;
  461. width: 680rpx;
  462. height: 382rpx;
  463. line-height: 382rpx;
  464. text-align: center;
  465. border-radius: 8px;
  466. .image {
  467. width: 680rpx;
  468. height: 382rpx;
  469. border-radius: 8px;
  470. }
  471. }
  472. }
  473. }
  474. .product_box {
  475. display: block;
  476. overflow: hidden;
  477. margin: -20rpx auto 20rpx;
  478. padding: 0rpx 35rpx;
  479. padding-bottom: calc(env(safe-area-inset-bottom) + 100rpx);
  480. .product_list {
  481. display: block;
  482. overflow: hidden;
  483. margin: 0rpx auto;
  484. .product_item {
  485. // float: left;
  486. width: 100%;
  487. // height: 520rpx;
  488. display: block;
  489. overflow: hidden;
  490. margin: 20rpx 0rpx;
  491. margin-right: 40rpx;
  492. background-color: #ffffff;
  493. border-radius: 20rpx;
  494. padding: 16rpx;
  495. box-sizing: border-box;
  496. .product_item_content {
  497. display: flex;
  498. gap: 10rpx;
  499. }
  500. .product_item_bottom {
  501. display: flex;
  502. justify-content: space-between;
  503. align-items: center;
  504. }
  505. .product_image_content {
  506. width: 168rpx;
  507. height: 168rpx;
  508. background: #f5f5f5;
  509. border-radius: 16rpx 16rpx 16rpx 16rpx;
  510. display: flex;
  511. align-items: center;
  512. justify-content: center;
  513. flex-shrink: 0;
  514. }
  515. .product_image {
  516. width: 143rpx;
  517. height: 149rpx;
  518. flex-shrink: 0;
  519. }
  520. .product_name {
  521. // height: 80rpx;
  522. font-size: 30rpx;
  523. line-height: 40rpx;
  524. overflow: hidden;
  525. margin: 10rpx 0rpx;
  526. padding: 0rpx 10rpx;
  527. text-overflow: ellipsis;
  528. .regiment_title {
  529. background-color: red;
  530. color: #f9f9f9;
  531. }
  532. }
  533. .product_spec {
  534. height: 30rpx;
  535. color: #999999;
  536. font-size: 24rpx;
  537. line-height: 30rpx;
  538. padding: 0rpx 10rpx;
  539. overflow: hidden;
  540. white-space: nowrap;
  541. text-overflow: ellipsis;
  542. }
  543. .stock_price {
  544. color: #dddddd;
  545. font-size: 20rpx;
  546. overflow: hidden;
  547. line-height: 30rpx;
  548. padding: 0rpx 10rpx;
  549. display: flex;
  550. gap: 10rpx;
  551. align-items: baseline;
  552. padding-left: 185rpx;
  553. box-sizing: border-box;
  554. .product_price {
  555. color: red;
  556. font-size: 30rpx;
  557. line-height: 60rpx;
  558. .product_market {
  559. font-size: 24rpx;
  560. color: #999999;
  561. line-height: 30rpx;
  562. vertical-align: top;
  563. text-decoration: line-through;
  564. }
  565. }
  566. .product_stock {
  567. font-size: 20rpx;
  568. line-height: 60rpx;
  569. }
  570. }
  571. .stock_button {
  572. width: 152rpx;
  573. height: 60rpx;
  574. background: #f89c33;
  575. border-radius: 500rpx 500rpx 500rpx 500rpx;
  576. color: #ffffff;
  577. color: 26rpx;
  578. text-align: center;
  579. line-height: 60rpx;
  580. font-size: 24rpx;
  581. }
  582. }
  583. .product_item:nth-child(even) {
  584. margin-right: 0rpx;
  585. }
  586. }
  587. }
  588. .icon-list {
  589. margin-top: 24rpx;
  590. padding: 0 35rpx;
  591. }
  592. .notice-list {
  593. margin-top: 24rpx;
  594. }
  595. .header-title {
  596. padding: 0 35rpx;
  597. }
  598. </style>