123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- <template>
- <div class="video">
- <div class="overflow">
- <ui-icon
- ctrl
- :type="isScenePlayIng ? 'pausecircle-fill' : 'playon_fill'"
- :disabled="!paths.length"
- @click="play"
- />
- <ui-button
- type="primary"
- @click="addPath"
- width="200px"
- :class="{ disabled: isScenePlayIng }"
- >
- 添加视角
- </ui-button>
- </div>
- <div class="info" v-if="paths.length">
- <div class="meta">
- <div class="length">
- <span>视频时长</span>
- </div>
- <div
- class="fun-ctrl clear"
- @click="deleteAll"
- :class="{ disabled: isScenePlayIng }"
- >
- <ui-icon type="del" />
- <span>清空画面</span>
- </div>
- </div>
- <div class="photo-list" ref="listVm">
- <div
- v-for="(path, i) in paths"
- class="photo"
- :key="path.id"
- :class="{ active: current === path, disabled: isScenePlayIng }"
- @click="changeCurrent(path)"
- >
- <ui-icon
- type="del"
- ctrl
- @click.stop="deletePath(path)"
- :class="{ disabled: isScenePlayIng }"
- />
- <img :src="path.cover" />
- </div>
- </div>
- </div>
- <p class="un-video" v-else>暂无导览</p>
- </div>
- </template>
- <script setup lang="ts">
- import { loadPack, togetherCallback } from '@/utils'
- import { sdk, playSceneGuide, pauseSceneGuide, isScenePlayIng } from '@/sdk'
- import { createGuidePath, TemploraryID, useAutoSetMode, guides, enterOld } from '@/store'
- import { Dialog } from 'bill/index'
- import { useViewStack } from '@/hook'
- import { nextTick, ref, toRaw, watchEffect } from 'vue'
- import { showRightPanoStack, showLeftCtrlPanoStack, showLeftPanoStack, showRightCtrlPanoStack } from '@/env'
- import type { Guide, GuidePaths, GuidePath } from '@/store'
- type LocalPath = GuidePath & { blob?: Blob }
- type LocalPaths = LocalPath[]
- const props = defineProps< { data: Guide }>()
- const paths = ref<LocalPaths>([...props.data.paths])
- const current = ref<LocalPath>(paths.value[0])
- useViewStack(() =>
- togetherCallback([
- showRightPanoStack.push(ref(false)),
- showLeftCtrlPanoStack.push(ref(false)),
- showLeftPanoStack.push(ref(false)),
- showRightCtrlPanoStack.push(ref(false)),
- ])
- );
- useAutoSetMode(paths, {
- save() {
- props.data.paths = paths.value
- if (props.data.id === TemploraryID) {
- guides.value.push(props.data)
- }
- }
- })
- setTimeout(() => {
- paths.value = [{
- id: '123a',
- position: {x: 1, y: 1, z: 1},
- target: {x: 1, y: 1, z: 1},
- cover: 'https://gw.alicdn.com/tps/TB1W_X6OXXXXXcZXVXXXXXXXXXX-400-400.png',
- speed: 1,
- time: 1
- }]
- }, 1000)
- const addPath = () => {
- loadPack(async () => {
- const dataURL = await sdk.screenshot(260, 160)
- const res = await fetch(dataURL)
- const blob = await res.blob()
- const pose = sdk.getPose()
- const index = paths.value.indexOf(current.value) + 1
- const path: LocalPath = Object.assign(
- { blob },
- createGuidePath({ ...pose, cover: dataURL })
- )
- paths.value.splice(index, 0, path)
- current.value = path
- })
- }
- const deletePath = async (path: GuidePath, fore: boolean = false) => {
- if (fore || (await Dialog.confirm('确定要删除此画面吗?'))) {
- const index = paths.value.indexOf(path)
- if (~index) {
- paths.value.splice(index, 1)
- }
- if (path === current.value) {
- current.value = paths.value[index + (index === 0 ? 0 : -1)]
- }
- }
- }
- const deleteAll = async () => {
- if (await Dialog.confirm('确定要清空画面吗?')) {
- while (paths.value.length) {
- deletePath(paths.value[0], true)
- }
- current.value = paths.value[0]
- }
- }
- const changeCurrent = (path: GuidePath) => {
- sdk.comeTo({ dur: 300, ...path })
- current.value = path
- }
- const play = () => {
- if (isScenePlayIng.value) {
- pauseSceneGuide()
- } else {
- playSceneGuide(sdk, toRaw(paths.value), (index) => current.value = paths.value[index])
- }
- }
- const listVm = ref<HTMLDivElement>()
- watchEffect(async () => {
- const index = paths.value.indexOf(current.value)
- if (~index && listVm.value) {
- await nextTick()
- const scrollWidth = listVm.value.scrollWidth / paths.value.length
- const centerWidth = listVm.value.offsetWidth / 2
- const offsetLeft = scrollWidth * index - centerWidth
- listVm.value.scroll({
- left: offsetLeft,
- top: 0,
- })
- }
- })
- </script>
- <style lang="scss" scoped>
- .video {
- position: relative;
- .overflow {
- position: absolute;
- left: 50%;
- bottom: 100%;
- transform: translateX(-50%);
- margin-bottom: 20px;
- display: flex;
- align-items: center;
- .icon {
- margin-right: 20px;
- color: #fff;
- font-size: 50px;
- }
- }
- .meta {
- font-size: 12px;
- border-bottom: 1px solid rgba(255,255,255,.6);
- padding: 10px 20px;
- display: flex;
- justify-content: space-between;
-
- .length span {
- margin-right: 10px;
- }
- .clear {
- display: flex;
- align-items: center;
- .icon {
- font-size: 1.4em;
- margin-right: 5px;
- }
- }
- }
- .photo-list {
- padding: 10px 20px 20px;
- overflow-x: auto;
- display: flex;
- .photo {
- cursor: pointer;
- flex: none;
- position: relative;
- &.active {
- outline: 2px solid var(--colors-primary-base);
- }
- .icon {
- position: absolute;
- right: 10px;
- top: 10px;
- width: 24px;
- font-size: 12px;
- height: 24px;
- background-color: rgba(0,0,0,0.6);
- color: rgba(255,255,255,.6);
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- border-radius: 50%;
- }
- &:not(:last-child) {
- margin-right: 10px;
- }
- img {
- width: 230px;
- height: 160px;
- display: block;
- }
- }
- }
- }
- .un-video {
- height: 100px;
- line-height: 100px;
- text-align: center;
- color: rgba(255,255,255,0.6);
- font-size: 1.2em;
- }
- </style>
|