index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. <template>
  2. <view class="detail">
  3. <!-- 轮播图 -->
  4. <view class="carousel-map">
  5. <u-swiper :list="swiperList" previousMargin="30" nextMargin="30" circular bgColor="#ffffff" height="150" />
  6. <!-- <u-swiper :list="swiperList"/> -->
  7. <!-- <view class="carousel-item">
  8. <view class="mark">
  9. <view class="mark-item">{{ merchant.score }}分</view>
  10. <u-rate count="5" v-model="merchant.score" active-color="#fff" readonly inactive-color="#fff" :size="12" />
  11. </view>
  12. <view class="good-item">近期有6266个购买者给了给好评</view>
  13. </view> -->
  14. </view>
  15. <!-- 商家信息 -->
  16. <view class="merchant-info">
  17. <view class="info-title">
  18. <view>{{ merchant.name }}</view>
  19. </view>
  20. <view class="info-tag">商家信息</view>
  21. <view class="info-item">
  22. <view class="info-text">
  23. <view>营业时间:{{ merchant.opening }}</view>
  24. <view>电话号码:{{ merchant.mobile }}</view>
  25. <view>营业状态:{{ merchant.businessStatus == "1" ? "休息中" : "营业中" }}</view>
  26. <view>{{ merchant.address }}</view>
  27. <view class="distance">{{ (merchant.distance / 1000).toFixed(2) }}km</view>
  28. </view>
  29. <view class="info-icon">
  30. <view class="info-map" @click="handlerFavouriteShop">
  31. <u-icon class="user-operate-icon" :name="merchant.favorites ? 'heart-fill' : 'heart' " size="24" />
  32. <view style="font-size: 20rpx; margin-top: 5rpx">收藏</view>
  33. </view>
  34. <view class="info-map">
  35. <u-icon name="map" size="24"></u-icon>
  36. <view style="font-size: 20rpx; margin-top: 5rpx">导航</view>
  37. </view>
  38. <view class="info-map" @click="handlerMakeCall">
  39. <u-icon name="phone" size="24"></u-icon>
  40. <view style="font-size: 20rpx; margin-top: 5rpx">电话</view>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. <view class="evaluate-context">
  46. <view class="flex evaluate">
  47. <view class="flex">
  48. <text style="margin-right: 30rpx">优惠</text>
  49. <view class="text_title"> 您有{{ coupons.length }}张购物券可领取 </view>
  50. </view>
  51. <view class="flex" @click="openPopup">
  52. <text class="text_title" style="margin-right: 20rpx">去领取</text>
  53. <u-icon name="arrow-right" size="16" color="#999" />
  54. </view>
  55. </view>
  56. </view>
  57. <!-- 商家分类 -->
  58. <view class="categoryList">
  59. <u-tabs :list="categoryList" @change='handlerChangeTab'></u-tabs>
  60. </view>
  61. <view>
  62. <view class="list" :key="index" v-for="(item, index) of goods" @click="handlerSkipGoodsDetail(item, index)">
  63. <image class="img" :src="!Boolean(item.logo) ? '@/static/QR57a.jpg' : item.logo"></image>
  64. <view class="listDetail">
  65. <view class="item-text">
  66. <view class="item-text-left"> {{ item.name }} </view>
  67. <view class="item-text-right">
  68. <image class="img" src="@/static/icon/shopCar.png" @click.stop="handlerAddCart(item)"></image>
  69. </view>
  70. </view>
  71. <view class="item-flex">
  72. <view class="star">
  73. <u-rate count="5" v-model="item.score" readonly :size="14" />
  74. <text class="line">|</text>
  75. <text class="points">{{ item.score }}分</text>
  76. </view>
  77. <view>
  78. <!-- {{ item.score }}单 -->
  79. </view>
  80. </view>
  81. <view class="list-item">
  82. <view class="list-price">
  83. <view class="item-l">
  84. 优惠价 <span>¥{{ item.specialPrice.toFixed(2) }}</span>
  85. </view>
  86. <view class="item-r">
  87. 门市价 <span>¥{{ item.originalPrice.toFixed(2) }}</span>
  88. </view>
  89. </view>
  90. <view class="btn-box">
  91. <button class="btn" @click.stop="handlerService(item, index)">预约</button>
  92. <!-- <button class="btn btn2" @click.stop="handlerSkipBuy(item, index)">购买</button> -->
  93. </view>
  94. </view>
  95. </view>
  96. </view>
  97. <u-empty v-if="goods.length == 0" mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png">
  98. </u-empty>
  99. </view>
  100. <!-- 底部购物车 -->
  101. <view class="bottom-box">
  102. <settleBottomComponent :goodsCateList.sync='goodsCateList' :ids='ids' @handlerDeleteGoods='handlerDeleteGoods' />
  103. </view>
  104. <!-- 弹窗 -->
  105. <u-popup :show="reserve_show" @close="reserve_show = false" round="20" mode="center">
  106. <view class="draw-box">
  107. <view class="draw-title"> 预约服务 </view>
  108. <view class="draw-item">
  109. <view class="item-text">时间</view>
  110. <view class="time-box" @click="time_show = true" :class="template_time == '' ? 'time-text' : ''">
  111. {{ template_time == '' ? '请选择时间' : template_time }}
  112. </view>
  113. </view>
  114. <view class="draw-item">
  115. <view class="item-text">联系方式</view>
  116. <u--input placeholder="请输入联系方式" border="surround" type="number" maxlength='11' v-model="addParams.mobile"></u--input>
  117. </view>
  118. <button class="draw-btn" @click="handlerDrawConfirmBtn">确定</button>
  119. </view>
  120. </u-popup>
  121. <!-- 时间 -->
  122. <u-datetime-picker :show="time_show" :minDate="Number(new Date())" :formatter="formatter"
  123. v-model="addParams.appointTime" @change="handlerTimeChange" @confirm="time_show = false"
  124. @cancel="time_show = false" mode="datetime">
  125. </u-datetime-picker>
  126. <u-popup :show="show" mode="bottom" :safeAreaInsetBottom="true">
  127. <view>
  128. <cpuponComponents @close="closeCoupon" :coupons="coupons"></cpuponComponents>
  129. </view>
  130. </u-popup>
  131. </view>
  132. </template>
  133. <script>
  134. import {
  135. getSellsDetail,
  136. addReservation,
  137. addShoppingCart,
  138. getCartList,
  139. addFavorite,
  140. cancelFavorite,
  141. changeGoodsType
  142. } from '@/api/client/business.js';
  143. import { getCurrentLocation, hotMerchant } from '@/api/client/home';
  144. import { accountTotIdGetConponList } from "@/api/client/mine.js"
  145. // import GainCoupon from '@/pages/client/clientPackage/serviceDetail/GainCoupon.vue';
  146. import cpuponComponents from "./components/couponComponent.vue"
  147. import settleBottomComponent from "./components/settleBottomComponent.vue"
  148. import {
  149. mapGetters
  150. } from 'vuex';
  151. export default {
  152. components: {
  153. cpuponComponents,
  154. settleBottomComponent
  155. },
  156. data() {
  157. return {
  158. show: false,
  159. merchant: {},
  160. goods: [],
  161. swiperList: [],
  162. categoryList: [{
  163. name: '全部',
  164. id: 0
  165. }], // 分类列表
  166. goodsCateList: [],
  167. queryParams: {
  168. //请求参数
  169. id: null, //商家ID
  170. region: null, //地区编码
  171. longitude: null, //经度
  172. latitude: null, //纬度
  173. },
  174. time_show: false,
  175. reserve_show: false,
  176. addParams: {
  177. merchantId: '',
  178. mobile: '',
  179. appointTime: '',
  180. goodsName: ''
  181. },
  182. template_time: '',
  183. ids: null, // 商家id
  184. coupons: []
  185. };
  186. },
  187. onLoad(option) {
  188. this.ids = option.id
  189. this.queryParams.id = option.id;
  190. },
  191. mounted() {
  192. let {
  193. latitude,
  194. longitude,
  195. region
  196. } = this.location
  197. this.queryParams.latitude = latitude
  198. this.queryParams.longitude = longitude
  199. this.queryParams.region = region
  200. this.handlerInitList();
  201. },
  202. onShow() {
  203. this.handletInitShopCarList()
  204. },
  205. computed: {
  206. ...mapGetters(['location'])
  207. },
  208. watch: {
  209. reserve_show(newValue) {
  210. if (!newValue) {
  211. this.addParams.mobile = '';
  212. this.addParams.appointTime = '';
  213. this.template_time = '';
  214. }
  215. },
  216. },
  217. methods: {
  218. // 初始化购物车列表
  219. handletInitShopCarList() {
  220. this.swiperList = []
  221. getCartList(this.ids).then(res => {
  222. let {
  223. merchantDTO,
  224. cartItems
  225. } = res.data
  226. // 商品轮播图
  227. merchantDTO.banners.map(rs => {
  228. this.swiperList.push(rs.url)
  229. })
  230. if (cartItems.length == 0) {
  231. this.goodsCateList = []
  232. } else {
  233. this.goodsCateList = cartItems
  234. }
  235. })
  236. accountTotIdGetConponList(this.ids, {
  237. paging: '1,10'
  238. }).then(res => {
  239. this.coupons = res.data.records
  240. })
  241. },
  242. // 初始化列表
  243. handlerInitList() {
  244. this.categoryList = [{
  245. name: '全部',
  246. id: 0
  247. }]
  248. getSellsDetail(this.queryParams.id, this.queryParams).then(res => {
  249. this.merchant = res.data.merchant;
  250. this.goods = res.data.goods;
  251. res.data.categories.map(rs => {
  252. this.categoryList.push(rs)
  253. })
  254. });
  255. // 获取锚点
  256. hotMerchant(this.queryParams.id).then();
  257. },
  258. // 点击拨打电话
  259. handlerMakeCall() {
  260. uni.makePhoneCall({
  261. phoneNumber: this.merchant.mobile,
  262. success: res => {
  263. console.log("@@@res", res)
  264. },
  265. fail: err => {
  266. console.log("@@@err", err)
  267. }
  268. });
  269. },
  270. // 点击跳转到商品详情
  271. handlerSkipGoodsDetail(item, index) {
  272. uni.navigateTo({
  273. url: `/pagesHome/marketer/productDetail?id=${item.id}&shopId=${this.queryParams.id}`,
  274. });
  275. },
  276. // 预约
  277. handlerService(item, index) {
  278. this.addParams.merchantId = this.ids;
  279. this.addParams.goodsId = item.id;
  280. this.addParams.goodsName = item.name;
  281. this.reserve_show = true;
  282. },
  283. // 点击预约确定按钮
  284. handlerDrawConfirmBtn() {
  285. if (this.addParams.appointTime == '') {
  286. uni.showToast({
  287. title: '请选择时间',
  288. icon: 'none',
  289. });
  290. return;
  291. } else if (this.addParams.mobile == '') {
  292. uni.showToast({
  293. title: '请填写手机号',
  294. icon: 'none',
  295. });
  296. return;
  297. } else if (!/^1[34578]\d{9}$/.test(this.addParams.mobile)) {
  298. uni.showToast({
  299. title: '请填写正确的手机号',
  300. icon: 'none',
  301. });
  302. return false;
  303. } else {
  304. addReservation(this.addParams.merchantId, this.addParams).then(res => {
  305. if (res.code === 'OK') {
  306. this.handlerInitList();
  307. this.reserve_show = false;
  308. uni.showToast({
  309. title: '预约成功',
  310. icon: 'success',
  311. });
  312. } else {
  313. uni.showToast({
  314. title: res.msg,
  315. icon: 'none',
  316. });
  317. return;
  318. }
  319. });
  320. }
  321. },
  322. // 收藏按钮
  323. handlerFavouriteShop() {
  324. if (this.merchant.favorites) {
  325. cancelFavorite(this.ids).then(res => {
  326. if (res.code === 'OK') {
  327. this.handlerInitList()
  328. uni.showToast({
  329. title: '取消成功',
  330. icon: 'none'
  331. })
  332. } else {
  333. uni.showToast({
  334. title: res.msg,
  335. icon: 'none'
  336. })
  337. return
  338. }
  339. })
  340. } else {
  341. addFavorite(this.ids).then(res => {
  342. if (res.code === 'OK') {
  343. this.handlerInitList()
  344. uni.showToast({
  345. title: '收藏成功',
  346. icon: 'none'
  347. })
  348. } else {
  349. uni.showToast({
  350. title: res.msg,
  351. icon: 'none'
  352. })
  353. return
  354. }
  355. })
  356. }
  357. },
  358. // 添加购物车
  359. handlerAddCart(e) {
  360. let params = {
  361. merchantId: this.ids,
  362. goodsId: e.id,
  363. quantity: 1,
  364. price: e.specialPrice,
  365. goodsName: e.name,
  366. goodsPic: e.logo,
  367. originalPrice: e.originalPrice,
  368. }
  369. addShoppingCart(params).then(res => {
  370. if (res.code === 'OK') {
  371. this.handletInitShopCarList()
  372. } else {
  373. uni.showToast({
  374. title: res.msg,
  375. icon: 'none'
  376. })
  377. return
  378. }
  379. })
  380. },
  381. formatter(type, value) {
  382. if (type === 'minute') {
  383. return `00`;
  384. }
  385. return value;
  386. },
  387. // 选择时间
  388. handlerTimeChange(e) {
  389. if (e) {
  390. this.addParams.appointTime = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss');
  391. this.template_time = this.addParams.appointTime;
  392. }
  393. },
  394. handlerDeleteGoods(e) {
  395. this.handletInitShopCarList()
  396. },
  397. // 切换tab
  398. handlerChangeTab(e) {
  399. if (e.id == 0) {
  400. this.handlerInitList()
  401. } else {
  402. changeGoodsType(this.ids, {
  403. categoryId: e.id,
  404. size: 20
  405. }).then(res => {
  406. this.goods = res.data;
  407. })
  408. }
  409. },
  410. openPopup() {
  411. this.show = true;
  412. },
  413. closeCoupon(data) {
  414. this.show = data;
  415. },
  416. },
  417. };
  418. </script>
  419. <style lang="scss" scoped>
  420. .detail {
  421. min-height: calc(100vh - 200rpx);
  422. background-color: #efefef;
  423. padding-bottom: 200rpx;
  424. }
  425. // 轮播图
  426. .carousel-map {
  427. background-color: #fff;
  428. padding: 0 20rpx;
  429. .carousel-item {
  430. height: 90rpx;
  431. display: flex;
  432. background-color: #fff7e0;
  433. border-radius: 0 0 10rpx 10rpx;
  434. .mark {
  435. background-color: #ff4b04;
  436. color: #fff;
  437. padding: 20rpx;
  438. border-radius: 0 0 0 10rpx;
  439. box-sizing: border-box;
  440. .mark-item {
  441. text-align: center;
  442. }
  443. }
  444. .good-item {
  445. font-size: 24rpx;
  446. color: #a39c85;
  447. line-height: 90rpx;
  448. margin-left: 40rpx;
  449. }
  450. }
  451. }
  452. // 商家信息
  453. .merchant-info {
  454. padding: 20rpx;
  455. background-color: #fff;
  456. .info-title {
  457. display: flex;
  458. justify-content: center;
  459. font-size: 36rpx;
  460. font-weight: bold;
  461. margin: 20rpx 0;
  462. .info-mark {
  463. font-size: 12px;
  464. font-weight: normal;
  465. color: #999;
  466. margin: 20rpx 0 20rpx 30rpx;
  467. }
  468. }
  469. .info-tag {
  470. width: 140rpx;
  471. padding: 10rpx;
  472. text-align: center;
  473. border: 1px solid #5992bb;
  474. color: #5992bb;
  475. margin-bottom: 10rpx;
  476. }
  477. .info-item {
  478. display: flex;
  479. justify-content: space-between;
  480. .info-text {
  481. font-size: 28rpx;
  482. line-height: 58rpx;
  483. color: #212020;
  484. margin-left: 20rpx;
  485. .distance {
  486. font-size: 26rpx;
  487. color: #555252;
  488. font-weight: normal;
  489. }
  490. }
  491. .info-icon {
  492. display: flex;
  493. align-items: center;
  494. }
  495. .info-map {
  496. padding: 10rpx;
  497. font-size: 28rpx;
  498. margin-top: 120rpx;
  499. }
  500. }
  501. }
  502. .evaluate-context {
  503. background-color: #fff;
  504. margin-bottom: 20rpx;
  505. .evaluate {
  506. padding: 20rpx;
  507. border-bottom: 1rpx solid #f4f4f4;
  508. }
  509. }
  510. .flex {
  511. display: flex;
  512. justify-content: space-between;
  513. align-items: center;
  514. }
  515. .text_title {
  516. font-size: 24rpx;
  517. color: #999;
  518. }
  519. .list {
  520. height: 220rpx;
  521. background-color: #fff;
  522. padding: 20rpx;
  523. margin-bottom: 20rpx;
  524. display: flex;
  525. .img {
  526. width: 140px;
  527. height: 100%;
  528. display: block;
  529. margin-right: 10rpx;
  530. border-radius: 10rpx;
  531. }
  532. .listDetail {
  533. width: calc(100% - 160rpx);
  534. }
  535. .item-text {
  536. display: flex;
  537. justify-content: space-between;
  538. align-items: center;
  539. font-weight: bold;
  540. margin: 10rpx 0 10rpx;
  541. color: #333;
  542. font-size: 36rpx;
  543. .item-text-left {}
  544. .item-text-right {
  545. .img {
  546. width: 50rpx;
  547. height: 50rpx;
  548. }
  549. }
  550. }
  551. .item-flex {
  552. display: flex;
  553. justify-content: space-between;
  554. align-items: center;
  555. font-size: 28rpx;
  556. margin: 0 20rpx 10rpx 0;
  557. color: #0d0d0d66;
  558. .star {
  559. display: flex;
  560. align-items: center;
  561. .line {
  562. margin: 0 12rpx;
  563. margin-top: 5rpx;
  564. font-size: 22rpx;
  565. }
  566. .points {
  567. color: #ff4b04;
  568. font-size: 22rpx;
  569. margin-top: 6rpx;
  570. margin-left: 10rpx;
  571. }
  572. }
  573. }
  574. .list-item {
  575. display: flex;
  576. justify-content: space-between;
  577. align-items: center;
  578. .list-price {
  579. .item-l {
  580. color: #e35240;
  581. font-weight: bold;
  582. font-size: 32rpx;
  583. span {
  584. font-size: 40rpx;
  585. }
  586. }
  587. .item-r {
  588. color: #a8a8a8;
  589. margin-top: 10rpx;
  590. span {
  591. text-decoration: line-through;
  592. }
  593. }
  594. }
  595. .btn-box {
  596. .btn {
  597. font-size: 26rpx;
  598. border-radius: 40rpx;
  599. border: 2rpx solid #ec5729;
  600. color: #ec5729;
  601. background-color: #fff;
  602. }
  603. }
  604. }
  605. }
  606. .draw-box {
  607. width: 560rpx;
  608. padding: 20rpx;
  609. .draw-title {
  610. font-size: 30rpx;
  611. font-weight: bold;
  612. color: #000;
  613. margin-bottom: 30rpx;
  614. }
  615. .draw-item {
  616. margin-bottom: 20rpx;
  617. .item-text {
  618. font-size: 28rpx;
  619. color: #303133;
  620. padding-left: 20rpx;
  621. margin-bottom: 8rpx;
  622. }
  623. .time-box {
  624. border-width: 0.5px !important;
  625. border-color: #dadbde !important;
  626. border-style: solid;
  627. padding: 12rpx 12rpx 18rpx 18rpx;
  628. border-radius: 8rpx;
  629. }
  630. }
  631. .draw-btn {
  632. width: 90%;
  633. background-color: #5992bb !important;
  634. color: #fff;
  635. font-size: 28rpx;
  636. border-radius: 20rpx;
  637. }
  638. }
  639. .time-text {
  640. color: #d4d6dc;
  641. }
  642. /* 分类 */
  643. .categoryList {
  644. background-color: #fff;
  645. }
  646. .bottom-box {
  647. width: 100%;
  648. position: fixed;
  649. bottom: 5%;
  650. }
  651. </style>