View.Mobile.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. <template>
  2. <div class="header">
  3. <div class="left" :class="{ show: player.showVR }">
  4. <div
  5. v-show="mode != 'panorama'"
  6. :class="{ disabled: flying }"
  7. class="back-pano"
  8. @click="onChangeMode"
  9. >
  10. <ui-icon type="show_back"></ui-icon>
  11. </div>
  12. <div v-show="mode == 'panorama'" class="back" @click="onBack">
  13. <ui-icon type="_back"></ui-icon>
  14. </div>
  15. </div>
  16. <div
  17. class="title"
  18. :class="{
  19. up: player.showDescription,
  20. drak: mode != 'panorama',
  21. empty: !description,
  22. }"
  23. @click="onShowDescription"
  24. v-show="player.showWidgets"
  25. >
  26. <div>
  27. <span>
  28. {{ metadata.title }}
  29. </span>
  30. <i class="iconfont icon-pull-down"></i>
  31. </div>
  32. </div>
  33. <div class="right"></div>
  34. <transition
  35. appear
  36. name="custom-classes-transition"
  37. enter-active-class="animated fadeInUp short faster"
  38. leave-active-class="animated fadeOutDown short faster"
  39. >
  40. <div
  41. class="content"
  42. :class="{ drak: mode != 'panorama' }"
  43. v-if="player.showDescription"
  44. @click="onShowDescription"
  45. >
  46. <div>
  47. <div v-html="description"></div>
  48. </div>
  49. </div>
  50. </transition>
  51. <div class="url-share" v-show="showCopy">
  52. <div>
  53. <div class="tips">
  54. <h4>分享链接给好友</h4>
  55. <i class="iconfont iconshow_cancel" @click="showCopy = false"></i>
  56. </div>
  57. <div class="url">{{ copyLink }}</div>
  58. <div class="btns">
  59. <ui-button class="cancel" @click="showCopy = false">取消</ui-button>
  60. <ui-button class="primary" :data-clipboard-text="copyLink" ref="copy$"
  61. >一键复制</ui-button
  62. >
  63. </div>
  64. </div>
  65. </div>
  66. </div>
  67. </template>
  68. <script setup>
  69. import ClipboardJS from "clipboard";
  70. import browser from "@/utils/browser";
  71. import { useStore } from "vuex";
  72. import { Dialog } from "@/global_components/";
  73. import { MessageToApp, NotchHeight } from "@/utils/platform";
  74. import { onMounted, watch, computed, ref, nextTick } from "vue";
  75. const store = useStore();
  76. let share_url = browser.getURLParam("share_url");
  77. if (share_url) {
  78. share_url = decodeURIComponent(share_url);
  79. } else {
  80. share_url = location.href.split("#")[0];
  81. }
  82. const deploy = ref(process.env.VUE_APP_DEPLOY);
  83. // const musicPlayer = useMusicPlayer();
  84. const loadingLogoFile = computed(() => store.getters["scene/loadingLogoFile"]);
  85. const metadata = computed(() => store.getters["scene/metadata"]);
  86. const controls = computed(() => {
  87. return metadata.value.controls;
  88. });
  89. const showMusic = computed(() => store.getters["scene/metadata"].music);
  90. const player = computed(() => store.getters["player"]);
  91. const flying = computed(() => store.getters["flying"]);
  92. const copy$ = ref(null);
  93. const copyLink = computed(() => {
  94. return share_url.replace("&app", "");
  95. });
  96. const showCopy = ref(false);
  97. const showShare = ref(false);
  98. const isMusicPlaying = ref(false);
  99. const mode = computed(() => store.getters["mode"]);
  100. const description = computed(() => metadata.value.description);
  101. watch(
  102. () => showCopy.value,
  103. (val, old) => {
  104. store.commit("SetPlayerOptions", {
  105. showMap: !showCopy.value,
  106. showToolbar: !showCopy.value,
  107. });
  108. },
  109. {
  110. deep: true,
  111. }
  112. );
  113. watch(
  114. () => showShare.value,
  115. (val, old) => {
  116. store.commit("SetPlayerOptions", {
  117. showMap: !showShare.value,
  118. showToolbar: !showShare.value,
  119. });
  120. },
  121. {
  122. deep: true,
  123. }
  124. );
  125. onMounted(() => {
  126. new ClipboardJS(copy$.value.$el).on("success", function (e) {
  127. e.clearSelection();
  128. showCopy.value = false;
  129. Dialog.toast({ content: t("toast.copySuccess"), type: "success" });
  130. });
  131. nextTick(() => {
  132. document.querySelector(".player").addEventListener("touchstart", () => {
  133. if (player.value.showMore) {
  134. store.commit("SetPlayerOptions", {
  135. showMore: false,
  136. showMap: true,
  137. showToolbar: true,
  138. });
  139. } else if (player.value.showDescription) {
  140. store.commit("SetPlayerOptions", {
  141. showDescription: false,
  142. showMap: true,
  143. showToolbar: true,
  144. });
  145. }
  146. });
  147. window.Back = () => {
  148. onBack();
  149. };
  150. });
  151. });
  152. const onListen = () => {
  153. // this.$bus.on('orientation', () => {
  154. if (NotchHeight) {
  155. this.$el.style.top = NotchHeight + "px";
  156. }
  157. // 发送返回按钮信息
  158. const rect = document.querySelector(".back").getBoundingClientRect();
  159. const data = {
  160. BackBtnInfo: {
  161. left: rect.left,
  162. top: rect.top,
  163. radius: rect.width / 2,
  164. },
  165. };
  166. if (browser.detectAndroid()) {
  167. MessageToApp(JSON.stringify(data));
  168. } else {
  169. MessageToApp(data);
  170. }
  171. // })
  172. };
  173. const onBack = () => {
  174. // player.value.showVR && store.commit('showVR')
  175. if (player.value.showVR) {
  176. MessageToApp("VRMode0");
  177. store.commit("showVR");
  178. }
  179. };
  180. const onShowMore = () => {
  181. let show = !player.value.showMore;
  182. store.commit("SetPlayerOptions", {
  183. showMore: show,
  184. showMap: show == false,
  185. showToolbar: show == false,
  186. showDescription: false,
  187. });
  188. };
  189. const onShowDescription = () => {
  190. let show = !player.value.showDescription;
  191. store.commit("SetPlayerOptions", {
  192. showMore: false,
  193. showMap: show == false,
  194. showToolbar: show == false,
  195. showDescription: show,
  196. });
  197. };
  198. const onMusicClick = () => {
  199. showMusicPlaying.value ? musicPlayer.pause() : musicPlayer.play();
  200. };
  201. const onMenuClick = (name) => {
  202. store.commit("SetPlayerOptions", {
  203. showMore: false,
  204. showDescription: false,
  205. showMap: true,
  206. showToolbar: true,
  207. });
  208. nextTick(() => {
  209. if (name == "music") {
  210. onMusicClick();
  211. // if (isMusicPlaying.value) {
  212. // musicPlayer.pause()
  213. // } else {
  214. // musicPlayer.play()
  215. // }
  216. } else if (name == "share") {
  217. showCopy.value = true;
  218. } else if (name === "measure") {
  219. this.$bus.emit("measure/Handle", "start");
  220. } else if (name == "vr") {
  221. store.commit("showVR");
  222. }
  223. });
  224. };
  225. const onShare = (name) => {
  226. if (name == "copy") {
  227. showShare.value = false;
  228. nextTick(() => {
  229. showCopy.value = true;
  230. });
  231. } else {
  232. MessageToApp(`Share-${name}`);
  233. showCopy.value = false;
  234. showShare.value = false;
  235. }
  236. };
  237. const onChangeMode = () => {
  238. store.commit("setMode", "panorama");
  239. };
  240. </script>
  241. <style lang="scss" scoped>
  242. .disable {
  243. opacity: 1;
  244. }
  245. .header {
  246. position: absolute;
  247. top: 10px;
  248. left: 0;
  249. height: 44px;
  250. width: 100%;
  251. z-index: 101;
  252. color: #fff;
  253. display: flex;
  254. align-items: center;
  255. text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.4);
  256. pointer-events: auto;
  257. &.app {
  258. top: 1rem;
  259. }
  260. .left {
  261. width: 1rem;
  262. height: 100%;
  263. display: flex;
  264. align-items: center;
  265. justify-content: center;
  266. &.show {
  267. visibility: visible;
  268. pointer-events: auto;
  269. .back {
  270. visibility: visible;
  271. }
  272. }
  273. .back {
  274. width: 0.78rem;
  275. height: 0.78rem;
  276. border-radius: 50%;
  277. background-color: rgba(0, 0, 0, 0.3);
  278. display: flex;
  279. align-items: center;
  280. justify-content: center;
  281. visibility: hidden;
  282. position: relative;
  283. i {
  284. font-size: 0.3rem;
  285. width: auto;
  286. position: static;
  287. }
  288. }
  289. .back-pano {
  290. width: 100%;
  291. height: 100%;
  292. display: flex;
  293. align-items: center;
  294. justify-content: center;
  295. // padding-left: 15px;
  296. position: relative;
  297. i {
  298. font-size: 0.6rem;
  299. position: static;
  300. }
  301. }
  302. }
  303. .right {
  304. position: relative;
  305. width: 1.28rem;
  306. height: 100%;
  307. padding-right: 15px;
  308. display: flex;
  309. align-items: center;
  310. justify-content: flex-end;
  311. z-index: 11;
  312. > i {
  313. font-size: 0.6rem;
  314. }
  315. > div {
  316. position: absolute;
  317. display: flex;
  318. flex-direction: column;
  319. right: 10px;
  320. top: 1.3rem;
  321. padding: 4px 0.42105rem;
  322. background-color: rgba(0, 0, 0, 0.5);
  323. border-radius: 5px;
  324. &::after {
  325. content: "";
  326. position: absolute;
  327. top: -5px;
  328. right: 0.3rem;
  329. width: 0;
  330. height: 0;
  331. border-width: 0 5px 5px;
  332. border-style: solid;
  333. border-color: transparent transparent rgba(0, 0, 0, 0.5);
  334. }
  335. &.flex {
  336. li {
  337. span {
  338. flex: 1;
  339. width: auto;
  340. // min-width: 2.8rem;
  341. }
  342. }
  343. }
  344. li {
  345. position: relative;
  346. display: flex;
  347. align-items: center;
  348. justify-content: center;
  349. // margin-top: 0.3rem;
  350. font-size: 0;
  351. // height: .5333rem;
  352. padding: 0.1333rem 0 0.2667rem;
  353. i {
  354. // position: absolute;
  355. // left: 0;
  356. // top: 0;
  357. // font-size: 0.45rem;
  358. font-size: 0.3733rem;
  359. margin-right: 0.4rem;
  360. }
  361. b {
  362. position: absolute;
  363. left: 0.32rem;
  364. top: 0.33rem;
  365. width: 7px;
  366. height: 7px;
  367. border-radius: 50%;
  368. background-color: #00c2c4;
  369. i {
  370. color: #fff;
  371. font-size: 12px;
  372. transform: scale(0.3, 0.3);
  373. top: -4px;
  374. left: -3px;
  375. position: absolute;
  376. }
  377. }
  378. span {
  379. width: 1.89474rem;
  380. white-space: nowrap;
  381. text-align: left;
  382. // padding-bottom: 0.3rem;
  383. // margin-left: 0.75rem;
  384. font-size: 0.3733rem;
  385. // text-indent: 0.2rem;
  386. // padding-right: 0.2rem;
  387. }
  388. }
  389. .home {
  390. border-top: solid 1px rgba(255, 255, 255, 0.4);
  391. a {
  392. width: 1.89474rem;
  393. margin-top: 0.3rem;
  394. margin-bottom: 0.1rem;
  395. margin-left: auto;
  396. margin-right: auto;
  397. display: block;
  398. text-decoration: none;
  399. overflow: hidden;
  400. img {
  401. width: 100%;
  402. outline: none;
  403. border: none;
  404. }
  405. }
  406. }
  407. }
  408. }
  409. .title {
  410. display: flex;
  411. flex: 1;
  412. width: 100%;
  413. height: 100%;
  414. font-size: 0.42105rem;
  415. letter-spacing: 1px;
  416. align-items: center;
  417. justify-content: center;
  418. pointer-events: auto;
  419. > div {
  420. display: flex;
  421. transition: background 0.3s ease, min-width 0.3s ease,
  422. border-radius 0.3s ease;
  423. align-items: center;
  424. justify-content: center;
  425. padding-right: 12px;
  426. padding-left: 12px;
  427. white-space: nowrap;
  428. position: absolute;
  429. height: 100%;
  430. min-width: 100%;
  431. overflow: visible;
  432. pointer-events: none;
  433. background: linear-gradient(
  434. 90deg,
  435. rgba(0, 0, 0, 0) 0%,
  436. rgba(0, 0, 0, 0.15) 50%,
  437. rgba(0, 0, 0, 0) 100%
  438. );
  439. }
  440. span {
  441. display: inline-block;
  442. position: relative;
  443. white-space: nowrap;
  444. overflow: hidden;
  445. text-overflow: ellipsis;
  446. max-width: 7rem;
  447. }
  448. i {
  449. transition: all 0.3s;
  450. position: absolute;
  451. left: 50%;
  452. bottom: 0;
  453. font-size: 10px;
  454. transform: translateX(-50%);
  455. }
  456. &.up {
  457. i {
  458. transform: translateX(-50%) rotate(180deg);
  459. }
  460. > div {
  461. min-width: 0;
  462. //position: static;
  463. flex-shrink: 0;
  464. background-color: rgba(0, 0, 0, 0.5);
  465. border-radius: 1.15789rem;
  466. }
  467. &.drak {
  468. > div {
  469. background-color: rgba(0, 0, 0, 0.8);
  470. }
  471. }
  472. }
  473. &.empty {
  474. i {
  475. display: none;
  476. }
  477. }
  478. }
  479. .content {
  480. position: fixed;
  481. top: 1.6rem;
  482. left: 0.92105rem;
  483. right: 0.92105rem;
  484. padding: 10px;
  485. background: rgba(0, 0, 0, 0.5);
  486. border-radius: 5px;
  487. font-size: 0.36842rem;
  488. text-align: center;
  489. max-height: 80vh;
  490. max-height: calc(var(--vh) * 80);
  491. overflow: scroll;
  492. -webkit-overflow-scrolling: touch;
  493. // z-index: 10000;
  494. pointer-events: auto;
  495. * {
  496. pointer-events: auto;
  497. -webkit-overflow-scrolling: touch;
  498. }
  499. &.drak {
  500. background: rgba(0, 0, 0, 0.8);
  501. }
  502. > div {
  503. display: inline-block;
  504. text-align: left;
  505. letter-spacing: 1px;
  506. word-break: break-all;
  507. white-space: normal;
  508. line-height: 1.5;
  509. :deep(p) {
  510. word-break: break-word;
  511. }
  512. :deep(a) {
  513. color: var(--editor-main-color);
  514. }
  515. }
  516. }
  517. .url-share {
  518. position: fixed;
  519. top: 0;
  520. left: 0;
  521. right: 0;
  522. bottom: 0;
  523. background-color: rgba(0, 0, 0, 0.1);
  524. > div {
  525. position: absolute;
  526. left: 0.6rem;
  527. right: 0.6rem;
  528. top: 50vh;
  529. transform: translateY(-50%);
  530. border-radius: 4px;
  531. background-color: rgba(0, 0, 0, 0.5);
  532. padding: 0.31579rem;
  533. font-size: 0.36842rem;
  534. .tips {
  535. display: flex;
  536. align-items: center;
  537. justify-content: space-between;
  538. h4 {
  539. margin: 0;
  540. font-size: 0.42105rem;
  541. }
  542. i {
  543. font-size: 0.6rem;
  544. }
  545. }
  546. .url {
  547. display: -webkit-box;
  548. color: #fff;
  549. text-align: center;
  550. padding: 0.26316rem;
  551. width: 100%;
  552. height: 1.8rem;
  553. margin: 0.7rem 0rem;
  554. border-radius: 0.07rem;
  555. line-height: 1.99;
  556. font-size: 0.36842rem;
  557. background-color: rgba(0, 0, 0, 0.35);
  558. overflow: hidden;
  559. text-overflow: ellipsis;
  560. word-break: break-all;
  561. word-wrap: break-word;
  562. -webkit-line-clamp: 2; //在第几行加省略号
  563. -webkit-box-orient: vertical;
  564. }
  565. .btns {
  566. display: flex;
  567. justify-content: space-between;
  568. button {
  569. font-size: 0.36842rem;
  570. width: 47%;
  571. height: 1.05263rem;
  572. border-radius: 1.05263rem;
  573. &.submit {
  574. background: #00c2c4;
  575. }
  576. }
  577. }
  578. }
  579. }
  580. }
  581. @media (orientation: landscape) {
  582. .header {
  583. top: 0.2rem;
  584. height: 0.7rem;
  585. &.app {
  586. top: 0.2rem;
  587. }
  588. .left {
  589. .back-pano {
  590. i {
  591. font-size: 0.5rem;
  592. }
  593. }
  594. }
  595. .right {
  596. > i {
  597. font-size: 0.5rem;
  598. }
  599. > div {
  600. right: 10px;
  601. top: 0.75rem;
  602. padding: 4px 0.2rem;
  603. &::after {
  604. right: 0.23rem;
  605. }
  606. li {
  607. margin-top: 0.15rem;
  608. i {
  609. font-size: 0.3rem;
  610. }
  611. b {
  612. left: 0.2rem;
  613. top: 0.15rem;
  614. }
  615. span {
  616. padding-bottom: 0.15rem;
  617. margin-left: 0.5rem;
  618. font-size: 0.25rem;
  619. }
  620. }
  621. .home {
  622. a {
  623. margin-top: 0.15rem;
  624. margin-bottom: 0rem;
  625. width: 1.4rem;
  626. }
  627. }
  628. }
  629. }
  630. .title {
  631. font-size: 0.3rem;
  632. }
  633. .content {
  634. top: 1rem;
  635. left: 2rem;
  636. right: 2rem;
  637. padding: 10px;
  638. > div {
  639. max-height: 3rem;
  640. font-size: 0.25rem;
  641. line-height: 1.5;
  642. }
  643. }
  644. }
  645. }
  646. // ipad 横屏
  647. @media only screen and (min-device-width: 768px) and (orientation: landscape) {
  648. .header {
  649. height: 0.8rem;
  650. .title {
  651. i {
  652. margin-bottom: 0;
  653. }
  654. }
  655. }
  656. }
  657. .app-share {
  658. position: fixed;
  659. left: 0;
  660. bottom: 0;
  661. width: 100%;
  662. background-color: #fff;
  663. color: var(--editor-main-color);
  664. text-shadow: none;
  665. border-radius: 0.146667rem 0.146667rem 0px 0px;
  666. z-index: 1000;
  667. i {
  668. // font-size: 2rem;
  669. font-size: 1rem;
  670. margin: 0.666667rem 0 0.106667rem;
  671. display: inline-block;
  672. }
  673. ul {
  674. // display: flex;
  675. // justify-content: space-around;
  676. overflow: hidden;
  677. div {
  678. text-align: center;
  679. // margin-top: -0.3rem;
  680. font-size: 0.34rem;
  681. }
  682. li {
  683. width: 33.3%;
  684. float: left;
  685. // padding-bottom: 0.5rem;
  686. overflow: hidden;
  687. text-align: center;
  688. // i{
  689. // font-size: 2rem;
  690. // }
  691. }
  692. &.flex {
  693. display: flex;
  694. li {
  695. float: none;
  696. }
  697. }
  698. }
  699. > div {
  700. height: 1.293333rem;
  701. font-size: 16px;
  702. text-align: center;
  703. // padding: 0.5rem;
  704. border-top: solid 1px #eeeeee;
  705. margin-top: 0.466667rem;
  706. line-height: 1.293333rem;
  707. }
  708. }
  709. </style>
  710. <style lang="scss">
  711. .animated.short {
  712. &.faster {
  713. animation-duration: 0.3s;
  714. }
  715. @keyframes fadeInUp {
  716. 0% {
  717. opacity: 0;
  718. transform: translate3d(0, 1rem, 0);
  719. }
  720. to {
  721. opacity: 1;
  722. transform: translateZ(0);
  723. }
  724. }
  725. @keyframes fadeOutDown {
  726. 0% {
  727. opacity: 1;
  728. }
  729. to {
  730. opacity: 0;
  731. transform: translate3d(0, 1rem, 0);
  732. }
  733. }
  734. }
  735. </style>