storeIndex.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. <template>
  2. <view class="content">
  3. <view class="top-content">
  4. <view class="status_bar" :style="{height: statusBarHeight}"></view>
  5. <!-- 这里是状态栏 -->
  6. <view class="top-title">
  7. <u-icon name="arrow-left" color="#fff" size="24" @click="navback()"></u-icon>
  8. <view class="search-cont">
  9. <view class="inner">
  10. <image class="icon-search" src="https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/icon_search.png" mode=""></image>
  11. <input type="text" disabled confirm-type="搜索" @click="toSearch" placeholder="查找店内药品" placeholder-style="font-size:28rpx;color:#BBBBBB;font-family: PingFang SC;" />
  12. </view>
  13. </view>
  14. </view>
  15. <view class="storebox x-bc">
  16. <view class="x-f">
  17. <image class="logo" :src="storeInfo.logoUrl" mode="aspectFill"></image>
  18. <view class="storebox-r" @click="goStoreDetail">
  19. <view class="storename ellipsis2">{{storeInfo.storeName}}</view>
  20. <!-- <view class="storedesc">24小时营业 销售{{storeInfo.salesCount|| 0}}</view> -->
  21. </view>
  22. </view>
  23. <!-- <view class="storebox-btn" @click="goStoreDetail">详情</view> -->
  24. </view>
  25. <view class="top-fixed x-ac" style="background-color: #fff;">
  26. <view>
  27. <u-tabs
  28. :scrollable="false"
  29. :list="tabs"
  30. lineColor="#2583EB"
  31. :current="current"
  32. @change="tabChange">
  33. </u-tabs>
  34. </view>
  35. </view>
  36. </view>
  37. <view v-show="current!=1" :style="{paddingTop: mescrollTop+'px'}">
  38. <tuiStoreProduct ref="tuiStoreProduct" :top="mescrollTop" :storeId="storeId" @refreshElementTop="getElementTop"></tuiStoreProduct>
  39. <view class="evaluate">
  40. <view class="title">店内商品评价({{evaluateTotal}})</view>
  41. <evaluateItem v-for="(item,index) in evaluate" :key="index" :item="item"></evaluateItem>
  42. <view class="footer-desc" v-if="evaluate&&evaluate.length>0">
  43. <text @click="moreEvaluate">查看更多评价</text>
  44. <image src="https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/shop/image/arrow_gray.png"></image>
  45. </view>
  46. </view>
  47. <detail class="store-detail" ref="getStoreInfo" :storeInfo="storeInfo"></detail>
  48. </view>
  49. <view v-if="current==1" class="medic-box">
  50. <view class="cate-list" :style="{top: mescrollTop+'px',height:divHeight}">
  51. <view
  52. v-for="(item,index) in cates"
  53. :key="index"
  54. :class="cateSelect == item.cateId?'item active':'item'"
  55. @click="choseCate(item)"
  56. >{{item.cateName }}</view>
  57. </view>
  58. <view class="medic">
  59. <mescroll-body :top="mescrollTop+'px'" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption">
  60. <view style="padding-right: 16rpx;">
  61. <medicineItem v-for="(item, index) in dataList" :key="index" :item="item" :storeId="storeId"></medicineItem>
  62. <!-- <medicineVerticalItem v-for="(item, index) in dataList" :key="index" :item="item" :storeId="storeId"></medicineVerticalItem> -->
  63. </view>
  64. </mescroll-body>
  65. <!-- 轮播图 -->
  66. <!-- <view class="banner-box">
  67. <swiper
  68. class="swiper"
  69. :indicator-dots="true"
  70. :circular="true"
  71. :autoplay="true"
  72. :interval="3000"
  73. :duration="1000"
  74. indicator-color="rgba(255, 255, 255, 0.6)"
  75. indicator-active-color="#ffffff"
  76. >
  77. <swiper-item class="swiper-item" v-for="(item,index) in advs" :key="index" @click="handleAdvClick(item)">
  78. <image :src="item.imageUrl" mode=""></image>
  79. </swiper-item>
  80. </swiper>
  81. </view> -->
  82. </view>
  83. </view>
  84. </view>
  85. </template>
  86. <script>
  87. import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
  88. import tuiStoreProduct from './components/tuiStoreProduct.vue'
  89. import qualifications from './components/qualifications.vue'
  90. import {getProductCate,storeDetail,getProducts} from '@/api/index.js'
  91. import medicineVerticalItem from "@/components/medicineVerticalItem";
  92. import medicineItem from "@/components/medicineItem";
  93. import evaluateItem from "@/components/evaluateItem";
  94. import detail from '@/components/storeDetail.vue'
  95. import {selectCommentByUser} from '@/api/myStoreOrder.js'
  96. // import {getAdv} from '@/api/adv'
  97. export default {
  98. mixins: [MescrollMixin], // 使用mixin
  99. components: {
  100. tuiStoreProduct,
  101. qualifications,
  102. medicineVerticalItem,
  103. medicineItem,
  104. evaluateItem,
  105. detail
  106. },
  107. data() {
  108. return {
  109. divHeight:'0px',
  110. allCates:[],
  111. cates:[],
  112. subCates:[],
  113. // 状态栏的高度
  114. statusBarHeight: uni.getStorageSync('menuInfo').statusBarHeight,
  115. // 选中药品分类
  116. cateSelect: 0,
  117. // 轮播图
  118. advs: [],
  119. tabs:[
  120. {
  121. id:1,
  122. name:'推荐'
  123. },
  124. {
  125. id:2,
  126. name:'分类'
  127. },
  128. {
  129. id:3,
  130. name:'评价'
  131. },
  132. {
  133. id:4,
  134. name:'详情'
  135. }
  136. ],
  137. current:0,
  138. storeInfo: {},
  139. storeId:'',
  140. mescroll:null,
  141. downOption: { //下拉刷新
  142. use:true,
  143. auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
  144. },
  145. // 上拉加载的配置
  146. upOption: {
  147. onScroll:true,
  148. use: true, // 是否启用上拉加载; 默认true
  149. page: {
  150. num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
  151. size: 10 // 每页数据的数量,默认10
  152. },
  153. noMoreSize: 10, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
  154. empty: {
  155. icon:'https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/app/newImages/empty_icon.png',
  156. tip: '暂无数据'
  157. },
  158. textNoMore:"已经到底了",
  159. },
  160. // 列表数据
  161. dataList: [],
  162. form:{
  163. defaultOrder:'desc',
  164. newOrder:null,
  165. priceOrder:null,
  166. salesOrder:null,
  167. productName:"",
  168. storeId: "",
  169. cateId:'',
  170. pid:'',
  171. storeId: ''
  172. },
  173. mescrollTop: 200,
  174. evaluate: [],
  175. evaluateTotal: 0,
  176. isScrollUpdating: false, // 标志位
  177. evaluateTop: 0,
  178. storeDetailTop: 0
  179. };
  180. },
  181. onLoad(option) {
  182. this.storeId = option.storeId
  183. this.form.storeId = option.storeId || ''
  184. uni.showShareMenu({
  185. withShareTicket:true,
  186. //小程序的原生菜单中显示分享按钮,才能够让发送给朋友与分享到朋友圈两个按钮可以点击
  187. menus:["shareAppMessage","shareTimeline"] //不设置默认发送给朋友
  188. })
  189. this.getProductCate();
  190. this.getStoreInfo();
  191. this.getCommentByUser();
  192. },
  193. onReady() {
  194. this.$refs.tuiStoreProduct.getProducts(this.storeId)
  195. },
  196. onShow() {
  197. var that=this;
  198. setTimeout(function(){
  199. let info = uni.createSelectorQuery().select(".top-content");
  200.     info.boundingClientRect(function(data) { //data - 各种参数
  201. //       console.log(data.height) // 获取元素宽度
  202. // console.log(uni.upx2px(10))
  203. that.divHeight="calc(100% - "+data.height+"px)"
  204. that.mescrollTop = data.height
  205.    }).exec()
  206. },500);
  207. },
  208. onPageScroll(e) {
  209. if (this.isScrollUpdating) return;
  210. const scrollTop = e.scrollTop;
  211. if (this.evaluateTop && this.storeDetailTop) {
  212. if (scrollTop >= this.storeDetailTop) {
  213. this.current = 3;
  214. } else if (scrollTop >= this.evaluateTop) {
  215. this.current = 2;
  216. } else {
  217. this.current = 0; // 或其他默认值
  218. }
  219. }
  220. },
  221. methods:{
  222. getElementTop(type) {
  223. this.$nextTick(() => {
  224. const query = uni.createSelectorQuery().in(this);
  225. query.select('.evaluate').boundingClientRect();
  226. query.select('.store-detail').boundingClientRect(); // 注意:ref 不能直接用于 select,需要加 class
  227. query.exec(res => {
  228. this.evaluateTop = res[0]?.top - this.mescrollTop || 0;
  229. this.storeDetailTop = res[1]?.top - this.mescrollTop || 0;
  230. });
  231. });
  232. },
  233. getStoreInfo() {
  234. storeDetail(this.storeId).then(res=>{
  235. if(res.code==200) {
  236. this.storeInfo =res.data || {}
  237. // if (this.storeInfo.doctorList && this.storeInfo.doctorList.length > 0) {
  238. // this.storeInfo.doctorList = this.storeInfo.doctorList.map(doctor => {
  239. // if (doctor.images) {
  240. // doctor.practiseImages = doctor.practiseImages.split(',').map(img => img.trim());
  241. // }
  242. // return doctor;
  243. // });
  244. // }
  245. this.storeInfo.doctorList = this.storeInfo.doctorList.map(doctor => {
  246. return {
  247. ...doctor,
  248. // 假设images字段是逗号分隔的图片字符串
  249. imagesArray: doctor.practiseImages ?
  250. doctor.practiseImages.split(',').map(img => img.trim()).filter(img => img) : []
  251. };
  252. });
  253. console.log(this.storeInfo.doctorList)
  254. }
  255. this.getElementTop('storeDetailTop');
  256. })
  257. },
  258. navback() {
  259. uni.navigateBack()
  260. },
  261. tabChange(item) {
  262. this.current=item.index
  263. this.isScrollUpdating = true;
  264. if ([0, 2, 3].includes(this.current)) {
  265. const scrollMap = {
  266. 0: 0,
  267. 2: this.evaluateTop,
  268. 3: this.storeDetailTop
  269. };
  270. setTimeout(()=>{
  271. uni.pageScrollTo({
  272. scrollTop: scrollMap[this.current] || 0 ,
  273. duration: 0,
  274. complete: () => {
  275. this.isScrollUpdating = false;
  276. }
  277. });
  278. },100)
  279. }
  280. },
  281. toSearch() {
  282. uni.navigateTo({
  283. url: '/pages_shopping/home/productSearch?storeId='+this.storeId
  284. })
  285. },
  286. handleAdvClick(item){
  287. if(item.showType==1){
  288. uni.setStorageSync('url',item.advUrl);
  289. uni.navigateTo({
  290. url:"/pages_shopping/home/h5"
  291. })
  292. }
  293. else if(item.showType==2){
  294. uni.navigateTo({
  295. url:item.advUrl
  296. })
  297. }
  298. else if(item.showType==3){
  299. uni.setStorageSync('content',item.content);
  300. uni.navigateTo({
  301. url:"/pages_shopping/home/content"
  302. })
  303. }
  304. },
  305. getAdv(){
  306. let data = {advType:2};
  307. getAdv(data).then(
  308. res => {
  309. if(res.code==200){
  310. this.advs=res.data;
  311. }
  312. },
  313. rej => {}
  314. );
  315. },
  316. getProductCate(){
  317. let data = {
  318. // storeId: this.storeId
  319. };
  320. getProductCate(data).then(
  321. res => {
  322. if(res.code==200){
  323. this.allCates=res.data;
  324. this.cates = this.allCates.filter(function (item) {
  325. return item.pid==0
  326. });
  327. if(this.cates!=null&&this.cates.length>0){
  328. this.cateSelect=this.cates[0].cateId;
  329. this.form.cateId = this.cates[0].cateId;
  330. // this.form.pid = this.cates[0].pid;
  331. this.mescroll&&this.mescroll.resetUpScroll()
  332. }
  333. }else{
  334. uni.showToast({
  335. icon:'none',
  336. title: "请求失败",
  337. });
  338. }
  339. },
  340. rej => {}
  341. );
  342. },
  343. // 药品分类选择
  344. choseCate(item) {
  345. this.cateSelect = item.cateId;
  346. // this.getSubCate()
  347. this.form.cateId = item.cateId;
  348. this.mescroll.resetUpScroll()
  349. },
  350. getSubCate(){
  351. var that=this;
  352. this.subCates = this.allCates.filter(function (item) {
  353. // let subList = that.allCates.filter(child => {
  354. // //返回每一项的子级数组
  355. // return child.pid === item.cateId
  356. // });
  357. // subList.length > 0 ? item.children = subList : [];
  358. return item.pid==that.cateSelect
  359. });
  360. },
  361. // 查看药品详情
  362. showProductList(item) {
  363. uni.navigateTo({
  364. url: '/pages_shopping/productList?cateId='+item.cateId+"&pid="+item.pid+'&storeId='+this.storeId
  365. })
  366. },
  367. goSearch(e) {
  368. if(e.detail.value!=null&&e.detail.value!=""){
  369. this.$addHisSearch(e.detail.value);
  370. }
  371. uni.navigateTo({
  372. url: '/pages_shopping/home/productList?storeId='+this.storeId+'&searchValue=' + e.detail.value
  373. })
  374. },
  375. goStoreDetail() {
  376. uni.navigateTo({
  377. url: '/pages_store/storeDetail?storeId='+this.storeId
  378. })
  379. },
  380. mescrollInit(mescroll) {
  381. this.mescroll = mescroll;
  382. },
  383. /*下拉刷新的回调 */
  384. downCallback(mescroll) {
  385. mescroll.resetUpScroll()
  386. },
  387. upCallback(page) {
  388. //联网加载数据
  389. var that = this;
  390. this.form.page=page.num;
  391. this.form.pageSize=page.size;
  392. getProducts(this.form).then(res => {
  393. if(res.code==200){
  394. //设置列表数据
  395. if (page.num == 1) {
  396. that.dataList = res.data.list;
  397. } else {
  398. that.dataList = that.dataList.concat(res.data.list);
  399. }
  400. that.mescroll.endBySize(res.data.list.length, res.data.total);
  401. }else{
  402. uni.showToast({
  403. icon:'none',
  404. title: "请求失败",
  405. });
  406. that.dataList = null;
  407. that.mescroll.endErr();
  408. }
  409. });
  410. },
  411. moreEvaluate() {
  412. uni.navigateTo({
  413. url: '/pages_shopping/evaluate?storeId='+this.storeId,
  414. })
  415. },
  416. getCommentByUser(){
  417. const param = {
  418. page: 1,
  419. pageSize: 2,
  420. storeId:this.storeId,
  421. orderId: null,
  422. productIds:null,
  423. userId: uni.getStorageSync('userId') || null,
  424. showSelf: 0
  425. }
  426. selectCommentByUser(param).then(res=>{
  427. if(res.code==200) {
  428. this.evaluate = res.data.list
  429. this.evaluateTotal = res.data.total
  430. } else {
  431. this.evaluate = []
  432. this.evaluateTotal = 0
  433. }
  434. this.getElementTop('evaluate');
  435. })
  436. }
  437. }
  438. }
  439. </script>
  440. <style lang="scss" scoped>
  441. .evaluate {
  442. padding: 30rpx 30rpx 0 30rpx;
  443. background-color: #FFFFFF;
  444. margin-bottom: 24rpx;
  445. .title {
  446. font-family: PingFang SC, PingFang SC;
  447. font-weight: 600;
  448. font-size: 30rpx;
  449. color: #222222;
  450. padding-bottom: 24rpx;
  451. }
  452. .footer-desc {
  453. text-align: center;
  454. padding: 0 32rpx 24rpx 0;
  455. font-size: 28rpx;
  456. color: #999;
  457. image{
  458. margin-left: 10rpx;
  459. width:15rpx;
  460. height:20rpx;
  461. }
  462. }
  463. }
  464. .storebox {
  465. padding: 26rpx 32rpx;
  466. font-family: PingFang SC, PingFang SC;
  467. color: #FFFFFF;
  468. .logo {
  469. width: 104rpx;
  470. height: 104rpx;
  471. background: #FFFFFF;
  472. border-radius: 16rpx 16rpx 16rpx 16rpx;
  473. margin-right: 26rpx;
  474. }
  475. .storename {
  476. font-weight: 500;
  477. font-size: 32rpx;
  478. }
  479. .storedesc {
  480. margin-top: 12rpx;
  481. font-weight: 400;
  482. font-size: 22rpx;
  483. }
  484. .storebox-r {
  485. flex: 1;
  486. overflow: hidden;
  487. }
  488. .storebox-btn {
  489. flex-shrink: 0;
  490. padding: 10rpx 16rpx;
  491. background: rgba(46, 218, 212, 0.50);
  492. font-size: 28rpx;
  493. border-radius: 8rpx 8rpx 8rpx 8rpx;
  494. }
  495. }
  496. .content{
  497. height: 100%;
  498. display: flex;
  499. flex-direction: column;
  500. .top-content{
  501. position: fixed;
  502. left: 0;
  503. top: 0;
  504. width: 100%;
  505. z-index: 10;
  506. background-repeat: no-repeat;
  507. background-image: url('https://bjyjb-1362704775.cos.ap-chongqing.myqcloud.com/app/image/index_img/home_top_bg.png');
  508. background-size: 100% 100%;
  509. .top-title{
  510. height: 88upx;
  511. line-height: 88upx;
  512. font-size: 42upx;
  513. font-family: Source Han Sans CN;
  514. font-weight: bold;
  515. color: #222222;
  516. padding-left: 41upx;
  517. background-color: transparent;
  518. display: flex;
  519. align-items: center;
  520. }
  521. .search-cont{
  522. padding: 6upx 30upx;
  523. .inner{
  524. box-sizing: border-box;
  525. width: 70%;
  526. height: 72upx;
  527. background: #FFFFFF;
  528. border-radius: 36upx;
  529. display: flex;
  530. align-items: center;
  531. padding: 0 30upx;
  532. .icon-search{
  533. width: 28upx;
  534. height: 28upx;
  535. margin-right: 20upx;
  536. }
  537. input{
  538. height: 60upx;
  539. line-height: 60upx;
  540. flex: 1;
  541. }
  542. }
  543. }
  544. }
  545. .medic-box{
  546. display: flex;
  547. background: #fff;
  548. ::v-deep{
  549. .mescroll-body, .mescroll-body{
  550. padding-left: 204rpx;
  551. }
  552. }
  553. .cate-list{
  554. position: fixed;
  555. left: 0;
  556. z-index: 999;
  557. box-sizing: border-box;
  558. width: 180upx;
  559. background: #F2F5F9;
  560. display: flex;
  561. flex-direction: column;
  562. padding: 20upx 0;
  563. overflow-y: scroll;
  564. .item{
  565. height: 100upx;
  566. line-height: 100upx;
  567. padding-left: 20upx;
  568. font-size: 28upx;
  569. font-family: PingFang SC;
  570. font-weight: 500;
  571. color: #333333;
  572. position: relative;
  573. &.active{
  574. color: #2583EB;
  575. &::after{
  576. content: "";
  577. width: 8upx;
  578. height: 50upx;
  579. background: #2583EB;
  580. position: absolute;
  581. top: 25upx;
  582. left: 0;
  583. }
  584. }
  585. }
  586. }
  587. .medic{
  588. overflow: hidden;
  589. box-sizing: border-box;
  590. .banner-box{
  591. margin-top: 30rpx;
  592. width: 100%;
  593. height: 160upx;
  594. border-radius: 10upx;
  595. overflow: hidden;
  596. .swiper,
  597. .swiper-item,
  598. .swiper-item image{
  599. width: 100%;
  600. height: 100%;
  601. }
  602. }
  603. }
  604. }
  605. }
  606. </style>