|
@@ -0,0 +1,459 @@
|
|
|
|
|
+<!--
|
|
|
|
|
+ 商城客服咨询页
|
|
|
|
|
+ 从首页轮播客服悬浮入口进入;展示客服微信二维码、在线咨询/电话客服、门店营业信息;
|
|
|
|
|
+ 「立即咨询」跳转 chatPage,「拨打电话」调起系统电话。
|
|
|
|
|
+-->
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="service-page">
|
|
|
|
|
+ <scroll-view scroll-y class="service-scroll">
|
|
|
|
|
+ <!-- 顶部:客服微信二维码 -->
|
|
|
|
|
+ <view class="top-card">
|
|
|
|
|
+ <view class="qrcode-wrap" v-if="info.serviceWx">
|
|
|
|
|
+ <image
|
|
|
|
|
+ class="qrcode-img"
|
|
|
|
|
+ :src="info.serviceWx"
|
|
|
|
|
+ mode="widthFix"
|
|
|
|
|
+ show-menu-by-longpress="true"
|
|
|
|
|
+ @click="previewQrcode"
|
|
|
|
|
+ />
|
|
|
|
|
+ <text class="qrcode-tip">长按图片识别二维码添加客服微信</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="qrcode-empty" v-else>
|
|
|
|
|
+ <text class="qrcode-empty-text">暂未设置客服微信二维码</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 在线咨询 / 电话客服双卡片 -->
|
|
|
|
|
+ <view class="action-cards">
|
|
|
|
|
+ <view class="action-card">
|
|
|
|
|
+ <view class="action-icon pink">
|
|
|
|
|
+ <zui-svg-icon icon="general-customerService" :width="28" :height="28" color="#FF4D6D" />
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="action-title">在线咨询</text>
|
|
|
|
|
+ <text class="action-desc">7×14小时在线</text>
|
|
|
|
|
+ <text class="action-desc">快速为您解答</text>
|
|
|
|
|
+ <view class="action-btn pink" @click="goChat">立即咨询</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="action-card">
|
|
|
|
|
+ <view class="action-icon green">
|
|
|
|
|
+ <zui-svg-icon icon="general-phone" :width="28" :height="28" color="#09C567" />
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="action-title">电话客服</text>
|
|
|
|
|
+ <text class="action-desc">一对一专人服务</text>
|
|
|
|
|
+ <text class="action-desc">为您贴心解答</text>
|
|
|
|
|
+ <view class="action-btn green" @click="phoneCall">拨打电话</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 营业时间 / 门店地址 -->
|
|
|
|
|
+ <view class="info-card">
|
|
|
|
|
+ <view class="info-row">
|
|
|
|
|
+ <view class="info-icon pink-bg">
|
|
|
|
|
+ <text class="info-icon-text">时</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="info-body">
|
|
|
|
|
+ <text class="info-label">营业时间</text>
|
|
|
|
|
+ <text class="info-value">{{ openTimeText }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="info-row address-row">
|
|
|
|
|
+ <view class="info-icon green-bg">
|
|
|
|
|
+ <text class="info-icon-text">地</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="info-body">
|
|
|
|
|
+ <text class="info-value address-text">{{ info.fullAddress || '暂无地址' }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="nav-btn" @click="goNav">导航到店</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <view class="slogan">用心服务 · 传递每一份心意</view>
|
|
|
|
|
+ <view class="bottom-space"></view>
|
|
|
|
|
+ </scroll-view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 底部固定操作栏 -->
|
|
|
|
|
+ <view class="bottom-bar">
|
|
|
|
|
+ <view class="bottom-btn outline" @click="phoneCall">
|
|
|
|
|
+ <zui-svg-icon icon="general-phone" :width="18" :height="18" color="#09C567" />
|
|
|
|
|
+ <text>拨打电话</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="bottom-btn solid" @click="goChat">
|
|
|
|
|
+ <zui-svg-icon icon="general-customerService" :width="18" :height="18" color="#fff" />
|
|
|
|
|
+ <text class="bottom-solid-text">立即咨询</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import { mapGetters } from 'vuex'
|
|
|
|
|
+import { getInfo } from '@/api/shop'
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: 'shopService',
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ info: {},
|
|
|
|
|
+ customId: 0,
|
|
|
|
|
+ loading: false
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ ...mapGetters({ loginInfo: 'getLoginInfo' }),
|
|
|
|
|
+ /** 店名:导航/聊天展示用,优先商家名,其次分店名 */
|
|
|
|
|
+ displayName() {
|
|
|
|
|
+ if (this.info.merchantName) return this.info.merchantName
|
|
|
|
|
+ if (this.info.shopName) return this.info.shopName
|
|
|
|
|
+ return '客服'
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 营业时间展示
|
|
|
|
|
+ * 起止时间都为空视为 24 小时营业;有值则拼成时段并附「全年无休」
|
|
|
|
|
+ */
|
|
|
|
|
+ openTimeText() {
|
|
|
|
|
+ const start = this.info.openStartTime || ''
|
|
|
|
|
+ const end = this.info.openEndTime || ''
|
|
|
|
|
+ if (!start && !end) {
|
|
|
|
|
+ return '24小时营业 (全年无休)'
|
|
|
|
|
+ }
|
|
|
|
|
+ return start + '–' + end + ' (全年无休)'
|
|
|
|
|
+ },
|
|
|
|
|
+ shopId() {
|
|
|
|
|
+ return this.info.id || this.info.shopId || uni.getStorageSync('account') || 0
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ /** 拉取门店信息与当前客户 customId,用于展示与进聊天 */
|
|
|
|
|
+ init() {
|
|
|
|
|
+ const hdId = Number((this.option && this.option.hdId) || uni.getStorageSync('hdId') || 0)
|
|
|
|
|
+ const account = (this.option && this.option.account) || uni.getStorageSync('account') || ''
|
|
|
|
|
+ if (account) {
|
|
|
|
|
+ uni.setStorageSync('account', account)
|
|
|
|
|
+ }
|
|
|
|
|
+ const params = {}
|
|
|
|
|
+ if (hdId > 0) {
|
|
|
|
|
+ params.hdId = hdId
|
|
|
|
|
+ }
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ getInfo(params)
|
|
|
|
|
+ .then((res) => {
|
|
|
|
|
+ if (!res || res.code !== 1 || !res.data) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (res.data.info) {
|
|
|
|
|
+ this.info = res.data.info
|
|
|
|
|
+ uni.setStorageSync('currentShop', res.data.info)
|
|
|
|
|
+ }
|
|
|
|
|
+ if (res.data.custom && res.data.custom.id) {
|
|
|
|
|
+ this.customId = Number(res.data.custom.id)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .finally(() => {
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 预览客服微信二维码大图 */
|
|
|
|
|
+ previewQrcode() {
|
|
|
|
|
+ if (!this.info.serviceWx) return
|
|
|
|
|
+ uni.previewImage({
|
|
|
|
|
+ urls: [this.info.serviceWx],
|
|
|
|
|
+ current: this.info.serviceWx
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 拨打客服电话
|
|
|
|
|
+ * 优先使用 xhShopExt.serviceMobile;未配置时提示
|
|
|
|
|
+ */
|
|
|
|
|
+ phoneCall() {
|
|
|
|
|
+ const phone = (this.info.serviceMobile || '').trim()
|
|
|
|
|
+ if (!phone) {
|
|
|
|
|
+ this.$msg('暂未设置客服电话')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ uni.makePhoneCall({
|
|
|
|
|
+ phoneNumber: phone
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 打开门店导航
|
|
|
|
|
+ * 使用门店 lat/long;无坐标时提示
|
|
|
|
|
+ */
|
|
|
|
|
+ goNav() {
|
|
|
|
|
+ const lat = parseFloat(this.info.lat)
|
|
|
|
|
+ const lng = parseFloat(this.info.long)
|
|
|
|
|
+ if (!lat || !lng) {
|
|
|
|
|
+ this.$msg('暂无门店坐标')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ uni.openLocation({
|
|
|
|
|
+ latitude: lat,
|
|
|
|
|
+ longitude: lng,
|
|
|
|
|
+ name: this.displayName,
|
|
|
|
|
+ address: this.info.fullAddress || ''
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 跳转在线咨询聊天页
|
|
|
|
|
+ * 通过 eventChannel 传递 chatPage 所需参数(与商品详情 goChat 保持一致,不含商品信息)
|
|
|
|
|
+ */
|
|
|
|
|
+ goChat() {
|
|
|
|
|
+ if (isNaN(parseInt(this.loginInfo && this.loginInfo.id))) {
|
|
|
|
|
+ this.$msg('登录用户数据异常,请稍后再试')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNaN(parseInt(this.customId)) || Number(this.customId) <= 0) {
|
|
|
|
|
+ this.$msg('客户数据异常,请稍后再试')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNaN(parseInt(this.shopId)) || Number(this.shopId) <= 0) {
|
|
|
|
|
+ this.$msg('门店数据异常,请稍后再试')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ userId: this.loginInfo.id,
|
|
|
|
|
+ customId: this.customId,
|
|
|
|
|
+ shopId: this.shopId,
|
|
|
|
|
+ name: this.loginInfo.name,
|
|
|
|
|
+ avatar: this.loginInfo.avatar,
|
|
|
|
|
+ chatPerson: this.displayName
|
|
|
|
|
+ }
|
|
|
|
|
+ uni.navigateTo({
|
|
|
|
|
+ url: '/pages/chat/chatPage',
|
|
|
|
|
+ success: function (res) {
|
|
|
|
|
+ res.eventChannel.emit('acceptDataFromOpenerPage', params)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.service-page {
|
|
|
|
|
+ min-height: 100vh;
|
|
|
|
|
+ background: #f7f7f7;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+}
|
|
|
|
|
+.service-scroll {
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+}
|
|
|
|
|
+.top-card {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ padding: 40upx 40upx 40upx;
|
|
|
|
|
+ margin-bottom: 20upx;
|
|
|
|
|
+}
|
|
|
|
|
+.qrcode-wrap {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+/* 宽度铺满卡片内边距区域,height 随图片比例自适应,避免固定正方形裁切 */
|
|
|
|
|
+.qrcode-img {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ background: #fafafa;
|
|
|
|
|
+}
|
|
|
|
|
+.qrcode-tip {
|
|
|
|
|
+ margin-top: 24upx;
|
|
|
|
|
+ font-size: 28upx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #e64545;
|
|
|
|
|
+}
|
|
|
|
|
+.qrcode-empty {
|
|
|
|
|
+ height: 280upx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+.qrcode-empty-text {
|
|
|
|
|
+ font-size: 26upx;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+}
|
|
|
|
|
+.action-cards {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ padding: 0 20upx;
|
|
|
|
|
+ margin-bottom: 20upx;
|
|
|
|
|
+}
|
|
|
|
|
+.action-card {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 20upx;
|
|
|
|
|
+ padding: 30upx 20upx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-right: 16upx;
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ margin-right: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.action-icon {
|
|
|
|
|
+ width: 88upx;
|
|
|
|
|
+ height: 88upx;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ margin-bottom: 16upx;
|
|
|
|
|
+ &.pink {
|
|
|
|
|
+ background: #ffe8ee;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.green {
|
|
|
|
|
+ background: #e8f8ef;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.phone-icon {
|
|
|
|
|
+ font-size: 40upx;
|
|
|
|
|
+ color: #09c567;
|
|
|
|
|
+}
|
|
|
|
|
+.action-title {
|
|
|
|
|
+ font-size: 30upx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ margin-bottom: 10upx;
|
|
|
|
|
+}
|
|
|
|
|
+.action-desc {
|
|
|
|
|
+ font-size: 22upx;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ line-height: 1.5;
|
|
|
|
|
+}
|
|
|
|
|
+.action-btn {
|
|
|
|
|
+ margin-top: 20upx;
|
|
|
|
|
+ min-width: 180upx;
|
|
|
|
|
+ height: 56upx;
|
|
|
|
|
+ line-height: 54upx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ border-radius: 28upx;
|
|
|
|
|
+ font-size: 26upx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ &.pink {
|
|
|
|
|
+ color: #ff4d6d;
|
|
|
|
|
+ border: 2upx solid #ff4d6d;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.green {
|
|
|
|
|
+ color: #09c567;
|
|
|
|
|
+ border: 2upx solid #09c567;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.info-card {
|
|
|
|
|
+ margin: 0 20upx 20upx;
|
|
|
|
|
+ background: #fff7f2;
|
|
|
|
|
+ border-radius: 20upx;
|
|
|
|
|
+ padding: 10upx 24upx;
|
|
|
|
|
+}
|
|
|
|
|
+.info-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 22upx 0;
|
|
|
|
|
+}
|
|
|
|
|
+.address-row {
|
|
|
|
|
+ border-top: 1upx solid rgba(0, 0, 0, 0.04);
|
|
|
|
|
+}
|
|
|
|
|
+.info-icon {
|
|
|
|
|
+ width: 48upx;
|
|
|
|
|
+ height: 48upx;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ margin-right: 16upx;
|
|
|
|
|
+ &.pink-bg {
|
|
|
|
|
+ background: #ff4d6d;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.green-bg {
|
|
|
|
|
+ background: #09c567;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.info-icon-text {
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 22upx;
|
|
|
|
|
+}
|
|
|
|
|
+.addr-icon {
|
|
|
|
|
+ font-size: 26upx;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+.info-body {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+.info-label {
|
|
|
|
|
+ font-size: 26upx;
|
|
|
|
|
+ color: #333;
|
|
|
|
|
+ margin-right: 12upx;
|
|
|
|
|
+}
|
|
|
|
|
+.info-value {
|
|
|
|
|
+ font-size: 26upx;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+}
|
|
|
|
|
+.address-text {
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+}
|
|
|
|
|
+.nav-btn {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ margin-left: 16upx;
|
|
|
|
|
+ padding: 0 18upx;
|
|
|
|
|
+ height: 48upx;
|
|
|
|
|
+ line-height: 48upx;
|
|
|
|
|
+ border-radius: 24upx;
|
|
|
|
|
+ background: #09c567;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 22upx;
|
|
|
|
|
+}
|
|
|
|
|
+.slogan {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ font-size: 24upx;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+ padding: 20upx 0 40upx;
|
|
|
|
|
+}
|
|
|
|
|
+.bottom-space {
|
|
|
|
|
+ height: 160upx;
|
|
|
|
|
+ padding-bottom: env(safe-area-inset-bottom);
|
|
|
|
|
+}
|
|
|
|
|
+.bottom-bar {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ padding: 16upx 24upx calc(16upx + env(safe-area-inset-bottom));
|
|
|
|
|
+ box-shadow: 0 -4upx 20upx rgba(0, 0, 0, 0.06);
|
|
|
|
|
+ z-index: 20;
|
|
|
|
|
+}
|
|
|
|
|
+.bottom-btn {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 84upx;
|
|
|
|
|
+ border-radius: 42upx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 30upx;
|
|
|
|
|
+ margin-right: 20upx;
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ margin-right: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.outline {
|
|
|
|
|
+ color: #09c567;
|
|
|
|
|
+ border: 2upx solid #09c567;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ &.solid {
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ background: #09c567;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+.bottom-phone {
|
|
|
|
|
+ font-size: 32upx;
|
|
|
|
|
+ color: #09c567;
|
|
|
|
|
+ margin-right: 10upx;
|
|
|
|
|
+}
|
|
|
|
|
+.bottom-solid-text {
|
|
|
|
|
+ margin-left: 10upx;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|