app.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. <template>
  2. <LoadingLogo v-if="hadVideo" :thumb="true" />
  3. <OpenVideo v-else @close="hadVideo = true" />
  4. <Guide />
  5. <div class="ui-view-layout" :class="{ show: show }" is-mobile="true">
  6. <div class="scene" ref="scene$"></div>
  7. <template v-if="dataLoaded">
  8. <Information v-if="!isshoppingguide" />
  9. <Control />
  10. <teleport v-if="refMiniMap && player.showWidgets" :to="refMiniMap">
  11. <span :class="{ gudieDisabled: isshoppingguide && role != 'leader' }" class="button-switch" @click.stop="toggleMap">
  12. <ui-icon type="show_map_collect"></ui-icon>
  13. </span>
  14. <p class="change" :class="{ gudieDisabled: isshoppingguide && role != 'leader' }" @click="changeMode('dollhouse', $event, 'focus3d')">
  15. <ui-icon type="show_3d_normal"></ui-icon>
  16. 3D模型
  17. </p>
  18. </teleport>
  19. <template v-if="refMiniMap && player.showWidgets">
  20. <div
  21. :class="{ disabled: flying, gudieDisabled: isshoppingguide && role != 'leader' }"
  22. v-show="mode != 'panorama'"
  23. v-if="controls.showFloorplan && controls.showDollhouse"
  24. class="tab-layer"
  25. >
  26. <div class="tabs" v-if="controls.showMap">
  27. <span :class="{ active: mode === 'floorplan' }" @click="changeMode('floorplan', $event)">
  28. <ui-icon :type="mode == 'floorplan' ? 'show_plane_selected' : 'show_plane_normal'"></ui-icon>
  29. 二維
  30. </span>
  31. <span :class="{ active: mode === 'dollhouse' }" @click="changeMode('dollhouse', $event)">
  32. <ui-icon :type="mode == 'dollhouse' ? 'show_3d_selected' : 'show_3d_normal'"></ui-icon>
  33. 三維
  34. </span>
  35. <div class="background" ref="background"></div>
  36. </div>
  37. </div>
  38. </template>
  39. </template>
  40. <!-- <UiTags /> -->
  41. </div>
  42. <GoodsList @close="closetagtype" />
  43. <Treasure @close="closetagtype" />
  44. <Waterfall @close="closetagtype" />
  45. </template>
  46. <script setup>
  47. import { useMusicPlayer } from "@/utils/sound";
  48. // import UiTags from "@/components/Tags";
  49. import GoodsList from "@/components/Tags/goods-list.vue";
  50. import Treasure from "@/components/Tags/treasure.vue";
  51. import Waterfall from "@/components/Tags/waterfall.vue";
  52. import Information from "@/components/Information";
  53. import Control from "@/components/Controls/Control.Mobile.vue";
  54. import LoadingLogo from "@/components/shared/Loading.vue";
  55. import OpenVideo from "@/components/openVideo/";
  56. import Guide from "@/components/shared/Guide.vue";
  57. import { Dialog } from "@/global_components/";
  58. import { createApp } from "@/app";
  59. import { ref, onMounted, computed, nextTick, watch } from "vue";
  60. import { useStore } from "vuex";
  61. import browser from "@/utils/browser";
  62. import { useApp, getApp } from "@/app";
  63. import common from "@/utils/common";
  64. import { Cache } from "@/utils/index";
  65. import * as apis from "@/apis/index.js";
  66. const store = useStore();
  67. let jumpNewScene = (sceneFirstView) => {
  68. let url = window.location.href;
  69. if (!browser.hasURLParam("pose")) {
  70. url += `&${sceneFirstView.sceneview}`;
  71. } else {
  72. url = browser.replaceQueryString(url, "pose", sceneFirstView.sceneview.replace("pose=", ""));
  73. }
  74. url = browser.replaceQueryString(url, "m", sceneFirstView.num);
  75. return url;
  76. };
  77. let visibilitychangeFn = () => {
  78. if (browser.isTabHidden()) {
  79. apis.burying_point({ type: 1 });
  80. }
  81. };
  82. let hashchangefn = () => {
  83. if (window.location.hash.indexOf("#showpage") >= 0) {
  84. window.history.go(-1);
  85. }
  86. };
  87. const musicPlayer = useMusicPlayer();
  88. let app = null;
  89. let tagid = browser.getURLParam("tagid");
  90. const role = ref(browser.getURLParam("role"));
  91. const userName = ref(browser.getURLParam("name"));
  92. const closetagtype = () => {
  93. store.commit("tag/setTagClickType", {
  94. type: "",
  95. data: {},
  96. });
  97. if (isshoppingguide.value) {
  98. if (role.value == "leader") {
  99. socket.value &&
  100. socket.value.emit("action", {
  101. type: "tagclose",
  102. });
  103. }
  104. }
  105. };
  106. const socket = computed(() => store.getters["rtc/socket"]);
  107. const tags = computed(() => {
  108. return store.getters["tag/tags"] || [];
  109. });
  110. const isshoppingguide = computed(() => store.getters["shoppingguide"]);
  111. const player = computed(() => store.getters["player"]);
  112. const flying = computed(() => store.getters["flying"]);
  113. const metadata = computed(() => store.getters["scene/metadata"]);
  114. const controls = computed(() => {
  115. return metadata.value.controls;
  116. });
  117. const mode = computed(() => store.getters["mode"]);
  118. const showNavigations = computed(() => store.getters["showNavigations"]);
  119. const scene$ = ref(null);
  120. const hadVideo = ref(true);
  121. if (!Cache.get("HIDENVIDEOEXPIRES")) {
  122. if (browser.getURLParam("m") == "eur-KJ-z5ZEV22AeU" && browser.getURLParam("pose") == "pano:408,qua:-0.006,0.6299,0.0049,0.7766") {
  123. Cache.set("HIDENVIDEOEXPIRES", "yes", 60 * 8 * 60);
  124. hadVideo.value = false;
  125. } else {
  126. hadVideo.value = true;
  127. }
  128. }
  129. if (role.value) {
  130. hadVideo.value = true;
  131. }
  132. const show = ref(false);
  133. const dataLoaded = ref(false);
  134. const refMiniMap = ref(null);
  135. const isCollapse = ref(false);
  136. const background = ref(null);
  137. const resize = () => {
  138. if (this.$refs.background && (this.mode == "floorplan" || this.mode == "dollhouse")) {
  139. this.$nextTick(() => {
  140. let $active = $(this.$el).find(".tabs .active");
  141. background.value.style.width = $active[0].getBoundingClientRect().width + "px";
  142. background.value.style.left = $active.position().left + "px";
  143. });
  144. }
  145. };
  146. watch(
  147. () => isshoppingguide.value,
  148. (val, old) => {
  149. let $minmap = document.querySelector("[xui_min_map]");
  150. if ($minmap) {
  151. setTimeout(async () => {
  152. if (role.value == "leader") {
  153. return;
  154. }
  155. await nextTick();
  156. if (isshoppingguide.value) {
  157. $minmap.classList.add("gudieDisabled");
  158. } else {
  159. $minmap.classList.remove("gudieDisabled");
  160. }
  161. });
  162. }
  163. },
  164. {
  165. deep: true,
  166. }
  167. );
  168. watch(
  169. () => player.value.showMap,
  170. (val, old) => {
  171. if (!isCollapse.value) {
  172. let $minmap = document.querySelector("[xui_min_map]");
  173. if ($minmap) {
  174. if (val) {
  175. $minmap.classList.remove("collapse");
  176. } else {
  177. $minmap.classList.add("collapse");
  178. }
  179. }
  180. }
  181. },
  182. {
  183. deep: true,
  184. }
  185. );
  186. watch(
  187. () => player.value.showWidgets,
  188. (val, old) => {
  189. let $minmap = document.querySelector("[xui_min_map]");
  190. if ($minmap) {
  191. if (val) {
  192. $minmap.classList.remove("collapse");
  193. } else {
  194. $minmap.classList.add("collapse");
  195. }
  196. }
  197. },
  198. {
  199. deep: true,
  200. }
  201. );
  202. const changeMode = (name, e, focus3d = false) => {
  203. if (!flying.value) {
  204. let width, left;
  205. store.commit("setMode", name);
  206. nextTick(() => {
  207. if (focus3d) {
  208. let $active = document.querySelector(".tabs>span:last-of-type");
  209. background.value.style.width = $active.getBoundingClientRect().width + "px";
  210. background.value.style.left = $active.offsetLeft + "px";
  211. } else {
  212. background.value.style.width = width || e.srcElement.getBoundingClientRect().width + "px";
  213. background.value.style.left = left || e.srcElement.offsetLeft + "px";
  214. }
  215. });
  216. }
  217. // console.dir(document.querySelector(".tabs>span:last-of-type"));
  218. };
  219. const toggleMap = () => {
  220. isCollapse.value = !isCollapse.value;
  221. let $minmap = document.querySelector("[xui_min_map]");
  222. if ($minmap) {
  223. if (!isCollapse.value) {
  224. $minmap.classList.remove("collapse");
  225. } else {
  226. $minmap.classList.add("collapse");
  227. }
  228. }
  229. };
  230. const onClickTagInfo = (el) => {
  231. el.stopPropagation();
  232. let item = tags.value.find((item) => item.sid == el.target.dataset.id);
  233. if (item.type == "commodity") {
  234. guideclicktag(item);
  235. store.commit("tag/setTagClickType", {
  236. type: "goodlist",
  237. data: item,
  238. });
  239. } else if (item.type == "link_scene") {
  240. guideclicktag(item);
  241. let sceneFirstView = item.hotContent.sceneFirstView;
  242. window.location.href = jumpNewScene(sceneFirstView);
  243. }
  244. };
  245. const guideclicktag = (tag) => {
  246. if (isshoppingguide.value) {
  247. if (role.value == "leader") {
  248. socket.value &&
  249. socket.value.emit("action", {
  250. type: "tagclick",
  251. data: {
  252. sid: tag.sid,
  253. },
  254. });
  255. }
  256. }
  257. };
  258. onMounted(async () => {
  259. apis.burying_point({ type: 0 });
  260. app = createApp({
  261. num: browser.getURLParam("m"),
  262. dom: scene$.value,
  263. mobile: true,
  264. isLoadTags: false,
  265. sceneKind: "tiles",
  266. scene: {
  267. markerOpacity: 1,
  268. markerURL: "https://eurs3.4dkankan.com/cdf/file/43aa29799bfd472298a47cc6370b10cc.png",
  269. pathEndColor: "#FF4641",
  270. },
  271. });
  272. app.use("MinMap", { theme: { camera_fillStyle: "#ED5D18" } });
  273. app.use("Tag");
  274. app
  275. .use("TagView", {
  276. render(data) {
  277. if (data.type == "waterfall") {
  278. return `<span class="tag-icon waterfall animate" style="background-image:url({{icon}})"></span>`;
  279. } else if (data.type == "coupon") {
  280. return `<span class="tag-icon coupon animate" style="background-image:url({{icon}})"></span>`;
  281. } else if (data.type == "applet_link") {
  282. try {
  283. data.hotContent = JSON.parse(data.hotContent);
  284. } catch (error) {}
  285. return `<span class="tag-icon applet_link animate" style="background-image:url(${
  286. data.hotContent.liveIcon.src ? common.changeUrl(data.hotContent.liveIcon.src) : "{{icon}}"
  287. })"></span>`;
  288. } else if (data.type == "link_scene") {
  289. return `<span class="tag-icon animate" style="background-image:url({{icon}})"></span>
  290. <div class="tag-body">
  291. <div data-id="${data.sid}" class="tag-commodity tag-link_scene">
  292. <p class="tag-title">點擊前往下一個區域</p>
  293. </div>
  294. </div>
  295. `;
  296. } else if (data.type == "commodity") {
  297. let arr = data.products.map((item) => item.price);
  298. let priceMin = isFinite(Math.min.apply(null, arr)) ? Math.min.apply(null, arr) : 0;
  299. let priceMax = isFinite(Math.max.apply(null, arr)) ? Math.max.apply(null, arr) : 0;
  300. let price = priceMin == priceMax ? priceMax : `${priceMin}-${priceMax}`;
  301. let range = `${data.products[0] ? data.products[0].symbol : "MOP$"} ${price}`;
  302. return `<span class="tag-icon animate" style="background-image:url({{icon}})"></span>
  303. <div class="tag-body">
  304. <div data-id="${data.sid}" class="tag-commodity">
  305. <div style="background-image:url(${data.products[0] ? data.products[0].pic : ""})" class='tag-avatar'>
  306. </div>
  307. <p class="tag-title">${data.title}</p>
  308. <p class="tag-info">${range} | 查看 ></p>
  309. </div>
  310. </div>
  311. `;
  312. } else {
  313. return `<span class="tag-icon animate" style="background-image:url({{icon}})"></span>`;
  314. }
  315. },
  316. })
  317. .then((view) => {
  318. view.on("click", (e) => {
  319. var tag = e.data;
  320. // 聚焦當前點擊的熱點
  321. view.focus(tag.sid).then(() => {
  322. if (tag.type == "coupon") {
  323. try {
  324. document.querySelector(`[data-tag-id="${tag.sid}"] .tag-icon`).style.display = "none";
  325. let hotcontent = typeof tag.hotContent == "string" ? JSON.parse(tag.hotContent) : tag.hotContent;
  326. browser.openLink(
  327. "/subPackage/pages/activity/activity?pageId=" + hotcontent.couponLink,
  328. `https://m.cdfmembers.com/shop/600667208/showactivity?pageId=${hotcontent.couponLink}`,
  329. `/pages/showactivity/showactivity?pageId=${hotcontent.couponLink}`
  330. );
  331. apis.burying_point({ type: 2 });
  332. } catch (error) {}
  333. } else if (tag.type == "waterfall") {
  334. store.commit("tag/setTagClickType", {
  335. type: "waterfall",
  336. data: tag,
  337. });
  338. guideclicktag(tag);
  339. } else if (tag.type == "applet_link") {
  340. try {
  341. let hotcontent = typeof tag.hotContent == "string" ? JSON.parse(tag.hotContent) : tag.hotContent;
  342. browser.openLink(
  343. "/subPackage/pages/home/home?pageType=2&pageId=" + hotcontent.liveLink,
  344. `https://m.cdfmembers.com/shop/600667208/showactivity?pageId=${hotcontent.liveLink}`,
  345. `/pages/showactivity/showactivity?pageId=${hotcontent.liveLink}`
  346. );
  347. } catch (error) {}
  348. } else if (tag.type == "link_scene") {
  349. guideclicktag(tag);
  350. let sceneFirstView = tag.hotContent.sceneFirstView;
  351. window.location.href = jumpNewScene(sceneFirstView);
  352. }
  353. });
  354. });
  355. view.on("focus", (e) => {
  356. document.querySelectorAll("[xui_tags_view] >div").forEach((el) => {
  357. if (el.getAttribute("data-tag-type") == "link_scene" || el.getAttribute("data-tag-type") == "commodity") {
  358. el.querySelector(".tag-body").classList.remove("show");
  359. el.style.zIndex = "auto";
  360. }
  361. });
  362. if (e.data.type == "commodity" || e.data.type == "link_scene") {
  363. e.target.style.zIndex = "999";
  364. e.target.querySelector(".tag-body").classList.add("show");
  365. e.target.querySelector(".tag-commodity").removeEventListener("click", onClickTagInfo);
  366. e.target.querySelector(".tag-commodity").addEventListener("click", onClickTagInfo);
  367. if (tagid) {
  368. document.querySelector(`[data-id="${tagid}"]`) && document.querySelector(`[data-id="${tagid}"]`).click();
  369. tagid = null;
  370. }
  371. }
  372. });
  373. view.on("rendered", (e) => {
  374. tagid && view.focus(tagid);
  375. }); //dom渲染完成
  376. });
  377. app.use("TourPlayer");
  378. // if (!hadVideo.value) {
  379. // app.Scene.lock();
  380. // }
  381. app.Scene.on("ready", () => {
  382. show.value = true;
  383. });
  384. app.Scene.on("error", (data) => {
  385. switch (data.code) {
  386. case 5033:
  387. Dialog.alert("该场景正在计算中,请稍后再试");
  388. break;
  389. case 5034:
  390. Dialog.alert("服务端开小差,请稍后再试");
  391. break;
  392. case 5009:
  393. Dialog.alert("服务端开小差,请稍后再试");
  394. break;
  395. case 5005:
  396. Dialog.alert("服务端开小差,请稍后再试");
  397. break;
  398. }
  399. });
  400. app.Scene.on("loaded", (pano) => {
  401. refMiniMap.value = "[xui_min_map]";
  402. store.commit("setFloorId", pano.floorIndex);
  403. store.commit("rtc/setShowdaogou", true);
  404. if (browser.getURLParam("roomId")) {
  405. store.commit("showShoppingguide", true);
  406. }else{
  407. if (!localStorage.getItem("user_guide")) {
  408. Dialog.confirm({
  409. showCloseIcon: false,
  410. okText: "我知道了",
  411. content:
  412. "<span style='font-size: 16px; line-height: 1.5;'>開發者已遵守收集、使用最終用戶個人信息有關的所有可適用法律、政策和法規,保護用戶個人信息安全。<span/>",
  413. title: "隱私條款:",
  414. single: true,
  415. func: (state) => {
  416. if (state == "ok") {
  417. localStorage.setItem("user_guide", Date.now());
  418. }
  419. },
  420. });
  421. }
  422. }
  423. app.resource.tags(`${process.env.VUE_APP_RESOURCE_URL}cdf/hot/${browser.getURLParam("m")}/hot.json?rnd=${Math.random()}`);
  424. useMusicPlayer();
  425. });
  426. app.Scene.on("panorama.videorenderer.resumerender", () => {
  427. musicPlayer.pause(true);
  428. });
  429. app.Scene.on("panorama.videorenderer.suspendrender", async () => {
  430. let player = await getApp().TourManager.player;
  431. if (!player.isPlaying) {
  432. musicPlayer.resume();
  433. }
  434. });
  435. app.store.on("metadata", (metadata) => {
  436. store.commit("scene/load", metadata);
  437. if (!metadata.controls.showMap) {
  438. app.MinMap.hide(true);
  439. }
  440. dataLoaded.value = true;
  441. });
  442. app.store.on("tags", (tags) => {
  443. store.commit("tag/load", tags);
  444. });
  445. app.Camera.on("mode.beforeChange", ({ fromMode, toMode, floorIndex }) => {
  446. if (fromMode) {
  447. store.commit("setFlying", true);
  448. }
  449. });
  450. app.Camera.on("mode.afterChange", ({ toMode, floorIndex }) => {
  451. store.commit("setFlying", false);
  452. });
  453. app.Camera.on("flying.started", (pano) => {
  454. store.commit("setFlying", true);
  455. });
  456. app.Camera.on("flying.ended", ({ targetPano }) => {
  457. store.commit("setFlying", false);
  458. store.commit("setPanoId", targetPano.id);
  459. if (app.Scene.isCurrentPanoHasVideo) {
  460. apis.burying_point({ type: 5 });
  461. }
  462. });
  463. app.Camera.on("pano.chosen", (pano) => {
  464. apis.burying_point({ type: 4 });
  465. });
  466. app.store.on("tour", async (tour) => {
  467. app.TourManager.load(tour);
  468. store.commit("tour/setData", {
  469. tours: JSON.parse(
  470. JSON.stringify(app.TourManager.tours, (key, val) => {
  471. if (key === "audio") {
  472. return null;
  473. } else {
  474. return val;
  475. }
  476. })
  477. ),
  478. });
  479. store.commit("tour/setBackUp", {
  480. tours: JSON.parse(
  481. JSON.stringify(app.TourManager.tours, (key, val) => {
  482. if (key === "audio") {
  483. return null;
  484. } else {
  485. return val;
  486. }
  487. })
  488. ),
  489. });
  490. });
  491. app.store.on("floorcad", (floor) => store.commit("scene/loadFloorData", floor));
  492. app.render();
  493. document.removeEventListener("visibilitychange", visibilitychangeFn);
  494. document.addEventListener("visibilitychange", visibilitychangeFn);
  495. if (browser.detectWeixin()) {
  496. //ios的ua中无miniProgram,但都有MicroMessenger(表示是微信浏览器)
  497. wx.miniProgram.getEnv((res) => {
  498. if (res.miniprogram) {
  499. window.removeEventListener("hashchange", hashchangefn);
  500. window.addEventListener("hashchange", hashchangefn);
  501. }
  502. });
  503. }
  504. });
  505. </script>
  506. <style lang="scss">
  507. .tab-layer {
  508. width: 100%;
  509. text-align: center;
  510. display: flex;
  511. justify-content: center;
  512. align-items: center;
  513. z-index: 10;
  514. position: fixed;
  515. left: 50%;
  516. transform: translateX(-50%);
  517. top: 2.3rem;
  518. pointer-events: none;
  519. }
  520. .tabs {
  521. pointer-events: auto;
  522. position: relative;
  523. display: flex;
  524. background: #222222;
  525. border-radius: 6px;
  526. padding: 2px;
  527. justify-content: center;
  528. align-items: center;
  529. border: 1px solid rgba(255, 255, 255, 0.1);
  530. box-shadow: inset 0px 0px 6px 0px rgba(0, 0, 0, 0.5);
  531. .background {
  532. position: absolute;
  533. left: 2px;
  534. top: 2px;
  535. bottom: 2px;
  536. width: 50%;
  537. border-radius: 4px;
  538. background: #444444;
  539. box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.3);
  540. z-index: 0;
  541. transition: left 0.3s;
  542. }
  543. span {
  544. flex: 1;
  545. color: #fff;
  546. opacity: 0.5;
  547. border-radius: 6px;
  548. height: 0.94737rem;
  549. font-size: 0.36842rem;
  550. transition: all 0.3s ease;
  551. display: flex;
  552. align-items: center;
  553. justify-content: center;
  554. padding-left: 10px;
  555. padding-right: 10px;
  556. white-space: nowrap;
  557. z-index: 1;
  558. i {
  559. font-size: 0.47368rem;
  560. margin-right: 4px;
  561. pointer-events: none;
  562. }
  563. }
  564. span.active {
  565. opacity: 1;
  566. }
  567. }
  568. [xui_tags_view] {
  569. .tag-body {
  570. /* display: none; */
  571. position: absolute;
  572. left: 50%;
  573. bottom: 50px;
  574. transform: translateX(-50%) scale(0);
  575. transform-origin: bottom;
  576. transition: all 0.3s cubic-bezier(0.35, 0.32, 0.65, 0.63);
  577. // pointer-events: none;
  578. .tag-commodity,
  579. .tag-link_scene {
  580. min-width: 230px;
  581. height: 76px;
  582. background: rgba(255, 255, 255, 0.8);
  583. box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.16);
  584. border-radius: 2px;
  585. position: relative;
  586. margin-bottom: 30px;
  587. &::before {
  588. content: "";
  589. display: inline-block;
  590. left: 50%;
  591. transform: translateX(-50%);
  592. width: 2px;
  593. height: 28px;
  594. bottom: -30px;
  595. background: linear-gradient(145deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0));
  596. position: absolute;
  597. }
  598. .tag-avatar {
  599. position: absolute;
  600. z-index: 99;
  601. width: 80px;
  602. height: 80px;
  603. background: #ffffff;
  604. box-shadow: 0px 3px 6px 0px rgb(0 0 0 / 16%);
  605. border-radius: 2px;
  606. top: -14px;
  607. left: -12px;
  608. background-size: cover;
  609. pointer-events: none;
  610. }
  611. > p {
  612. color: #131d34;
  613. font-size: 16px;
  614. pointer-events: none;
  615. }
  616. .tag-title {
  617. padding: 10px 10px 10px 76px;
  618. overflow: hidden;
  619. text-overflow: ellipsis;
  620. white-space: nowrap;
  621. width: 240px;
  622. }
  623. .tag-info {
  624. padding: 0 20px 0 76px;
  625. font-size: 12px;
  626. overflow: hidden;
  627. text-overflow: ellipsis;
  628. white-space: nowrap;
  629. }
  630. }
  631. &.show {
  632. transform: translateX(-50%) scale(1);
  633. }
  634. .tag-link_scene {
  635. height: auto;
  636. min-width: unset;
  637. .tag-title {
  638. padding: 10px;
  639. width: auto;
  640. text-align: center;
  641. }
  642. }
  643. }
  644. .coupon {
  645. width: 84px !important;
  646. height: 84px !important;
  647. &::after {
  648. content: "發現好禮";
  649. width: 100%;
  650. color: #ed5d18;
  651. position: absolute;
  652. bottom: -24px;
  653. text-align: center;
  654. font-size: 14px;
  655. }
  656. }
  657. .waterfall {
  658. width: 90px !important;
  659. height: 90px !important;
  660. }
  661. .applet_link {
  662. width: 64px !important;
  663. height: 64px !important;
  664. border-radius: 50%;
  665. background-color: #fff;
  666. border: 1px solid #ed5d18;
  667. position: relative;
  668. overflow: hidden;
  669. &::after {
  670. content: "直播中";
  671. width: 100%;
  672. height: 20px;
  673. background: #ed5d18;
  674. position: absolute;
  675. bottom: 0;
  676. text-align: center;
  677. line-height: 1.2;
  678. font-size: 12px;
  679. border-radius: 26%;
  680. }
  681. }
  682. }
  683. .gudieDisabled {
  684. pointer-events: none !important;
  685. * {
  686. pointer-events: none !important;
  687. }
  688. }
  689. @media (orientation: landscape) {
  690. .tab-layer {
  691. top: 1.2rem;
  692. .tabs {
  693. height: 0.7rem;
  694. > span {
  695. height: 0.7rem;
  696. font-size: 0.25rem;
  697. }
  698. }
  699. }
  700. }
  701. </style>