history-detail.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. <!-- 直播间 -->
  2. <template>
  3. <view class="detail live-detail">
  4. <div class="body">
  5. <detailHeader :roomInfo="roomInfo" v-if="roomInfo.title"></detailHeader>
  6. <div id="palyevent">palyevent</div>
  7. <div v-html="inputHtml"></div>
  8. <div style="height: 420rpx; width: 100%">
  9. <div class="prism-player" id="player-con">
  10. <lff-barrage
  11. ref="lffBarrage"
  12. :maxTop="240"
  13. type="leftToRight"
  14. ></lff-barrage>
  15. <lff-barrage ref="lffBarrage2"></lff-barrage>
  16. <detailDownload @cancel="downloadTimerFun" v-if="downloadShow"></detailDownload>
  17. <detailFollow v-if="toolbar && !isFullScreen" :matchDetail="matchDetail" :roomInfo="roomInfo" @success="getLiveDetail1" :userInfo="userInfo"></detailFollow>
  18. <div class="icon-box" v-if="toolbar">
  19. <u-icon name="rewind-left-fill" color="#fff" size="50" @click="setSeek(-10)"></u-icon>
  20. <u-icon :name="!isPlay ? 'play-right-fill' : 'pause'" @click="playToggle" color="#fff" size="100"></u-icon>
  21. <u-icon name="rewind-right-fill" color="#fff" size="50" @click="setSeek(10)"></u-icon>
  22. </div>
  23. </div>
  24. </div>
  25. <div class="adver-box">
  26. <img class="ad" v-if="roomInfo.adver_img_one" @click="adClick(roomInfo)" :src="roomInfo.adver_img_one" alt="">
  27. <img class="qr_img" v-if="roomInfo.qr_img" @click.stop="adClick1(roomInfo)" :src="roomInfo.qr_img" alt="">
  28. </div>
  29. <view class="tabs" v-if="liveType != 'game'">
  30. <u-tabs
  31. :list="tabList"
  32. lineHeight="3px"
  33. lineWidth="35px"
  34. lineColor="#DC3C23"
  35. :scrollable="true"
  36. :activeStyle="{
  37. color: '#DC3C23',
  38. fontSize: '15px',
  39. fontWeight: '700',
  40. }"
  41. :itemStyle="{height: '40px'}"
  42. :inactiveStyle="{ color: '#000', fontSize: '15px' }"
  43. :current="current"
  44. @change="change"
  45. >
  46. </u-tabs>
  47. </view>
  48. </div>
  49. <detailList v-if="current == 0" :liveList="liveList" :robotLength="robotLength"/>
  50. <detailChat :liveType="liveType" v-show="current == 1" :giftList="giftList" @addMesg="addMesg" ref="detail1" :roomInfo="roomInfo" :userInfo="userInfo"/>
  51. <!-- <detailAnimation v-if="current == 2" :livePath="matchDetail.live_url" /> -->
  52. <detailLive v-if="current == 2" :matchDetail="matchDetail" />
  53. <detailInfo v-if="current == 3" :matchDetail="matchDetail" />
  54. <detailScorecard v-if="current == 4" :list="competition_list" :matchDetail="matchDetail" />
  55. <detailSquad v-if="current == 5" :matchDetail="matchDetail" />
  56. </view>
  57. </template>
  58. <script>
  59. import detailInfo from './compontent/detail-info.vue'
  60. import detailChat from './compontent/detail-chat.vue'
  61. import detailAnimation from './compontent/detail-animation.vue'
  62. import detailList from './compontent/detail-list-h.vue'
  63. import detailLive from './compontent/detail-live.vue'
  64. import detailScorecard from './compontent/detail-scorecard.vue'
  65. import detailSquad from './compontent/detail-squad.vue'
  66. import bus from '@/utils/bus'
  67. import detailHeader from './compontent/detail-header.vue'
  68. import detailFollow from './compontent/detail-follow.vue'
  69. import detailDownload from './compontent/detail-download.vue'
  70. export default {
  71. components: {
  72. detailHeader,
  73. detailFollow,
  74. detailInfo,
  75. detailChat,
  76. detailList,
  77. detailLive,
  78. detailScorecard,
  79. detailSquad,
  80. detailAnimation,
  81. detailDownload
  82. },
  83. data() {
  84. return {
  85. nativeShare: null,
  86. videoMask: false,
  87. timer: null, //定时器
  88. i: 0, //计数
  89. show: false,
  90. quality: ["540", "720", "1080"],
  91. bg: {
  92. backgroundColor: "transparent",
  93. },
  94. tabList: [
  95. {
  96. name: this.$t("live.detailTab1"),
  97. },
  98. {
  99. name: this.$t("live.detailTab2"),
  100. },
  101. // {
  102. // name: this.$t('live.lab39'),
  103. // },
  104. {
  105. name: this.$t("live.detailTab3"),
  106. },
  107. {
  108. name: this.$t("live.detailTab4"),
  109. },
  110. {
  111. name: this.$t("live.detailTab5"),
  112. },
  113. {
  114. name: this.$t("live.detailTab6"),
  115. },
  116. ],
  117. groupID: "",
  118. id: '',
  119. roomInfo: {},
  120. matchDetail: {},
  121. competition_list: [],
  122. player: null,
  123. current: 1,
  124. userInfo: {},
  125. giftList: [],
  126. isPlay: true,
  127. toolbar: false,
  128. isFullScreen: false,
  129. toolbarTimer: null,
  130. videoPlay: false,
  131. isQuality: false,
  132. qualityIndex: 0,
  133. qualityArr: [], //画质数组
  134. quality: [], //画质
  135. fanItam: {},
  136. setType: 0,
  137. liveList: [],
  138. MediaUrl: '',
  139. liveType: '',
  140. danmu: true,
  141. time1: null,
  142. robotLength: 0,
  143. userClick: false,
  144. downloadShow: false,
  145. downloadTimer: null,
  146. inputHtml: '<input type="text" id="copy-input" style="opacity: 0;position: fixed;top: 0;z-index: -1;" readonly="readonly">'
  147. };
  148. },
  149. onLoad(option) {
  150. this.id = option.ID;
  151. this.liveType = option.type
  152. this.MediaUrl = option.MediaUrl;
  153. // 根据传递过来的参数判断是详情还是历史记录
  154. // let watchingOutSign = localStorage.getItem('watchingOutSign')
  155. // if (watchingOutSign && this.isLogin != 1) {
  156. // this.$r.loginBox();
  157. // this.$store.state.loginShowSign = true;
  158. // this.$store.state.loginShowCloseSign = false;
  159. // } else {
  160. this.getIsLogin();
  161. // }
  162. // this.getUserGiftList()
  163. if (this.liveType != 'game') {
  164. this.getList();
  165. }
  166. this.$store.state.timMessage = [];
  167. },
  168. onUnload() {
  169. bus.$off('chatLogin')
  170. this.time1 && clearInterval(this.time1);
  171. this.downloadTimer && clearTimeout(this.downloadTimer);
  172. window.removeEventListener('touchstart', this.owerPlay1)
  173. this.player && this.player.dispose();
  174. this.time1 = null;
  175. /* 退出群组 */
  176. uni.$TUIKit
  177. .quitGroup(this.groupID)
  178. .then((imResponse) => {})
  179. .catch((imError) => {
  180. console.warn("joinGroup error:", imError); // 申请加群失败的相关信息
  181. });
  182. },
  183. onShow() {
  184. },
  185. onHide() {
  186. },
  187. watch: {
  188. },
  189. mounted() {
  190. this.downloadTimerFun()
  191. this.getLiveDetail();
  192. window.addEventListener('touchstart', this.owerPlay1)
  193. document.getElementById('palyevent').addEventListener('click',this.owerPlay)
  194. },
  195. computed: {
  196. infos() {
  197. return this.$store.state.info;
  198. },
  199. isLogin() {
  200. return this.$store.state.isLogin;
  201. },
  202. system() {
  203. return this.$store.state.system;
  204. },
  205. },
  206. methods: {
  207. videoInit(data) {
  208. var $this = this
  209. this.player = new Aliplayer(
  210. {
  211. id: "player-con",
  212. source: this.MediaUrl,
  213. width: "100%",
  214. height: "100%",
  215. autoplay: true,
  216. isLive: false,
  217. rePlay: true,
  218. showBarTime: '3000',
  219. // cover: data.thumb,
  220. videoHeight: "100%",
  221. keyShortCuts: true,
  222. playsinline: true,
  223. "language": "en-us",
  224. preload: true,
  225. controlBarVisibility: "hover",
  226. videoWidth: "100%",
  227. useH5Prism: true,
  228. skinLayout: [
  229. // {
  230. // name: "bigPlayButton",
  231. // align: "blabs",
  232. // x: 30,
  233. // y: 80,
  234. // },
  235. {
  236. name: "H5Loading",
  237. align: "cc",
  238. },
  239. {
  240. name: "errorDisplay",
  241. align: "tlabs",
  242. x: 0,
  243. y: 0,
  244. },
  245. {
  246. name: "infoDisplay",
  247. },
  248. {
  249. name: "tooltip",
  250. align: "blabs",
  251. x: 0,
  252. y: 56,
  253. },
  254. {
  255. name: "thumbnail",
  256. },
  257. {
  258. name: "controlBar",
  259. align: "blabs",
  260. x: 0,
  261. y: 0,
  262. children: [
  263. {
  264. name: "progress",
  265. align: "blabs",
  266. x: 0,
  267. y: 44,
  268. },
  269. // {
  270. // name: "playButton",
  271. // align: "tl",
  272. // x: 15,
  273. // y: 12,
  274. // },
  275. {
  276. name: "timeDisplay",
  277. align: "tl",
  278. x: 10,
  279. y: 7,
  280. },
  281. {
  282. name: "fullScreenButton",
  283. align: "tr",
  284. x: 10,
  285. y: 12,
  286. },
  287. {
  288. name: "volume",
  289. align: "tr",
  290. x: 5,
  291. y: 10,
  292. },
  293. ],
  294. },
  295. ],
  296. },
  297. function (player) {
  298. setTimeout(() => {
  299. $this.clickPlay()
  300. }, 1000)
  301. }
  302. );
  303. this.player.on('hideBar', () => {
  304. this.toolbar = false
  305. })
  306. this.player.on('showBar', () => {
  307. this.isPlay = this.player.getStatus() == 'playing';
  308. this.toolbar = true;
  309. if (this.toolbarTimer) {
  310. clearTimeout(this.toolbarTimer)
  311. }
  312. this.toolbarTimer = setTimeout(() => {
  313. this.toolbar = false
  314. this.toolbarTimer = null
  315. }, 3000)
  316. })
  317. this.player.on('requestFullScreen', () => {
  318. this.isFullScreen = true
  319. })
  320. this.player.on('cancelFullScreen', () => {
  321. this.isFullScreen = false
  322. })
  323. },
  324. getLiveDetail1() {
  325. uni.$u.http.post("/api/Live_streaming/getRoomInfo", {
  326. id: this.id,
  327. }).then(res => {
  328. this.roomInfo = res.info || {};
  329. this.userInfo = res.userData;
  330. })
  331. },
  332. /* 获取详情 */
  333. cricket_match_detail() {
  334. let time = new Date();
  335. let timeZone = time.toLocaleTimeString('en-us',{timeZoneName:'short'}); //'1:12:38 PM GMT+8'
  336. let timeZoneId = Intl.DateTimeFormat().resolvedOptions().timeZone; //'Asia/Shanghai'
  337. uni.$u.http.post('/api/Cricket/cricket_match_detail',{
  338. match_id: this.roomInfo.match_id,
  339. timezone:timeZoneId
  340. }).then(res=>{
  341. this.matchDetail = res;
  342. this.competition_list = res.competition_list || []
  343. }).catch(res=>{})
  344. },
  345. /* 发布弹幕 */
  346. addMesg(e) {
  347. if (!this.$refs.lffBarrage) {
  348. return
  349. }
  350. this.$refs.lffBarrage.add({ item: e });
  351. this.$refs.lffBarrage2.add({ item: e });
  352. },
  353. /* 获取直播 */
  354. getList() {
  355. uni.$u.http.get('/api/LivePlayBack/list', {}).then(res => {
  356. if (res.list) {
  357. this.robotLength = res.list.length
  358. this.liveList = res.list.slice(0, 6)
  359. } else {
  360. this.liveList = []
  361. }
  362. })
  363. },
  364. getHistoryMsg(msg) {
  365. uni.$u.http.get("/api/LivePlayBack/getSimple", {
  366. params: {
  367. id: this.groupID
  368. }
  369. }).then((res) => {
  370. let RspMsgList = res.RspMsgList || [];
  371. let msgList = []
  372. RspMsgList.forEach(item => {
  373. let MsgBody = item.MsgBody || []
  374. if (Array.isArray(MsgBody)) {
  375. MsgBody.forEach(item1 => {
  376. msgList.unshift({
  377. conversationType: 'GROUP',
  378. conversationID: 'GROUP' + this.groupID,
  379. from: item.From_Account,
  380. nick: item.From_Account,
  381. payload: {
  382. data: item1.MsgContent.Data
  383. }
  384. })
  385. })
  386. }
  387. })
  388. if (msg) {
  389. msgList.push(msg)
  390. }
  391. let arr = {
  392. data: msgList,
  393. };
  394. this.$refs.detail1.$onMessageReceived(arr);
  395. });
  396. },
  397. /* 判断是否登录 未登录情况下只能停留3分钟 180秒 */
  398. getIsLogin() {
  399. let that = this;
  400. if (this.isLogin == 1) return;
  401. uni.$u.http.get('/api/universal/getHot', {}).then(res => {
  402. this.$store.state.system = res;
  403. if (!this.system.login_remind || Number(this.system.login_remind) > 5000) return;
  404. this.time1 = setTimeout((res) => {
  405. if (this.isLogin == 1) {
  406. return
  407. }
  408. localStorage.setItem('watchingOutSign', true)
  409. this.$toast(this.$t('live.lab40'));
  410. setTimeout((res1) => {
  411. this.$toUrl('/pages/login/login')
  412. }, 1500);
  413. }, this.system.login_remind * 60000);
  414. })
  415. },
  416. getLiveDetail(id) {
  417. let _this = this;
  418. uni.showLoading({
  419. title: this.$t('common.lab'),
  420. });
  421. uni.$u.http
  422. .post("/api/Live_streaming/getRoomInfo", {
  423. id: this.id,
  424. })
  425. .then((res) => {
  426. this.userInfo = res.userData || {};
  427. // 编辑主播公告
  428. // res.userData.announcement1 = []
  429. // res.userData.announcement1.push(res.userData.announcement)
  430. this.roomInfo = res.info || {};
  431. this.groupID = this.roomInfo.id + '';
  432. if (this.roomInfo.match_id) {
  433. this.cricket_match_detail()
  434. } else {
  435. this.tabList = [
  436. {
  437. name: this.$t("live.detailTab1"),
  438. },
  439. {
  440. name: this.$t("live.detailTab2"),
  441. }
  442. ]
  443. }
  444. if (JSON.stringify(res.info.clarity) == "{}") {
  445. this.quality = ["原画"];
  446. } else {
  447. this.quality = ["流畅", "标清", "高清"];
  448. // 重组清晰画质连接
  449. let qualityArr = [];
  450. for (let var1 in res.info.clarity) {
  451. let name = var1;
  452. // if(var1 == 'smooth') {
  453. // name = '540'
  454. // }else if(var1 == 'sd') {
  455. // name = '720'
  456. // }else if(var1 == 'hd') {
  457. // name = '1080'
  458. // }
  459. qualityArr.push({
  460. name,
  461. src: res.info.clarity[var1],
  462. });
  463. }
  464. qualityArr.unshift({
  465. src: res.info.pull,
  466. name: this.$t("live.standard"),
  467. });
  468. this.qualityArr = qualityArr;
  469. }
  470. this.loginTim()
  471. setTimeout(() => {
  472. this.videoInit(res.info)
  473. }, 1000)
  474. }).finally(() => {
  475. uni.hideLoading();
  476. });
  477. },
  478. loginTim() {
  479. if (this.isLogin == 1) {
  480. this.$store.dispatch('loginTim', this.infos).then(() => {
  481. this.joinGroup(this.infos)
  482. })
  483. } else {
  484. bus.$on('chatLogin', this.joinGroup)
  485. let youkeInfo = JSON.parse(sessionStorage.getItem('youkeInfo'))
  486. if (youkeInfo) {
  487. this.$store.dispatch('loginTim', {
  488. ...youkeInfo,
  489. types: 'youke'
  490. }).then(() => {
  491. this.joinGroup(youkeInfo)
  492. })
  493. } else {
  494. uni.$u.http.post("/api/Universal/imTouristAccount").then(res => {
  495. sessionStorage.setItem('youkeInfo', JSON.stringify(res))
  496. this.$store.dispatch('loginTim', {
  497. ...res,
  498. types: 'youke'
  499. }).then(() => {
  500. this.joinGroup(res)
  501. })
  502. })
  503. }
  504. }
  505. },
  506. joinGroup(info, sign) {
  507. uni.$TUIKit.joinGroup({
  508. groupID: this.groupID,
  509. type: "TIM.TYPES.GRP_AVCHATROOM",
  510. }).then((imResponse) => {
  511. switch (imResponse.data.status) {
  512. case uni.$TUIKitTIM.TYPES.JOIN_STATUS_WAIT_APPROVAL:
  513. // 等待管理员同意
  514. break;
  515. case uni.$TUIKitTIM.TYPES.JOIN_STATUS_SUCCESS:
  516. // 加群成功
  517. this.$nextTick(() => {
  518. this.login(info)
  519. });
  520. break;
  521. case "AlreadyInGroup":
  522. // 加群成功
  523. this.$nextTick(() => {
  524. if (sign) {
  525. this.login(info)
  526. } else {
  527. this.getHistoryMsg()
  528. }
  529. });
  530. break;
  531. case uni.$TUIKitTIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP:
  532. // 已经在群中
  533. break;
  534. default:
  535. break;
  536. }
  537. });
  538. },
  539. login(infos) {
  540. let data = {
  541. type: 102,
  542. nobel: {
  543. level: 1,
  544. // 贵族图标guard_icon || 等级图标exp_icon || 房主图标
  545. exp_icon: infos.exp_icon,
  546. is_guard: infos.is_guard,
  547. guard_swf: infos.is_guard == 1 ? infos.guard.swf : "",
  548. guard_name: infos.is_guard == 1 ? infos.guard.swf_name : "",
  549. is_room: infos.id == this.groupID ? 1 : 0,
  550. guard_icon: infos.is_guard == 1 ? infos.guard.icon : "",
  551. },
  552. };
  553. let to = this.groupID;
  554. const message = uni.$TUIKit.createCustomMessage({
  555. to,
  556. conversationType: "GROUP",
  557. payload: {
  558. data: JSON.stringify(data),
  559. },
  560. });
  561. uni.$TUIKit
  562. .sendMessage(message)
  563. .then((res) => {
  564. this.getHistoryMsg()
  565. })
  566. .catch((error) => {});
  567. },
  568. change(e) {
  569. this.current = e.index;
  570. if (e == 2) {
  571. setTimeout((res) => {
  572. this.$refs.detail3.getList({ uid: this.userInfo.uid, type: 0 });
  573. }, 100);
  574. }
  575. },
  576. setSeek(type) {
  577. if (this.toolbarTimer) {
  578. clearTimeout(this.toolbarTimer)
  579. }
  580. this.toolbarTimer = setTimeout(() => {
  581. this.toolbar = false
  582. this.toolbarTimer = null
  583. }, 3000)
  584. let t = this.player.getCurrentTime();
  585. let a = this.player.getDuration();
  586. t += type
  587. if (t < 0) {
  588. t = 0
  589. }
  590. if (t > a) {
  591. t = a
  592. }
  593. this.player.seek(t)
  594. },
  595. playToggle() {
  596. let status = this.player.getStatus();
  597. if (this.toolbarTimer) {
  598. clearTimeout(this.toolbarTimer)
  599. }
  600. this.toolbarTimer = setTimeout(() => {
  601. this.toolbar = false
  602. this.toolbarTimer = null
  603. }, 3000)
  604. if (status == 'playing') {
  605. this.isPlay = false
  606. this.userClick = true
  607. this.player.pause()
  608. } else {
  609. this.isPlay = true
  610. this.player.play()
  611. }
  612. },
  613. clickPlay() {
  614. try {
  615. var evt = document.createEvent('HTMLEvents')
  616. evt.initEvent('click', true, true)
  617. document.getElementById('palyevent').dispatchEvent(evt)
  618. } catch (error) {
  619. }
  620. },
  621. owerPlay() {
  622. this.isPlay = true
  623. this.player && this.player.play()
  624. },
  625. owerPlay1() {
  626. if (this.userClick) {
  627. return
  628. }
  629. this.owerPlay()
  630. },
  631. downloadTimerFun() {
  632. this.downloadShow = false
  633. this.downloadTimer = setTimeout(() => {
  634. this.downloadShow = true
  635. }, 60000 * 2)
  636. },
  637. adClick(info) {
  638. if (info.adver_url_one) {
  639. uni.$u.http
  640. .post("/api/live_streaming/click_adv", {
  641. type: this.liveType == 'game' ? 6 : 3,
  642. id: info.id,
  643. url: info.adver_url_one
  644. })
  645. .then((res) => {
  646. }).finally(() => {
  647. });
  648. window.open(info.adver_url_one)
  649. }
  650. },
  651. adClick1(info) {
  652. if (info.qr_url) {
  653. window.open(info.qr_url)
  654. }
  655. }
  656. },
  657. };
  658. </script>
  659. <style lang="scss">
  660. page {
  661. background-color: #f3f3f7;
  662. }
  663. .detail {
  664. position: relative;
  665. background: #f3f3f7;
  666. }
  667. .body {
  668. position: sticky;
  669. top: 0;
  670. z-index: 20;
  671. background-color: #f3f3f7;
  672. }
  673. @media screen and (orientation: landscape) {
  674. .body {
  675. position: relative;
  676. }
  677. }
  678. #palyevent {
  679. opacity: 0;
  680. position: absolute;
  681. top: 0;
  682. left: 0;
  683. }
  684. .icon-box {
  685. position: absolute;
  686. top: 50%;
  687. left: 50%;
  688. transform: translate(-50%, -50%);
  689. color: #fff;
  690. font-weight: 700;
  691. z-index: 9997;
  692. display: flex;
  693. align-items: center;
  694. background-color: rgba(0, 0, 0, 0.1);
  695. .u-icon {
  696. padding: 10px;
  697. }
  698. }
  699. .row {
  700. display: flex;
  701. align-items: center;
  702. text-align: center;
  703. background-color: rgb(18, 20, 21);
  704. color: #fff;
  705. font-size: 14px;
  706. .col {
  707. flex: 1;
  708. display: flex;
  709. align-items: center;
  710. justify-content: center;
  711. height: 20px;
  712. }
  713. .u-icon {
  714. margin: 0 5px;
  715. }
  716. }
  717. .tabs {
  718. position: relative;
  719. }
  720. .u-tabs {
  721. background-color: #fff;
  722. }
  723. .adver-box {
  724. position: relative;
  725. .qr_img {
  726. position: absolute;
  727. top: 0;
  728. right: 0;
  729. height: 100%;
  730. }
  731. }
  732. .ad {
  733. display: block;
  734. width: 100%;
  735. }
  736. </style>