index.vue 18 KB

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