activityDetail.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. <template>
  2. <view class="act-deltail-main"
  3. :style="{paddingBottom: `${footerHeight}rpx`}">
  4. <network-error />
  5. <view class="over-view">
  6. <image class="detail-img"
  7. :src="detail.imgs"
  8. mode="aspectFill"></image>
  9. <view class="detail-over">
  10. <text class="detail-title u-line-2 u-font-40 line-56 u-tips-color bold">【{{detail.activity_type | activityTyepFilter}}】{{detail.title}}</text>
  11. <view class="u-flex u-col-bottom u-p-t-24 u-p-b-28 u-border-bottom">
  12. <text class="u-primary-color u-font-28 line-40">返利:</text>
  13. <block v-if="detail.activity_type === 1">
  14. <text class="u-flex-1 u-primary-color u-font-36 line-50 bold">实付全返</text>
  15. </block>
  16. <block v-if="detail.activity_type === 2">
  17. <view class="u-flex-1 u-primary-color bold">
  18. <text class="u-font-28 line-40">¥</text>
  19. <text class="u-font-36 line-50">{{(detail.rebate_amount / 100).toFixed(2)}}</text>
  20. </view>
  21. </block>
  22. <text class="u-primary-color u-font-24 line-34">{{detail.join_count - detail.join_number}}</text>
  23. <text class="u-content-color u-font-24 line-34">剩余名额</text>
  24. </view>
  25. <view class="u-flex u-row-between u-p-t-22 line-34">
  26. <text class="u-content-color">{{detail.join_number}}已参与</text>
  27. <button class="share-btn u-primary-color u-font-24 line-34"
  28. open-type="share">分享活动</button>
  29. </view>
  30. </view>
  31. </view>
  32. <view class="shop-info u-m-t-16">
  33. <view class="u-font-36 line-50 u-tips-color bold">店铺信息</view>
  34. <view class="u-flex">
  35. <view class="u-flex-1 u-p-r-32">
  36. <text class="shop-name u-font-28 u-tips-color line-40 u-line-1">【{{detail.plat_type | platFilter}}】{{detail.shop_name}}</text>
  37. <view class="u-flex"
  38. @click="openMap">
  39. <view class="icon-map-wh icon-map"></view>
  40. <view class="u-content-color u-m-l-8 u-m-r-16">{{(detail.distance / 1000).toFixed(1)}}km</view>
  41. <text class="shop-address u-flex-1 u-content-color u-line-1">{{detail.shop_address}}</text>
  42. </view>
  43. </view>
  44. <view class="divider-right"></view>
  45. <block v-if="detail.plat_type === 8">
  46. <view class="to-btn u-p-l-28"
  47. @click="openOtherApplte()">
  48. <view class="icon-mt-wh icon-elm"></view>
  49. <view class="u-m-t-2 u-font-22 u-content-color line-32">打开饿了么</view>
  50. </view>
  51. </block>
  52. <block v-if="detail.plat_type === 9">
  53. <view class="to-btn u-p-l-40"
  54. @click="openOtherApplte()">
  55. <view class="icon-mt-wh icon-mt"></view>
  56. <view class="u-m-t-2 u-font-22 u-content-color line-32">打开美团</view>
  57. </view>
  58. </block>
  59. </view>
  60. </view>
  61. <view class="act-able-time u-m-t-16">
  62. <view class="u-font-36 line-50 u-tips-color bold">活动可用时间</view>
  63. <view class="u-flex u-m-t-16">
  64. <text class="u-flex-1 u-content-color line-40 u-line-2 u-p-r-32">{{businessHours}}营业时间可用(当天参与报名,需当天提交资料才能有效返款)</text>
  65. <view class="divider-right"></view>
  66. <button class="to-btn contact-btn u-p-l-40"
  67. @click="copyWx">
  68. <view class="icon-phone-wh icon-phone"></view>
  69. <view class="u-m-t-2 u-font-22 u-content-color line-32">联系客服</view>
  70. </button>
  71. </view>
  72. </view>
  73. <view class="act-desc u-m-t-16">
  74. <view class="act-tabs u-border-bottom">
  75. <u-tabs :is-scroll="false"
  76. :list="[{name: '活动规则'}, {name: '评价要求'}]"
  77. :current="currentTab"
  78. height="104"
  79. font-size="30"
  80. active-color="#FF6632"
  81. inactive-color="#111111"
  82. :bar-style="{
  83. bottom: '-4rpx',
  84. marginLeft: '-40rpx',
  85. width: '120rpx',
  86. height: '6rpx',
  87. borderRadius: 0,
  88. backgroundColor: 'linear-gradient(270deg, #FFB76B 0%, #FE4028 100%)'
  89. }"
  90. @change="changeTab">
  91. </u-tabs>
  92. </view>
  93. <view class="u-m-b-18 u-p-t-32 u-p-b-32">
  94. <block v-if="currentTab === 0">
  95. <block v-for="(item, index) in detail.content"
  96. :key="index">
  97. <img-text :value="item.content"
  98. :type="item.contentType"></img-text>
  99. </block>
  100. </block>
  101. <block v-else>
  102. <img-text :value="detail.requirement"
  103. type="1"></img-text>
  104. </block>
  105. </view>
  106. </view>
  107. <block v-if="status">
  108. <fixed-bottom @get-height="getFooterHeight">
  109. <view class="bottom-footer u-flex">
  110. <block v-if="status * 1 === 1 || status * 1 === 2">
  111. <view class="u-flex-1">
  112. <view class="line-34 bold">距活动结束还有:</view>
  113. <view class="u-font-20 u-content-color line-28">{{remainingTime}}</view>
  114. </view>
  115. <block v-if="status * 1 === 1">
  116. <button class="sign-up-btn u-font-30 bold line-42"
  117. @click="join">我要报名</button>
  118. </block>
  119. <block v-if="status * 1 === 2">
  120. <view class="u-flex">
  121. <button class="canel-btn u-font-28 line-40"
  122. @click="cancelJoin">取消报名</button>
  123. <button class="submit-btn u-font-28 line-40 u-m-l-16"
  124. @click="toSubmiteOrder">提交结果</button>
  125. </view>
  126. </block>
  127. </block>
  128. <block v-if="status * 1 === 3 || status * 1 === 4">
  129. <block v-if="status * 1 === 3">
  130. <view class="u-flex-1">
  131. <view class="line-34 bold">等待审核:</view>
  132. <view class="u-font-20 u-content-color line-28">审核通过后将获得返利金额</view>
  133. </view>
  134. </block>
  135. <block v-if="status * 1 === 4">
  136. <view class="u-flex-1">
  137. <view class="line-34 bold">审核通过:</view>
  138. <view class="u-font-20 u-content-color line-28">返利金额将在第二日到账</view>
  139. </view>
  140. </block>
  141. <button class="sign-up-btn u-font-30 bold line-42"
  142. disabled>已提交</button>
  143. </block>
  144. <block v-if="status * 1 === 5">
  145. <view class="u-flex-1">
  146. <view class="line-34 bold">审核驳回:</view>
  147. <view class="u-font-20 u-content-color line-28">{{detail.reject_reason}}</view>
  148. </view>
  149. </block>
  150. <block v-if="status * 1 === 6">
  151. <button class="end-btn u-m-l-12"
  152. disabled>已结束</button>
  153. </block>
  154. <block v-if="status * 1 === 7">
  155. <button class="end-btn u-m-l-12"
  156. disabled>已抢光</button>
  157. </block>
  158. </view>
  159. </fixed-bottom>
  160. </block>
  161. </view>
  162. </template>
  163. <script>
  164. import fixedBottom from '@/components/fixedBottom'
  165. import imgText from '@/components/imgText'
  166. import { getActivityDetail } from '@/api/activityApi'
  167. import { editJoinActivity } from '@/api/userApi'
  168. export default {
  169. components: { fixedBottom, imgText },
  170. data () {
  171. return {
  172. showErr: false,
  173. errMsg: '',
  174. nowTime: '',
  175. timer: null,
  176. footerHeight: 0,
  177. currentTab: 0,
  178. activityId: '',
  179. recordId: '',
  180. detail: {
  181. imgs: '',
  182. activity_type: '',
  183. title: '',
  184. rebate_amount: '',
  185. join_count: 0,
  186. join_number: 0,
  187. plat_type: '',
  188. shop_name: '',
  189. distance: 0,
  190. shop_address: '',
  191. join_status: '',
  192. start_time: '',
  193. end_time: ''
  194. }
  195. }
  196. },
  197. computed: {
  198. userId () {
  199. return this.$store.state.userInfo.token
  200. },
  201. businessHours () {
  202. const date = this.$dayjs(`${this.detail.start_date}`).format('YYYY年MM月DD日')
  203. const start = this.$dayjs(`${this.detail.start_date} ${this.detail.start_time}`).format('HH:mm')
  204. const end = this.$dayjs(`${this.detail.end_date} ${this.detail.end_time}`).format('HH:mm')
  205. return `${date} ${start}-${end}`
  206. },
  207. status () {
  208. if (this.detail.join_status === 1) {
  209. return 2
  210. } else if (this.detail.join_status === 2) {
  211. return 3
  212. } else if (this.detail.join_status === 3) {
  213. return 4
  214. } else if (this.detail.join_status === 4) {
  215. return 5
  216. } else if (this.detail.join_status === 5) {
  217. return 1
  218. } else if (this.detail.join_status === 6) {
  219. return 6
  220. } else if (this.remainingTime === 0) {
  221. return 6
  222. } else if (this.detail.join_count === this.detail.join_number && this.detail.join_count) {
  223. return 7
  224. } else if (this.detail.join_status === 0) {
  225. return 1
  226. } else {
  227. return 0
  228. }
  229. },
  230. remainingTime () {
  231. if (!this.detail.end_time) { return }
  232. const endTime = this.$dayjs(`${this.$dayjs().format('YYYY-MM-DD')} ${this.detail.end_time}`)
  233. if (isNaN(endTime.diff(this.nowTime, 's'))) { return }
  234. if (!isNaN(endTime.diff(this.nowTime, 's')) && endTime.diff(this.nowTime, 's') === 0) {
  235. clearTimeout(this.timer)
  236. return 0
  237. }
  238. return this.$dayjs(endTime.diff(this.nowTime)).subtract(8, 'h').format('HH小时mm分ss秒')
  239. }
  240. },
  241. watch: {
  242. userId (e) {
  243. if (!e) {
  244. uni.navigateTo({
  245. url: '/pagesSub/other/login'
  246. })
  247. }
  248. }
  249. },
  250. onLoad (options) {
  251. this.activityId = options.id
  252. this.recordId = options.record_id
  253. },
  254. onShow () {
  255. if (!this.userId) {
  256. uni.navigateTo({
  257. url: '/pagesSub/other/login'
  258. })
  259. return
  260. }
  261. this.getDetailData()
  262. this.reNowTime()
  263. },
  264. onHide () {
  265. clearTimeout(this.timer)
  266. },
  267. onError () {
  268. clearTimeout(this.timer)
  269. },
  270. onPullDownRefresh () {
  271. clearTimeout(this.timer)
  272. this.getDetailData()
  273. this.reNowTime()
  274. },
  275. onPageNotFound () {
  276. clearTimeout(this.timer)
  277. },
  278. onShareAppMessage (res) {
  279. const title = `${this.detail.activity_type === 1 ? '【免费吃】' : '【返利餐】'}${this.detail.title}`
  280. return {
  281. title: title,
  282. path: `/pagesSub/activity/activityDetail?id=${this.detail.id}`,
  283. imageUrl: this.detail.imgs
  284. }
  285. },
  286. methods: {
  287. reNowTime () {
  288. clearTimeout(this.timer)
  289. this.timer = setTimeout(() => {
  290. this.nowTime = this.$dayjs()
  291. this.reNowTime()
  292. }, 1000)
  293. },
  294. // 获取用户经纬度
  295. getLocation () {
  296. return new Promise((resolve, reject) => {
  297. uni.getLocation({
  298. type: 'gcj02',
  299. success: (res) => {
  300. resolve(res)
  301. },
  302. fail: () => {
  303. resolve(false)
  304. }
  305. })
  306. })
  307. },
  308. // 获取活动详情
  309. async getDetailData () {
  310. const location = await this.getLocation()
  311. if (!location) { return }
  312. const params = {
  313. id: this.activityId,
  314. lng: location.longitude,
  315. lat: location.latitude
  316. }
  317. if (this.recordId) {
  318. params.record_id = this.recordId
  319. }
  320. const { code, data } = await getActivityDetail(params)
  321. if (code === 200) {
  322. this.detail = data
  323. }
  324. uni.stopPullDownRefresh()
  325. },
  326. // 报名活动/取消报名
  327. async joinActivity (type) {
  328. const params = {
  329. id: this.detail.id,
  330. type: type
  331. }
  332. const { code, msg } = await editJoinActivity(params)
  333. if (code === 200) {
  334. if (type === 1) {
  335. uni.navigateTo({
  336. url: `/pagesSub/activity/signUpOutcome?endTime=${this.detail.end_time}&platType=${this.detail.plat_type}`
  337. })
  338. } else {
  339. this.getDetailData()
  340. }
  341. } else {
  342. uni.showToast({
  343. title: msg,
  344. icon: 'none'
  345. })
  346. }
  347. },
  348. getFooterHeight (h) {
  349. this.footerHeight = h * 2
  350. },
  351. changeTab (index) {
  352. this.currentTab = index
  353. },
  354. openMap () {
  355. uni.openLocation({
  356. latitude: this.detail.shop_lat,
  357. longitude: this.detail.shop_lng
  358. })
  359. },
  360. // 我要报名
  361. join () {
  362. // uni.requestSubscribeMessage({
  363. // tmplIds: [''],
  364. // success: (res) => {
  365. // this.joinActivity(1)
  366. // }
  367. // })
  368. this.joinActivity(1)
  369. },
  370. // 取消报名
  371. cancelJoin () {
  372. uni.showModal({
  373. title: '提示',
  374. content: '确定取消报名',
  375. confirmColor: '#1677FF',
  376. cancelColor: '#1677FF',
  377. success: (res) => {
  378. if (res.confirm) {
  379. this.joinActivity(2)
  380. }
  381. }
  382. })
  383. },
  384. // 提交结果
  385. toSubmiteOrder () {
  386. uni.navigateTo({
  387. url: `/pagesSub/order/submitOrder?activityId=${this.detail.id}&userActivityId=${this.detail.user_activity_id}`
  388. })
  389. },
  390. openOtherApplte () {
  391. uni.navigateToMiniProgram({
  392. appId: this.detail.app_info.appid,
  393. path: this.detail.app_info.path
  394. })
  395. },
  396. copyWx () {
  397. uni.setClipboardData({
  398. data: this.detail.kf_wechat,
  399. success: () => {
  400. uni.showToast({
  401. icon: 'none',
  402. title: '已复制客服微信号,请添加客服反馈'
  403. })
  404. }
  405. })
  406. }
  407. },
  408. filters: {
  409. activityTyepFilter (e) {
  410. const typeList = {
  411. 1: '免费吃',
  412. 2: '返利餐'
  413. }
  414. return typeList[e] || ''
  415. },
  416. platFilter (e) {
  417. const platList = {
  418. 8: '饿了么',
  419. 9: '美团'
  420. }
  421. return platList[e] || ''
  422. }
  423. }
  424. }
  425. </script>
  426. <style lang="scss" scoped>
  427. .act-deltail-main {
  428. .over-view {
  429. .detail-img {
  430. width: 100%;
  431. height: 424px;
  432. font-size: 0;
  433. }
  434. .detail-over {
  435. padding: 24px 40px 28px;
  436. background-color: #fff;
  437. }
  438. .detail-title {
  439. max-width: 670px;
  440. }
  441. .share-btn {
  442. margin: 0;
  443. padding-right: 0;
  444. background-color: #fff;
  445. &::after {
  446. border-color: transparent;
  447. }
  448. }
  449. }
  450. .act-able-time,
  451. .shop-info {
  452. padding: 32px 40px 28px;
  453. background-color: #fff;
  454. .shop-name {
  455. display: inline-block;
  456. margin: 16px 0;
  457. max-width: 510px;
  458. }
  459. .shop-address {
  460. display: inline-block;
  461. max-width: 396px;
  462. }
  463. .to-btn {
  464. display: flex;
  465. flex-direction: column;
  466. align-items: center;
  467. }
  468. .contact-btn {
  469. padding-right: 0;
  470. background-color: #fff;
  471. &::after {
  472. border-color: transparent;
  473. }
  474. }
  475. .icon-map-wh {
  476. width: 20px;
  477. height: 24px;
  478. }
  479. .icon-phone-wh,
  480. .icon-elm-wh,
  481. .icon-mt-wh {
  482. width: 56px;
  483. height: 56px;
  484. }
  485. .divider-right {
  486. width: 2px;
  487. height: 54px;
  488. background-color: $u-border-color;
  489. }
  490. }
  491. .act-desc {
  492. padding: 0 40px;
  493. background-color: #fff;
  494. }
  495. .bottom-footer {
  496. padding: 16px 40px 16px 28px;
  497. width: 100%;
  498. background-color: #fff;
  499. .sign-up-btn {
  500. padding: 24px 128px;
  501. width: 374px;
  502. height: 88px;
  503. border-radius: 44px;
  504. color: #fff;
  505. background-color: $u-type-primary;
  506. white-space: nowrap;
  507. }
  508. .canel-btn,
  509. .submit-btn {
  510. padding: 16px 40px;
  511. width: 192px;
  512. height: 72px;
  513. border-radius: 36px;
  514. }
  515. .canel-btn {
  516. position: relative;
  517. color: $u-type-primary;
  518. background-color: #fff;
  519. &::after {
  520. content: '';
  521. display: flex;
  522. align-items: center;
  523. width: 200%;
  524. height: 200%;
  525. border: 2px solid $u-type-primary;
  526. border-radius: 72px;
  527. box-sizing: border-box;
  528. pointer-events: none;
  529. transform-origin: 0 0;
  530. }
  531. }
  532. .submit-btn {
  533. color: #fff;
  534. background-color: $u-type-primary;
  535. }
  536. .end-btn {
  537. width: 670px;
  538. height: 88px;
  539. border-radius: 44px;
  540. }
  541. }
  542. }
  543. button[disabled] {
  544. color: #fff !important;
  545. background-color: #d3d4d5 !important;
  546. }
  547. button[disabled]::after {
  548. border-color: transparent;
  549. }
  550. </style>
  551. <style >
  552. .act-tabs >>> .u-tab-item + .u-tab-item {
  553. margin-left: 42px;
  554. }
  555. </style>