storeIndex.vue 17 KB

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