activityDetail.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. <template>
  2. <view :style="vuex_skin">
  3. <!-- #ifdef MP-WEIXIN -->
  4. <u-navbar :custom-back="customBack" :is-back="true" title="作品详情"></u-navbar>
  5. <!-- #endif -->
  6. <view class="" v-show="!loading">
  7. <video v-if="activity.activeType == 'VIDEO_TEXT'" class="works-video" @error="videoError"
  8. :poster="activity.imgUrl" :src="activity.videoUrl"></video>
  9. <image v-else class="works-video" @click="$util.preview(activity.imgUrl)" :src="activity.imgUrl" mode="">
  10. </image>
  11. <view style="padding: 20rpx 30rpx 50rpx 30rpx;background: white;">
  12. <view class="title" style="border-bottom: 1rpx solid #EEEEEE ;">
  13. <span class="bg-base work-no"> {{activity.productNo}}号</span>
  14. <span class="work-title">{{activity.title}}</span>
  15. <view class="work-info-box" style="display: flex;">
  16. <view class="center">
  17. <text class="cuIcon-hotfill text-base" style="font-size: 36rpx;"></text>
  18. </view>
  19. <view class="vote-count">{{activity.voteCount}}</view>
  20. <view class="center" style="justify-content: flex-start;">
  21. <view class="cu-tag round sm bg-tag" style="font-size: 22rpx;" >
  22. <text>排行榜第{{activity.rank}}名</text>
  23. </view>
  24. </view>
  25. <!-- <view class="work-rank" style="background-color: rgba(102, 73, 239,.2);">排行榜第{{activity.rank}}名</view> -->
  26. </view>
  27. </view>
  28. <view style="font-size: 24rpx;color: #888888;padding: 30rpx 10rpx 20rpx 10rpx;">
  29. <u-parse :html="content"></u-parse>
  30. </view>
  31. </view>
  32. <view @click="showShare" class="bg-white padding-30 margin-top-30 flex">
  33. <view class="center margin-left-20">
  34. <view class="bg-base cu-btn round cuIcon" style="width: 70rpx;height: 70rpx;">
  35. <text class="cuIcon-forwardfill"></text>
  36. </view>
  37. <!-- <image style="width: 84rpx;height: 84rpx;" src="../../static/icon/ic_zhuanfa.png"></image> -->
  38. </view>
  39. <view class="basis-lg flex flex-direction" style="margin-left: 30rpx;">
  40. <view style="font-size: 28rpx;color: #353535;">为TA拉票</view>
  41. <view style="font-size: 22rpx;color: #AEACAF;padding-top: 10rpx;">
  42. <!-- <text>成功邀请一位好友投票,获得{{vuex_active_setting.voteAndHeatRate}}热力值</text> -->
  43. <text>转发邀请好友为该作品助力</text>
  44. </view>
  45. </view>
  46. <view class="flex justify-center align-center"
  47. style="color: #666666;flex-basis: 20%;font-size: 26rpx;font-family: PingFang-SC-Medium;">去邀请 >
  48. </view>
  49. </view>
  50. <view class="footer-bar" style="z-index: 1;">
  51. <u-button @click="goVote" shape="circle" :custom-style="btnText=='给ta投票'?customStyle:disabledStyle">
  52. {{btnText}}
  53. </u-button>
  54. </view>
  55. </view>
  56. <login ref="login" @signIn="signIn" @phoneSuccess="showVote"></login>
  57. <toast ref="toast"></toast>
  58. <!-- #ifdef MP-WEIXIN -->
  59. <loading ref="loading" type="3" theme="2" />
  60. <!-- #endif -->
  61. <vote-popup ref="votePopup" @toVote="toVote"></vote-popup>
  62. <!-- 海报 -->
  63. <poster v-if="$isNotEmpty(posetrParams.activeId)" ref="poster" :avatar="posetrParams.avatar"
  64. :activeId="posetrParams.activeId" :title="posetrParams.title" :subTitle="posetrParams.subTitle"></poster>
  65. <share-popup ref="sharePopup" @confirm="shareConfirm"></share-popup>
  66. <timeline-popup ref="timelinePopup"></timeline-popup>
  67. <sms-alert ref="smsAlert" @exchange="cmccVote"></sms-alert>
  68. <vote-success ref="voteSuccess" @support="showShare"></vote-success>
  69. <home-btn></home-btn>
  70. </view>
  71. </template>
  72. <script>
  73. import voteSuccess from "@/components/alert/voteSuccess.vue"
  74. import sharePopup from "@/components/alert/sharePopup.vue"
  75. import timelinePopup from "@/components/alert/timelinePopup.vue"
  76. import votePopup from '@/components/alert/votePopup.vue'
  77. import poster from "@/components/poster/poster.vue"
  78. import smsAlert from "@/components/alert/smsAlert.vue"
  79. export default {
  80. components: {
  81. voteSuccess,
  82. smsAlert,
  83. sharePopup,
  84. timelinePopup,
  85. votePopup,
  86. poster,
  87. },
  88. async onLoad(props) {
  89. this.customStyle.background = this.vuex_theme.bgColor
  90. // #ifdef MP-WEIXIN
  91. uni.showShareMenu({
  92. menus: ['shareAppMessage', 'shareTimeline']
  93. })
  94. // #endif
  95. this.isCustomBack = props.isCustomBack || true
  96. this.showLoading()
  97. //作品id
  98. this.id = props.id;
  99. //获取详情
  100. await this.fetchData()
  101. //处理授权结果
  102. this.handelAuthResult(props)
  103. // #ifdef MP-WEIXIN
  104. //处理创建订单结果
  105. this.handelOrderResult(props)
  106. // #endif
  107. // #ifdef H5
  108. this.h5CreateOrder()
  109. // #endif
  110. //处理海报参数
  111. this.handelShareParams()
  112. //隐藏loading
  113. setTimeout(() => {
  114. this.hideLoading()
  115. }, 20)
  116. },
  117. computed: {
  118. content() {
  119. return decodeURIComponent(this.activity.content)
  120. },
  121. btnText: {
  122. get() {
  123. let now = new Date().getTime()
  124. let startTime = this.$dateTime.getTime(this.activity.activeStartTime)
  125. let endTime = this.$dateTime.getTime(this.activity.activeEndTime)
  126. if (now < startTime) {
  127. return "活动未开始"
  128. }
  129. if (now > endTime) {
  130. return "活动已结束"
  131. }
  132. return "给ta投票"
  133. }
  134. }
  135. },
  136. data() {
  137. return {
  138. count: 0,
  139. //是否自定义返回,防止授权时返回到webview页面
  140. isCustomBack: true,
  141. defaultAvatar: 'https://vote.guosen-fumao.cn/obsfile/446d9e043f3748e4a47ea4d0de81b140-3b748fea4150c469b8eb66f98cd29e2.png',
  142. loading: false,
  143. //作品id
  144. id: '',
  145. //订单结果
  146. orderResult: {},
  147. //授权结果
  148. authResult: {},
  149. //分享
  150. qrCodeImg: '',
  151. //选中的道具
  152. selectGoods: {},
  153. mpShare: {},
  154. posetrParams: {
  155. avatar: '',
  156. title: '我是普法帮帮代言人',
  157. subTitle: '邀请您为888号作品投票!',
  158. activeId: ''
  159. },
  160. activity: {},
  161. customStyle: {
  162. color: 'white',
  163. background: "#E72226",
  164. fontSize: '32rpx',
  165. width: '500rpx',
  166. margin: '25rpx auto'
  167. },
  168. disabledStyle: {
  169. background: "#f1f1f1",
  170. fontSize: '32rpx',
  171. width: '500rpx',
  172. margin: '25rpx auto'
  173. },
  174. }
  175. },
  176. onShareAppMessage(res) {
  177. return {
  178. title: this.mpShare.title,
  179. path: this.mpShare.path,
  180. imageUrl: this.mpShare.imageUrl
  181. }
  182. },
  183. onShareTimeline(res) {
  184. return {
  185. title: this.mpShare.title,
  186. path: this.mpShare.path,
  187. imageUrl: this.mpShare.imageUrl
  188. }
  189. },
  190. methods: {
  191. goVote() {
  192. if (this.btnText == '给ta投票') {
  193. this.login()
  194. return
  195. }
  196. this.$refs.toast.error(this.btnText)
  197. },
  198. showLoading() {
  199. // #ifdef MP-WEIXIN
  200. this.$refs.loading.showLoading()
  201. // #endif
  202. // #ifndef MP-WEIXIN
  203. this.$dialog.showLoading()
  204. // #endif
  205. },
  206. videoError(e) {
  207. console.log(e, "error");
  208. },
  209. hideLoading() {
  210. // #ifdef MP-WEIXIN
  211. this.$refs.loading.hide()
  212. // #endif
  213. // #ifndef MP-WEIXIN
  214. uni.hideLoading()
  215. // #endif
  216. this.loading = false
  217. },
  218. async fetchData() {
  219. this.activity = (await this.$api.activity.getWorksDetail(this.id)).data.data
  220. },
  221. async handelShareParams() {
  222. let title = await this.getPosetrParamsTitle()
  223. this.posetrParams = {
  224. avatar: this.defaultAvatar,
  225. title: title,
  226. subTitle: '邀请您为' + this.activity.productNo + '号作品投票!',
  227. activeId: this.activity.activeId
  228. }
  229. let userId = this.vuex_userId || '000000' //游客
  230. let sharePath = '/pages/activity/activityDetail?id=' + this.activity.id + '&userId=' + userId
  231. let encodePath = encodeURIComponent(sharePath)
  232. this.mpShare = {
  233. title: title + ',' + this.posetrParams.subTitle,
  234. path: '/pages/index/home?path=' + encodePath,
  235. imageUrl: this.activity.imgUrl
  236. }
  237. // #ifdef H5
  238. let shareParam = {
  239. imgUrl: this.activity.imgUrl,
  240. desc: this.posetrParams.subTitle,
  241. title: title,
  242. link: window.location.href
  243. }
  244. this.$shareConfig.H5Share(shareParam)
  245. // #endif
  246. },
  247. async getPosetrParamsTitle() {
  248. let title = "我是普法帮帮代言人"
  249. if (this.$isEmpty(this.vuex_phone)) {
  250. return title
  251. }
  252. let params = {
  253. activeId: this.activity.activeId,
  254. phone: this.vuex_phone
  255. }
  256. let res = await this.$api.activity.getPromoteNum(params)
  257. if (this.$isNotEmpty(res.data) && this.$isNotEmpty(res.data.data.index)) {
  258. let index = res.data.data.index
  259. title = `我是第${index}位大赛代言人!`
  260. }
  261. return title
  262. },
  263. handelAuthResult(options) {
  264. if (options.authResult == undefined) {
  265. return
  266. }
  267. this.authResult = JSON.parse(options.authResult)
  268. if (this.authResult.resultCode == '0000') {
  269. //授权成功,直接弹出礼物框
  270. this.hideLoading()
  271. this.showVote()
  272. return
  273. }
  274. // #ifdef MP-WEIXIN
  275. if (this.authResult.resultCode == '9999') {
  276. //授权失败
  277. this.$refs.toast.error(this.authResult.message)
  278. return
  279. }
  280. // #endif
  281. },
  282. handelOrderResult(options) {
  283. if (options.orderPass && this.$cache.get('orderResult')) {
  284. this.orderResult = this.$cache.get('orderResult')
  285. this.createOrder()
  286. }
  287. },
  288. async showVote() {
  289. this.$refs.votePopup.showVote(this.vuex_phone, this.id, this.activity.activeId);
  290. },
  291. init() {
  292. if (this.vuex_phone) {
  293. this.showVote()
  294. }
  295. },
  296. //去投票
  297. toVote(item) {
  298. if (this.$cache.get('orderResult')) {
  299. this.orderResult = this.$cache.get('orderResult')
  300. this.orderResult.goodsId = item.id
  301. this.$cache.put('orderResult', this.orderResult, 1 * 60 * 60)
  302. }
  303. this.selectGoods = item
  304. if (item.point == 0) {
  305. //免费投票
  306. this.freeVote()
  307. return
  308. }
  309. this.$refs.votePopup.hideVote()
  310. //移动积分投票,创建订单
  311. if (this.$cache.get('orderResult')) {
  312. this.createOrder()
  313. return
  314. }
  315. // #ifdef MP-WEIXIN
  316. let params = {
  317. url: 'https://vote.guosen-fumao.cn/order.html',
  318. goodsId: this.selectGoods.id
  319. }
  320. this.$jump('/pages/webview/createOrder' + this.$u.queryParams(params))
  321. // #endif
  322. },
  323. //移动积分创建订单
  324. async createOrder() {
  325. if (this.$isEmpty(this.orderResult.fingerprint) ||
  326. this.$isEmpty(this.orderResult.sessionId) ||
  327. this.$isEmpty(this.orderResult.goodsId)) {
  328. this.$refs.toast.error('创建订单失败')
  329. return
  330. }
  331. let params = {
  332. fingerprint: this.orderResult.fingerprint,
  333. helpGoodsId: this.orderResult.goodsId,
  334. sessionId: this.orderResult.sessionId,
  335. num: 1,
  336. phone: this.vuex_phone,
  337. userId: this.vuex_userId
  338. }
  339. let res = await this.$api.order.create(params)
  340. if (res.data.success) {
  341. console.log("orderResult", this.orderResult);
  342. this.orderResult.outOrderId = res.data.data
  343. this.orderResult.mobile = this.vuex_phone
  344. this.$refs.smsAlert.showSmsAndSend(this.orderResult)
  345. } else {
  346. this.$refs.toast.error(res.data.msg)
  347. }
  348. },
  349. async cmccVote(item) {
  350. this.$refs.smsAlert.hideSms()
  351. let params = {
  352. ...item,
  353. machinetype: 'phone',
  354. productId: this.id,
  355. helpGoodsId: this.orderResult.goodsId,
  356. userId: this.vuex_userId,
  357. num: 1,
  358. }
  359. let res = await this.$api.order.exchange(params)
  360. if (res.data.success) {
  361. this.voteSuccess()
  362. this.$refs.smsAlert.hideSms()
  363. } else {
  364. this.$refs.toast.error(res.data.msg)
  365. }
  366. },
  367. voteSuccess() {
  368. try {
  369. let avatar = this.$cache.get('userInfo').avatar || this.defaultAvatar
  370. let activeVote = this.selectGoods.activeVote
  371. this.$refs.voteSuccess.showSuccess(avatar, activeVote)
  372. } catch (e) {
  373. this.$refs.toast.info('助力成功')
  374. }
  375. },
  376. async freeVote() {
  377. let params = {
  378. helpGoodsId: this.selectGoods.id,
  379. userId: this.vuex_userId,
  380. num: 1,
  381. productId: this.activity.id,
  382. }
  383. let res = await this.$api.order.exchange(params)
  384. if (res.data.success) {
  385. this.$refs.votePopup.hideVote()
  386. this.fetchData()
  387. let avatar = this.$cache.get('userInfo').avatar
  388. let voteCount = this.selectGoods.votePointRate
  389. let pointNum = this.vuex_active_setting.voteAndPointRate
  390. setTimeout(() => {
  391. this.voteSuccess()
  392. }, 200)
  393. } else {
  394. this.$refs.votePopup.hideVote()
  395. setTimeout(() => {
  396. this.$refs.toast.error(res.data.msg)
  397. }, 200)
  398. }
  399. },
  400. customBack() {
  401. if (this.isCustomBack == true) {
  402. uni.switchTab({
  403. url: '/pages/index/home'
  404. })
  405. } else {
  406. uni.navigateBack({
  407. delta: 1
  408. })
  409. }
  410. },
  411. //分享
  412. showPoster() {
  413. this.$refs.poster.showCanvas()
  414. },
  415. async shareConfirm(item) {
  416. if (item.name == '海报') {
  417. this.showPoster()
  418. return
  419. }
  420. if (item.name == '好友') {
  421. this.$refs.timelinePopup.PopupTyPe = 'friend';
  422. this.$refs.timelinePopup.show()
  423. return
  424. }
  425. if (item.name == '朋友圈') {
  426. this.$refs.timelinePopup.PopupTyPe = 'friendsCircle';
  427. this.$refs.timelinePopup.show()
  428. }
  429. },
  430. async showShare() {
  431. await this.handelShareParams()
  432. this.$refs.sharePopup.show()
  433. },
  434. // h5 创建订单 begin
  435. h5CreateOrder() {
  436. if (this.$cache.get('orderResult')) {
  437. this.orderResult = this.$cache.get('orderResult')
  438. return
  439. }
  440. //初始化js脚本
  441. this.initScript()
  442. //获取Fmopt
  443. this.fetchFmopt()
  444. //获取sessionId
  445. this.loadScriptFunc("", this.fetchSessionId())
  446. //打印数据
  447. this.cacheOrderData()
  448. },
  449. cacheOrderData() {
  450. let _this = this
  451. setTimeout(() => {
  452. _this.$nextTick(function() {
  453. try {
  454. _this.count++
  455. console.log("sessionId:" + window.sessionId);
  456. console.log("fingerprint:" + _fmOpt.getinfo());
  457. console.log("获取成功啦");
  458. _this.pushInCache(_fmOpt.getinfo(), window.sessionId)
  459. } catch (e) {
  460. console.log(_this.count);
  461. if (_this.count < 10) {
  462. _this.cacheOrderData()
  463. }
  464. }
  465. })
  466. }, 20)
  467. },
  468. pushInCache(fingerprint, sessionId) {
  469. this.orderResult = {
  470. fingerprint: encodeURIComponent(fingerprint),
  471. sessionId,
  472. goodsId: this.selectGoods.id
  473. }
  474. this.$cache.put('orderResult', this.orderResult)
  475. },
  476. initScript() {
  477. let monitorURL = "https://static.tongdun.net/monitor/monitor.js"
  478. this.loadScript(monitorURL)
  479. let tfdURL = "https://j.changyoyo.com/static/js/common/tfd.js"
  480. this.loadScript(tfdURL)
  481. let jqueryURL = "https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"
  482. this.loadScript(jqueryURL)
  483. },
  484. fetchFmopt() {
  485. window._fmOpt = {
  486. partner: 'changyou',
  487. appName: 'changyou_web',
  488. token: 'changyou' + "-" + new Date().getTime() + "-" +
  489. Math.random().toString(16).substr(2),
  490. fmb: true,
  491. success: function(data) {
  492. console.log('blackbox: ', data)
  493. },
  494. fpHost: "https://fp.tongdun.net"
  495. };
  496. var cimg = new Image(1, 1);
  497. cimg.onload = function() {
  498. _fmOpt.imgLoaded = true;
  499. };
  500. cimg.src =
  501. "https://fp.tongdun.net/fp/clear.png?partnerCode=changyou&appName=changyou_web&tokenId=" +
  502. _fmOpt.token;
  503. var fm = document.createElement('script');
  504. fm.type = 'text/javascript';
  505. fm.async = true;
  506. fm.src = ('https:' == document.location.protocol ? 'https://' : 'http://') +
  507. 'static.tongdun.net/v3/fm.js?ver=0.1&t=' + (new Date().getTime() / 3600000).toFixed(0);
  508. var s = document.getElementsByTagName('script')[0];
  509. s.parentNode.insertBefore(fm,
  510. s);
  511. },
  512. loadScript(src) {
  513. var script = document.createElement('script');
  514. script.src = src;
  515. document.body.appendChild(script);
  516. },
  517. loadScriptFunc(url, callback) {
  518. callback = typeof callback === 'function' ? callback : function() {};
  519. var head = document.getElementsByTagName('head')[0];
  520. var script = document.createElement('script');
  521. script.type = 'text/javascript';
  522. script.src = url;
  523. script.onreadystatechange = function() {
  524. if (this.readyState == "loaded" || this.readyState == "complete") {
  525. callback();
  526. }
  527. }
  528. script.onload = callback;
  529. head.appendChild(script);
  530. },
  531. fetchSessionId() {
  532. var url, ts, sessionId, appId, appkey;
  533. url = "tfd.changyoyo.com";
  534. appId = "5308e20b";
  535. appkey = "3daf27ea2fe840ada6af8e1ec0d7b760";
  536. ts = new Date().getTime();
  537. sessionId = "changyo-pc-" + ts + "-" + Math.random().toString(16).substr(2);
  538. window.sessionId = sessionId;
  539. [document.getElementsByTagName('script')[0].parentNode.appendChild(document.createElement('script')).src =
  540. "http://" +
  541. url + "/did/js/dp.js?appId=" + appId + "&appkey=" + appkey + "&sessionId=" + sessionId +
  542. "&ts=" +
  543. ts
  544. ][0];
  545. },
  546. //h5 创建订单end
  547. },
  548. }
  549. </script>
  550. <style lang="scss" scoped>
  551. .works-video {
  552. width: 100%;
  553. height: 422rpx;
  554. }
  555. .title {
  556. padding: 20rpx;
  557. .work-no {
  558. padding: 5rpx 10rpx 5rpx 10rpx;
  559. border-radius: 7rpx;
  560. }
  561. .work-title {
  562. padding: 0 0 0 20rpx;
  563. color: #353535;
  564. font-size: 32rpx;
  565. font-weight: 800;
  566. }
  567. }
  568. .work-info-box {
  569. padding: 30rpx 0 15rpx 10rpx;
  570. .remen-icon {
  571. width: 30rpx;
  572. height: 30rpx;
  573. }
  574. .vote-count {
  575. padding: 0 20rpx 0 10rpx;
  576. font-size: 40rpx;
  577. color: #353535;
  578. font-weight: 800;
  579. }
  580. .work-rank {
  581. margin-left: -10rpx;
  582. color: #353535;
  583. background: #FDEBEC;
  584. border-radius: 21px 21px 21px 21px;
  585. font-size: 22rpx;
  586. padding: 8rpx 15rpx 8rpx 15rpx;
  587. }
  588. }
  589. .footer-bar {
  590. position: absolute;
  591. bottom: 0;
  592. left: 0;
  593. width: 100%;
  594. height: 170rpx;
  595. background-color: white;
  596. }
  597. .canvas-hide {
  598. position: fixed;
  599. right: 100vw;
  600. bottom: 100vh;
  601. z-index: -9999;
  602. opacity: 0;
  603. }
  604. </style>