_id.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. <template>
  2. <div :class="mobile ? 'mobileMain' : ''"
  3. :style="{marginTop: mainMarginTop}"
  4. style="margin-bottom: 30px !important;">
  5. <div class="consult-detail-wrapper" v-if="!mobile">
  6. <div class="userinfo-wrapper">
  7. <div class="avatar-content">
  8. <img :src="consultDetail.user.icon_url" class="avatar" alt="avatar">
  9. <div class="line-status">{{ consultDetail.user.lineStatus }}</div>
  10. </div>
  11. <div class="userinfo-content">
  12. <div class="nickname">{{ consultDetail.user.nickname }}</div>
  13. <div class="split-line"></div>
  14. <div class="company-content">
  15. <img src="@/assets/img/common/company-icon@2x.png" class="icon" alt="company icon">
  16. <div class="text company-text">{{ consultDetail.user.company }}</div>
  17. <img src="@/assets/img/common/title-icon@2x.png" class="icon" alt="title icon">
  18. <div class="text title-text">{{ consultDetail.user.title }}</div>
  19. </div>
  20. <div class="stats-content">
  21. <div v-if="consultDetail.user.zxRating" class="rating-text">响应率:<span>{{ consultDetail.user.zxRatingText }}</span></div>
  22. <div v-if="consultDetail.user.zx_total_num" class="num-text">约聊人数:<span>{{ consultDetail.user.zx_total_num }}人</span></div>
  23. </div>
  24. </div>
  25. </div>
  26. <div class="consult-list">
  27. <div
  28. class="consult-item"
  29. v-for="(item, index) in consultDetail.sale_list"
  30. :key="item.sale_id">
  31. <div class="consult-item-header">{{ item.title }}</div>
  32. <div class="consult-item-content">
  33. <!-- 展开时 -->
  34. <div class="content-info-expand" v-show="item.expand">
  35. <div style="width: 100%;">{{ item.content }}</div>
  36. <img v-if="item.img_array.length && item.img_array[0]" :src="item.img_array[0]" alt="">
  37. </div>
  38. <!-- 收起时 -->
  39. <div class="content-info" v-show="!item.expand">{{ item.content }}</div>
  40. </div>
  41. <div class="consult-item-pay">
  42. <div class="expand-wrapper" @click="handleClickExpand(index)">
  43. <span v-show="item.showExpand">{{ item.expand ? '收起' : '展开' }}</span>
  44. <img v-show="item.showExpand" class="expand-icon" :src="item.expand ? ExpandTopIcon : ExpandDownIcon" alt="expand">
  45. </div>
  46. <div class="price-wrapper">
  47. <div class="price-text">¥{{ item.price }}</div>
  48. <el-button
  49. :loading="item.loading"
  50. @click="handleClickPay(item.sale_id, index)"
  51. class="pay-btn">一键约聊</el-button>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. <div class="consult-detail-wrapper-mobile" v-else>
  58. </div>
  59. <!-- 约聊时间选择 modal -->
  60. <el-dialog
  61. :visible.sync="isShowSelectTimeDialog"
  62. width="670px"
  63. @close="handleSelectTimeDialogClose">
  64. <div class="time-dialog-title" slot="title">选择预约时间</div>
  65. <div class="time-dialog-content">
  66. <div class="date-wrapper">
  67. <div class="title">日期:</div>
  68. <div class="date-list-wrapper">
  69. <div
  70. class="date-item"
  71. :class="currentDateIndex === index ? 'active' : ''"
  72. v-for="(item, index) in orderTime"
  73. :key="index"
  74. @click="handleClickDialogDate(index)">
  75. {{ item.date }}
  76. </div>
  77. </div>
  78. </div>
  79. <div class="time-wrapper">
  80. <div class="title">时间:</div>
  81. <div class="time-list-wrapper">
  82. <div
  83. class="time-list-item"
  84. v-show="currentDateIndex === index"
  85. v-for="(item, index) in orderTime"
  86. :key="`time-${index}`">
  87. <!-- empty info -->
  88. <div class="time-empty" v-if="item.time.length === 1 && item.time[0].date === '00:00'">
  89. 当前日期无服务
  90. </div>
  91. <template v-else>
  92. <div
  93. class="time-item"
  94. :class="selectedOrderTime === timeItem.value ? 'active' : ''"
  95. v-for="timeItem in item.time"
  96. :key="timeItem.value"
  97. @click="handleClickDialogTime(timeItem.value)">
  98. {{ timeItem.date }}
  99. </div>
  100. </template>
  101. </div>
  102. </div>
  103. </div>
  104. <div class="action-wrapper">
  105. <el-button
  106. class="confirm-btn"
  107. @click="handleClickDialogConfirm">确认</el-button>
  108. <el-button
  109. class="cancel-btn"
  110. @click="handleClickDialogCancel">取消</el-button>
  111. </div>
  112. </div>
  113. </el-dialog>
  114. </div>
  115. </template>
  116. <script>
  117. import {mapState} from "vuex"
  118. import DealSeoDetail from "@/components/consult/dealSeoDetail"
  119. import qs from "qs"
  120. import ExpandTopIcon from "@/assets/img/common/expand-top-icon@2x.png"
  121. import ExpandDownIcon from "@/assets/img/common/expand-down-icon@2x.png"
  122. export default {
  123. // web - 咨询服务详情页
  124. name: 'SeoConsultUser',
  125. data () {
  126. return {
  127. ExpandTopIcon,
  128. ExpandDownIcon,
  129. baseUrl: '',
  130. isWeixinApp: true,
  131. // 是否展示约聊时间 dialog
  132. isShowSelectTimeDialog: false,
  133. // 正在约聊的 saleId
  134. actionSaleId: '',
  135. // 约聊可选时间
  136. orderTime: [],
  137. // 约聊选择的时间
  138. selectedOrderTime: '',
  139. // dialog 当前选中的日期索引
  140. currentDateIndex: 0
  141. }
  142. },
  143. head() {
  144. const {
  145. title = "",
  146. keyword = "",
  147. description = "",
  148. h1 = "",
  149. canonical = "",
  150. metaLocation
  151. } = this.head || {}
  152. let obj = {
  153. title: title,
  154. meta: [{
  155. name: "keywords",
  156. content: keyword
  157. }, {
  158. name: "description",
  159. content: description
  160. }, {
  161. name: "h1",
  162. content: h1
  163. }, {
  164. name: "viewport",
  165. content: "width=device-width, initial-scale=1.0, viewport-fit=cover"
  166. }],
  167. link: [{rel: "canonical", href: canonical}]
  168. }
  169. if (metaLocation) {
  170. obj.meta.push({name: "location", content: metaLocation})
  171. }
  172. return obj
  173. },
  174. computed: {
  175. ...mapState(["deviceType"]),
  176. showWxHeader () {
  177. return !this.deviceType.app && !this.isWeixinApp &&
  178. (this.deviceType.android || this.deviceType.ios)
  179. },
  180. mainMarginTop () {
  181. if (this.mobile && this.showWxHeader) {
  182. return '64px !important'
  183. } else if (this.mobile) {
  184. return '0px !important'
  185. } else {
  186. return '20px !important'
  187. }
  188. }
  189. },
  190. async asyncData ({...params}) {
  191. let dealDataObj = new DealSeoDetail(params)
  192. let ans = await dealDataObj.dealData()
  193. return {
  194. ...ans
  195. }
  196. },
  197. mounted () {
  198. const self = this
  199. this.baseUrl = this.$store.state.domainConfig.siteUrl
  200. this.isWeixinApp = navigator.userAgent.indexOf("miniProgram") > -1
  201. if (this.act === 'pay') {
  202. setTimeout(() => {
  203. self.$message.success('购买成功,请等待对方接单')
  204. }, 800)
  205. }
  206. },
  207. methods: {
  208. /**
  209. * 获取约聊可选时间
  210. * @param {Number} saleId - 服务 id
  211. * @param {Number} index - 咨询列表索引
  212. */
  213. _getConsultTime (saleId, index) {
  214. const self = this
  215. const data = {
  216. sale_id: saleId
  217. }
  218. this.$axios.$post('/api/sale/time', data).then(res => {
  219. if (Number(res.status) === 1) {
  220. // 可约聊时间
  221. let orderTime = res.data.list || []
  222. // 为约聊的时间增加下单所需 value
  223. orderTime.forEach((item) => {
  224. item.time.forEach(dateItem => {
  225. dateItem.value = `${item.ymd} ${dateItem.date}`
  226. })
  227. })
  228. let consultItem = self.consultDetail.sale_list[index]
  229. consultItem.orderTime = orderTime
  230. self.consultDetail.sale_list.splice(index, 1, consultItem)
  231. if (orderTime[0].time &&
  232. orderTime[0].time.length > 1 &&
  233. orderTime[0].time[0].date !== '00:00') {
  234. self.selectedOrderTime = orderTime[0].time[0].value
  235. }
  236. self.orderTime = orderTime
  237. self.actionSaleId = saleId
  238. self.isShowSelectTimeDialog = true
  239. }
  240. console.log(res)
  241. })
  242. },
  243. /**
  244. * 点击展开收起时
  245. * @param {Number} index - 咨询列表索引
  246. */
  247. handleClickExpand (index) {
  248. let consultItem = this.consultDetail.sale_list[index]
  249. consultItem.expand = !consultItem.expand
  250. this.consultDetail.sale_list.splice(index, 1, consultItem)
  251. },
  252. /**
  253. * 点击一键约聊时
  254. * @param {Number} saleId - 服务 id
  255. * @param {Number} index - 咨询列表索引
  256. */
  257. handleClickPay (saleId, index) {
  258. // this.$message.info(`一键约聊:${saleId}`)
  259. let consultItem = this.consultDetail.sale_list[index]
  260. if (consultItem.orderTime && consultItem.orderTime.length) {
  261. // 已获取过约聊时间数据,为 dialog 赋值即可
  262. this.orderTime = consultItem.orderTime
  263. this.actionSaleId = saleId
  264. if (consultItem.orderTime[0].time &&
  265. consultItem.orderTime[0].time.length > 1 &&
  266. consultItem.orderTime[0].time[0].date !== '00:00') {
  267. this.selectedOrderTime = consultItem.orderTime[0].time[0].value
  268. }
  269. this.isShowSelectTimeDialog = true
  270. } else {
  271. this._getConsultTime(saleId, index)
  272. }
  273. },
  274. /**
  275. * 点击约聊 modal 的日期
  276. * @param {Number} index - 日期索引
  277. */
  278. handleClickDialogDate (index) {
  279. if (this.currentDateIndex !== index) {
  280. this.currentDateIndex = index
  281. }
  282. },
  283. /**
  284. * 点击约聊 modal 的时间
  285. * @param {String} value - 选择的值
  286. */
  287. handleClickDialogTime (value) {
  288. this.selectedOrderTime = value
  289. },
  290. /**
  291. * 点击约聊 modal 的确定
  292. */
  293. handleClickDialogConfirm () {
  294. // this.$message.info('稍微校验数据,然后直接跳转支付')
  295. if (!this.selectedOrderTime) {
  296. this.$message.error('请选择预约时间')
  297. return
  298. }
  299. const query = {
  300. product_type: 503,
  301. product_id: this.actionSaleId,
  302. obj: this.selectedOrderTime,
  303. next: location.href + '?act=pay'
  304. }
  305. if (!this.userinfo || !this.userinfo.nickname) {
  306. location.href = this.baseUrl + "/?loginbox=show&next=" + encodeURIComponent(location.href)
  307. } else {
  308. location.href = `/pay?${qs.stringify(query)}`
  309. }
  310. this.isShowSelectTimeDialog = false
  311. },
  312. /**
  313. * 点击约聊 modal 的取消
  314. */
  315. handleClickDialogCancel () {
  316. this.isShowSelectTimeDialog = false
  317. },
  318. /**
  319. * 约聊时间选择 modal 关闭时
  320. */
  321. handleSelectTimeDialogClose () {
  322. this.selectedOrderTime = ''
  323. this.currentDateIndex = 0
  324. this.orderTime = []
  325. this.actionSaleId = ''
  326. }
  327. }
  328. }
  329. </script>
  330. <style lang="scss" scoped>
  331. @import "@/assets/css/consult/user/_id.scss";
  332. </style>