index.vue 19 KB

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