|
|
@@ -1,5 +1,26 @@
|
|
|
<template>
|
|
|
- <mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack" />
|
|
|
+ <div :class="['preview-page', { 'preview-page--switched': orientationSwitched }]">
|
|
|
+ <mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack" />
|
|
|
+ <button
|
|
|
+ class="orientation-toggle"
|
|
|
+ type="button"
|
|
|
+ aria-label="切换显示方向"
|
|
|
+ @click="orientationSwitched = !orientationSwitched">
|
|
|
+ <svg
|
|
|
+ class="orientation-toggle__icon"
|
|
|
+ aria-hidden="true"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ fill="none">
|
|
|
+ <path
|
|
|
+ d="M20 11a8 8 0 1 0-2.34 5.66M20 4v7h-7"
|
|
|
+ stroke="currentColor"
|
|
|
+ stroke-width="2"
|
|
|
+ stroke-linecap="round"
|
|
|
+ stroke-linejoin="round" />
|
|
|
+ </svg>
|
|
|
+ <span class="orientation-toggle__text">切换方向</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
import { WebtopoProjectApi, parseWebtopoDataModel } from '@/api/pms/maotu'
|
|
|
@@ -16,6 +37,7 @@ const MtPreviewRef = ref<InstanceType<typeof MtPreview>>()
|
|
|
const previewData = ref<IExportJson>()
|
|
|
const pollingTimer = ref<number>()
|
|
|
const polling = ref(false)
|
|
|
+const orientationSwitched = ref(false)
|
|
|
|
|
|
const getProjectId = () => {
|
|
|
const id = Number(route.params.id)
|
|
|
@@ -169,3 +191,87 @@ onUnmounted(() => {
|
|
|
stopDeviceBindPolling()
|
|
|
})
|
|
|
</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.preview-page {
|
|
|
+ position: relative;
|
|
|
+ width: 100vw;
|
|
|
+ width: 100dvw;
|
|
|
+ height: 100vh;
|
|
|
+ height: 100dvh;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.preview-page--switched {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100vh;
|
|
|
+ width: 100dvh;
|
|
|
+ height: 100vw;
|
|
|
+ height: 100dvw;
|
|
|
+ transform: rotate(90deg) translateY(-100%);
|
|
|
+ transform-origin: left top;
|
|
|
+}
|
|
|
+
|
|
|
+.orientation-toggle {
|
|
|
+ position: fixed;
|
|
|
+ top: max(12px, env(safe-area-inset-top));
|
|
|
+ right: max(12px, env(safe-area-inset-right));
|
|
|
+ z-index: 10;
|
|
|
+ display: inline-flex;
|
|
|
+ height: 36px;
|
|
|
+ padding: 0 14px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1;
|
|
|
+ color: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ background: rgb(0 0 0 / 65%);
|
|
|
+ border: 1px solid rgb(255 255 255 / 35%);
|
|
|
+ border-radius: 18px;
|
|
|
+ box-shadow: 0 2px 10px rgb(0 0 0 / 25%);
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ backdrop-filter: blur(6px);
|
|
|
+ -webkit-tap-highlight-color: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.orientation-toggle:active {
|
|
|
+ background: rgb(0 0 0 / 80%);
|
|
|
+}
|
|
|
+
|
|
|
+.orientation-toggle__icon {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ flex: 0 0 auto;
|
|
|
+}
|
|
|
+
|
|
|
+.orientation-toggle__text {
|
|
|
+ line-height: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 手机竖屏时模拟横屏,横屏状态和桌面端保持原方向 */
|
|
|
+/* stylelint-disable-next-line order/order -- 基础视口样式需要位于移动端覆盖样式之前 */
|
|
|
+@media screen and (width <= 767px) and (orientation: portrait) {
|
|
|
+ .preview-page {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100vh;
|
|
|
+ width: 100dvh;
|
|
|
+ height: 100vw;
|
|
|
+ height: 100dvw;
|
|
|
+ transform: rotate(90deg) translateY(-100%);
|
|
|
+ transform-origin: left top;
|
|
|
+ }
|
|
|
+
|
|
|
+ .preview-page.preview-page--switched {
|
|
|
+ position: relative;
|
|
|
+ width: 100vw;
|
|
|
+ width: 100dvw;
|
|
|
+ height: 100vh;
|
|
|
+ height: 100dvh;
|
|
|
+ transform: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|