|
@@ -1,642 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="controls-left-buttons">
|
|
|
- <div class="play-control" v-if="tours.length > 0" :class="{ disabled: flying && !isPlay }">
|
|
|
- <div class="play-btn tour-btn" @click="playTour">
|
|
|
- <div class="animation-icon" :class="{ action: isPlay }" :style="`background-image: url(${resource.getStaticURL('static/images/walk_animation.png')});`">
|
|
|
- <p class="tip">{{ isPlay ? $t('common.pauseTour') : $t('common.playTour') }}</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="tour-btn bor">
|
|
|
- <ui-icon type="pull-down" @click="openTours" :class="{ active: showTours }"></ui-icon>
|
|
|
- </div>
|
|
|
- <!-- <teleport :to="editorMain"> -->
|
|
|
- <div class="tour-list" :class="{ ban: flying || isSelect }" :style="`height:${showTours ? '120px' : '0px'};`">
|
|
|
- <div class="part-content" ref="tourScroll">
|
|
|
- <!-- 多个片段 -->
|
|
|
- <div class="part-list" v-if="tours.length > 1">
|
|
|
- <div
|
|
|
- @click="changeFrame(1, index)"
|
|
|
- class="part-item"
|
|
|
- :name="index"
|
|
|
- v-for="(i, index) in tours"
|
|
|
- :style="`background-image:url(${i.frameId && i.list[i.frameId] ? common.changeUrl(i.list[i.frameId].enter.cover) : common.changeUrl(i.list[0].enter.cover)});`"
|
|
|
- >
|
|
|
- <div class="part-title">{{ i.name }}</div>
|
|
|
- <div v-if="partId == index && progressNum > 0" class="precent" :style="`width:${progressNum}%;`"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <!-- 只有一个片段 -->
|
|
|
- <div class="part-list frame-list" v-else>
|
|
|
- <div @click="changeFrame(2, index)" class="part-item" v-for="(i, index) in tours[0].list" :name="index" :style="`background-image:url(${common.changeUrl(i.enter.cover)});`">
|
|
|
- <div class="part-title"></div>
|
|
|
- <div v-if="frameId == index && progressNum > 0" class="precent" :style="`width:${progressNum}%;`"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <!-- </teleport> -->
|
|
|
- </div>
|
|
|
- <div class="buttons mode" :class="{ disabled: isPlay || flying }">
|
|
|
- <div v-if="controls.showPanorama" :class="{ active: viewmode == 'panorama' }" @click="onModeChange('panorama')">
|
|
|
- <ui-icon :tip="$t('mode.panorama')" tipV="top" :type="viewmode == 'panorama' ? 'show_roaming_s' : 'show_roaming_n'"></ui-icon>
|
|
|
- </div>
|
|
|
- <div v-if="controls.showFloorplan" :class="{ active: viewmode == 'floorplan' }" @click="onModeChange('floorplan')">
|
|
|
- <ui-icon :tip="$t('mode.floorplan')" tipV="top" :type="viewmode == 'floorplan' ? 'show_plane_s' : 'show_plane_n'"></ui-icon>
|
|
|
- </div>
|
|
|
- <div v-if="controls.showDollhouse" :class="{ active: viewmode == 'dollhouse' }" @click="onModeChange('dollhouse')">
|
|
|
- <ui-icon :tip="$t('mode.dollhouse')" tipV="top" :type="viewmode == 'dollhouse' ? 'show_3d_s' : 'show_3d_n'"></ui-icon>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 导览字幕 -->
|
|
|
- <!-- <teleport to=".kankan-app" > -->
|
|
|
- <div class="tours-captions" :class="{ active: showTours }" v-if="tours.length > 0 && isPlay">
|
|
|
- <div class="captions-title" v-if="tours[partId] && tours[partId].title">{{ tours[partId].title || '' }}</div>
|
|
|
- <div class="captions-desc" v-if="tours[partId] && tours[partId].description">{{ tours[partId].description || '' }}</div>
|
|
|
- </div>
|
|
|
- <!-- </teleport> -->
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-<script setup>
|
|
|
-import { computed, defineProps, onMounted, ref, nextTick, watch } from 'vue'
|
|
|
-import { Scrollbar, Dialog } from '@kankan/components'
|
|
|
-import { useApp, getApp } from '@/app'
|
|
|
-import { useStore } from 'vuex'
|
|
|
-import browser from '@/utils/browser'
|
|
|
-import common from '@/utils/common'
|
|
|
-import resource from '@/utils/resource'
|
|
|
-import { useMusicPlayer } from '@/utils/sound'
|
|
|
-import { Track, startTrack, endTrack } from '@/utils/track.js'
|
|
|
-// import test from './test.vue'
|
|
|
-const musicPlayer = useMusicPlayer()
|
|
|
-const props = defineProps({
|
|
|
- isEdit: Boolean,
|
|
|
-})
|
|
|
-let timer = null
|
|
|
-const isSelect = ref(false)
|
|
|
-const store = useStore()
|
|
|
-const tourScroll = ref(null)
|
|
|
-const viewmode = computed(() => store.getters.mode)
|
|
|
-const flying = computed(() => store.getters['flying'])
|
|
|
-const controls = computed(() => store.getters['scene/metadata'].controls || {})
|
|
|
-const showTours = computed(() => store.getters['tour/showTours'])
|
|
|
-const sceneUI = computed(() => store.getters.sceneUI)
|
|
|
-const partId = computed(() => {
|
|
|
- let id = store.getters['tour/partId']
|
|
|
- if (isPlay.value) {
|
|
|
- slideScroll()
|
|
|
- }
|
|
|
- return id
|
|
|
-})
|
|
|
-
|
|
|
-const frameId = computed(() => {
|
|
|
- let id = store.getters['tour/frameId']
|
|
|
- if (isPlay.value) {
|
|
|
- slideScroll()
|
|
|
- }
|
|
|
- return id
|
|
|
-})
|
|
|
-const progressNum = ref(0)
|
|
|
-const isPlay = computed(() => {
|
|
|
- let status = store.getters['tour/isPlay']
|
|
|
- let map = document.querySelector('.kankan-app div[xui_min_map]')
|
|
|
- if (map) {
|
|
|
- if (status) {
|
|
|
- map.classList.add('disabled')
|
|
|
- } else {
|
|
|
- map.classList.remove('disabled')
|
|
|
- }
|
|
|
- }
|
|
|
- return status
|
|
|
-})
|
|
|
-const isInit = ref(false)
|
|
|
-const tours = computed(() => {
|
|
|
- let tours = store.getters['tour/tours']
|
|
|
- if (tours.length > 0) {
|
|
|
- if (tourScroll.value && !isInit.value) {
|
|
|
- isInit.value = true
|
|
|
- new Scrollbar(tourScroll.value, { onlyHorizontal: true })
|
|
|
- }
|
|
|
- }
|
|
|
- return tours
|
|
|
-})
|
|
|
-
|
|
|
-watch(
|
|
|
- () => sceneUI.value,
|
|
|
- (val, old) => {
|
|
|
- if (showTours.value) {
|
|
|
- if (val) {
|
|
|
- store.commit('setControlsBottom', '120px')
|
|
|
- } else {
|
|
|
- store.commit('setControlsBottom', '0')
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-)
|
|
|
-
|
|
|
-const onModeChange = name => {
|
|
|
- store.commit('setMode', name)
|
|
|
- Track('view-button', {
|
|
|
- eventType: 'click',
|
|
|
- click: name,
|
|
|
- })
|
|
|
-}
|
|
|
-const playTour = async () => {
|
|
|
- let player = await getApp().TourManager.player
|
|
|
- if (isPlay.value) {
|
|
|
- store.commit('tour/setData', { isPlay: true })
|
|
|
- player.pause()
|
|
|
- } else {
|
|
|
- store.commit('tour/setData', { isPlay: true })
|
|
|
- player.play(partId.value, frameId.value)
|
|
|
- }
|
|
|
- store.commit('tag/setData', { isFixed: false, isClick: false, flyClose: false })
|
|
|
- store.commit('tag/closeTag')
|
|
|
-
|
|
|
- //自动打开导览
|
|
|
- if (isPlay.value) {
|
|
|
- store.commit('tour/setData', { showTours: true })
|
|
|
- let bot = '0px'
|
|
|
- if (showTours.value) {
|
|
|
- bot = '120px'
|
|
|
- } else {
|
|
|
- bot = '0px'
|
|
|
- }
|
|
|
- store.commit('setControlsBottom', bot)
|
|
|
- nextTick(() => {
|
|
|
- if (isPlay.value) {
|
|
|
- slideScroll()
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const hanlderTourPartPlay = time => {
|
|
|
- if (!timer) {
|
|
|
- timer = KanKan.Animate.transitions.start(progress => {
|
|
|
- progressNum.value = progress * 100
|
|
|
- }, time)
|
|
|
- }
|
|
|
-}
|
|
|
-const cancelTimer = () => {
|
|
|
- if (timer) {
|
|
|
- KanKan.Animate.transitions.cancel(timer)
|
|
|
- timer = null
|
|
|
- }
|
|
|
-}
|
|
|
-const slideScroll = () => {
|
|
|
- nextTick(() => {
|
|
|
- let t = setTimeout(() => {
|
|
|
- clearTimeout(t)
|
|
|
- let id = tours.value.length > 1 ? partId.value : frameId.value
|
|
|
- let item = document.querySelector(`.part-item[name="${id}"]`)
|
|
|
- item.scrollIntoView({ block: 'nearest', behavior: 'smooth', inline: 'center' })
|
|
|
- }, 100)
|
|
|
- })
|
|
|
-}
|
|
|
-let tour_finish = false
|
|
|
-const hanlderTour = async () => {
|
|
|
- let player = await getApp().TourManager.player
|
|
|
- player.on('play', data => {
|
|
|
- tour_finish = false
|
|
|
- musicPlayer.pause(true)
|
|
|
- Track('view-tour', {
|
|
|
- eventType: 'click',
|
|
|
- click: 'play',
|
|
|
- })
|
|
|
- })
|
|
|
- player.on('pause', tours => {
|
|
|
- console.log('pause')
|
|
|
- musicPlayer.resume()
|
|
|
- currProgress = 0
|
|
|
- currFrameProgress = 0
|
|
|
- progressNum.value = 0
|
|
|
- cancelTimer()
|
|
|
- store.commit('tour/setData', { isPlay: false })
|
|
|
- })
|
|
|
- player.on('end', () => {
|
|
|
- tour_finish = true
|
|
|
- musicPlayer.resume()
|
|
|
- currProgress = 0
|
|
|
- currFrameProgress = 0
|
|
|
- progressNum.value = 100
|
|
|
- slideScroll()
|
|
|
- store.commit('tour/setData', { isPlay: false })
|
|
|
- cancelTimer()
|
|
|
-
|
|
|
- // 循环播放导览
|
|
|
- if (browser.hasURLParam('tour_loop')) {
|
|
|
- setTimeout(() => {
|
|
|
- playTour()
|
|
|
- }, 1000)
|
|
|
- }
|
|
|
- //当最后一个有热点时候,需要展开
|
|
|
- if (tours.value[partId.value].list[frameId.value].tagId) {
|
|
|
- getApp().TagManager.open(tours.value[partId.value].list[frameId.value].tagId)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- let currPartId = null
|
|
|
- let currFrameId = null
|
|
|
- let currProgress = 0
|
|
|
- let FrameLength = 0
|
|
|
- let currFrameProgress = 0
|
|
|
-
|
|
|
- player.on('progress', data => {
|
|
|
- if (tour_finish) {
|
|
|
- return
|
|
|
- }
|
|
|
- if (currPartId != data.partId || currFrameId != data.frameId) {
|
|
|
- if (!tours.value[data.partId].list[data.frameId].tagId) {
|
|
|
- store.commit('tag/closeTag')
|
|
|
- }
|
|
|
- }
|
|
|
- if (tours.value.length == 1) {
|
|
|
- progressNum.value = data.progress * 100
|
|
|
- currPartId = data.partId
|
|
|
- currFrameId = data.frameId
|
|
|
- } else {
|
|
|
- // let time = getPartTime(data.partId)
|
|
|
-
|
|
|
- // hanlderTourPartPlay(time)
|
|
|
-
|
|
|
- if (currPartId != data.partId) {
|
|
|
- currProgress = 0
|
|
|
- currFrameProgress = 0
|
|
|
- progressNum.value = 0
|
|
|
- currPartId = data.partId
|
|
|
- FrameLength = tours.value[data.partId].list.length
|
|
|
- } else {
|
|
|
- FrameLength = tours.value[data.partId].list.length
|
|
|
-
|
|
|
- if (currFrameId != data.frameId) {
|
|
|
- currFrameId = data.frameId
|
|
|
- currFrameProgress = currProgress
|
|
|
- } else {
|
|
|
- currProgress = (data.progress / FrameLength) * 100 + currFrameProgress
|
|
|
- }
|
|
|
- if (currProgress >= 100) {
|
|
|
- currProgress = 100
|
|
|
- }
|
|
|
-
|
|
|
- progressNum.value = currProgress
|
|
|
- }
|
|
|
- }
|
|
|
- store.commit('tour/setData', { partId: data.partId, frameId: data.frameId })
|
|
|
- })
|
|
|
-
|
|
|
- // 导览自动播放
|
|
|
- getApp().TourManager.on('loaded', () => {
|
|
|
- if (browser.hasURLParam('autoplay')) {
|
|
|
- setTimeout(() => {
|
|
|
- if (tours.value.length) {
|
|
|
- let hasMusic = false
|
|
|
- for (let i = 0; i < tours.value.length; i++) {
|
|
|
- if (tours.value[i].music) {
|
|
|
- hasMusic = true
|
|
|
- continue
|
|
|
- }
|
|
|
- }
|
|
|
- if (!hasMusic) {
|
|
|
- //当所有片段没有背景音乐时,才能自动播放
|
|
|
- playTour()
|
|
|
- }
|
|
|
- }
|
|
|
- }, 500)
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-const getPartTime = partId => {
|
|
|
- cancelTimer()
|
|
|
- let time = 0
|
|
|
- for (let i = 0; i < tours.value[partId].list.length; i++) {
|
|
|
- if (!tours.value[partId].list[i]._end) {
|
|
|
- time += tours.value[partId].list[i].time - 0
|
|
|
- if (!tours.value[partId].list[i]._notrans) {
|
|
|
- time += 1000
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return time
|
|
|
-}
|
|
|
-
|
|
|
-const openTours = () => {
|
|
|
- // showTours.value = !showTours.value
|
|
|
- store.commit('tour/setData', { showTours: !showTours.value })
|
|
|
- let bot = '0px'
|
|
|
- if (showTours.value) {
|
|
|
- bot = '120px'
|
|
|
- } else {
|
|
|
- bot = '0px'
|
|
|
- }
|
|
|
- store.commit('setControlsBottom', bot)
|
|
|
- nextTick(() => {
|
|
|
- if (isPlay.value) {
|
|
|
- slideScroll()
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-const changeFrame = async (type, id) => {
|
|
|
- store.commit('tag/closeTag')
|
|
|
- progressNum.value = 0
|
|
|
- let player = await getApp().TourManager.player
|
|
|
- if (type == 1) {
|
|
|
- Track('view-tour', {
|
|
|
- eventType: 'click',
|
|
|
- click: 'part',
|
|
|
- })
|
|
|
- store.commit('tour/setData', {
|
|
|
- frameId: 0,
|
|
|
- partId: id,
|
|
|
- })
|
|
|
- progressNum.value = 0
|
|
|
-
|
|
|
- player.selectPart(id).then(() => {
|
|
|
- if (!isPlay.value) {
|
|
|
- return
|
|
|
- }
|
|
|
- store.commit('tour/setData', {
|
|
|
- isPlay: true,
|
|
|
- })
|
|
|
- player.play(id, frameId.value)
|
|
|
- })
|
|
|
- } else {
|
|
|
- Track('view-tour', {
|
|
|
- eventType: 'click',
|
|
|
- click: 'frame',
|
|
|
- })
|
|
|
-
|
|
|
- store.commit('tour/setData', {
|
|
|
- frameId: id,
|
|
|
- })
|
|
|
- progressNum.value = 0
|
|
|
- player.selectFrame(id).then(() => {
|
|
|
- if (!isPlay.value) {
|
|
|
- return
|
|
|
- }
|
|
|
- store.commit('tour/setData', {
|
|
|
- isPlay: true,
|
|
|
- })
|
|
|
- player.play(0, id)
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- slideScroll()
|
|
|
-}
|
|
|
-const onClickHandler = async () => {
|
|
|
- if (isPlay.value) {
|
|
|
- let player = await getApp().TourManager.player
|
|
|
- player.pause()
|
|
|
- musicPlayer.resume()
|
|
|
- }
|
|
|
-}
|
|
|
-onMounted(() => {
|
|
|
- useApp().then(app => {
|
|
|
- hanlderTour()
|
|
|
- })
|
|
|
-
|
|
|
- nextTick(() => {
|
|
|
- let player = document.querySelector('.player[name="main"]')
|
|
|
- player.addEventListener('pointerdown', onClickHandler)
|
|
|
- })
|
|
|
-})
|
|
|
-</script>
|
|
|
-
|
|
|
-<style lang="scss" scoped>
|
|
|
-.tours-captions {
|
|
|
- position: absolute;
|
|
|
- bottom: 64px;
|
|
|
- left: 20px;
|
|
|
- width: 480px;
|
|
|
- word-break: break-all;
|
|
|
- text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);
|
|
|
- text-align: justify;
|
|
|
- color: #fff;
|
|
|
- pointer-events: none;
|
|
|
- z-index: 1;
|
|
|
- transition: all 0.3s;
|
|
|
- &.active {
|
|
|
- // bottom: 184px;
|
|
|
- }
|
|
|
- .captions-title {
|
|
|
- font-size: 28px;
|
|
|
- margin-bottom: 10px;
|
|
|
- font-weight: bold;
|
|
|
- }
|
|
|
- .captions-desc {
|
|
|
- font-size: 16px;
|
|
|
- line-height: 24px;
|
|
|
- }
|
|
|
-}
|
|
|
-.controls-left-buttons {
|
|
|
- // margin-left: 20px;
|
|
|
- // margin-bottom: 20px;
|
|
|
- display: flex;
|
|
|
- // justify-content: center;
|
|
|
- align-items: flex-end;
|
|
|
- padding: 0 0 20px 20px;
|
|
|
-}
|
|
|
-.buttons.tour {
|
|
|
- margin-right: 10px;
|
|
|
- > div {
|
|
|
- margin-left: 0px;
|
|
|
- margin-right: 0px;
|
|
|
- padding: 0 10px;
|
|
|
- &.show-list {
|
|
|
- border-left: solid 1px var(--editor-font-color);
|
|
|
- }
|
|
|
- .icon-pull-down {
|
|
|
- font-size: 12px;
|
|
|
- }
|
|
|
- span {
|
|
|
- right: -10px;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-.tour-list {
|
|
|
- width: 100%;
|
|
|
- position: fixed;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- flex: 1;
|
|
|
- // height: var(--editor-toolbar-height);
|
|
|
- height: 120px;
|
|
|
- background-color: var(--editor-menu-back);
|
|
|
- pointer-events: all;
|
|
|
- left: var(--editor-toolbox-left);
|
|
|
- z-index: 1;
|
|
|
- transition: all 0.3s ease;
|
|
|
- &::after {
|
|
|
- width: 100%;
|
|
|
- position: absolute;
|
|
|
- content: '';
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- border-bottom: solid 1px rgba(255, 255, 255, 0.16);
|
|
|
- border-top: solid 1px #000;
|
|
|
- }
|
|
|
- &.ban {
|
|
|
- pointer-events: none;
|
|
|
- }
|
|
|
- .part-content {
|
|
|
- display: flex;
|
|
|
- flex-direction: row;
|
|
|
- overflow: hidden;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- .part-list {
|
|
|
- width: 100%;
|
|
|
- height: 120px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: flex-start;
|
|
|
- padding: 0 10px;
|
|
|
- box-sizing: border-box;
|
|
|
- .part-item {
|
|
|
- width: 120px;
|
|
|
- height: 80px;
|
|
|
- position: relative;
|
|
|
- cursor: pointer;
|
|
|
- margin-right: 10px;
|
|
|
- background-repeat: no-repeat;
|
|
|
- background-size: 100%;
|
|
|
- background-position: center;
|
|
|
- &:last-of-type {
|
|
|
- margin-right: 0px;
|
|
|
- }
|
|
|
- &:hover {
|
|
|
- opacity: 0.6;
|
|
|
- }
|
|
|
- .precent {
|
|
|
- width: 0%;
|
|
|
- height: 3px;
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- background: var(--editor-main-color);
|
|
|
- // opacity: 0.4;
|
|
|
- z-index: 100;
|
|
|
- // transition: width 0.1s;
|
|
|
- }
|
|
|
- .part-title {
|
|
|
- width: 100%;
|
|
|
- height: 24px;
|
|
|
- background: linear-gradient(180deg, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0.5) 100%);
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- font-size: 14px;
|
|
|
- z-index: 10;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-.play-control {
|
|
|
- pointer-events: all;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- height: 34px;
|
|
|
- border-radius: 17px;
|
|
|
- // background-color: rgba(0, 0, 0, 0.3);
|
|
|
- min-width: 34px;
|
|
|
- border-radius: 17px;
|
|
|
- position: relative;
|
|
|
- z-index: 2;
|
|
|
- // margin-left: 10px;
|
|
|
-
|
|
|
- .tour-btn {
|
|
|
- width: 34px;
|
|
|
- height: 22px;
|
|
|
- cursor: pointer;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
-
|
|
|
- > .iconfont {
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
- &.play-btn {
|
|
|
- // border-right: 1px solid rgba(255, 255, 255, 0.2);
|
|
|
- // > .iconfont {
|
|
|
- // font-size: 20px;
|
|
|
- // transition: rotate 0.3s;
|
|
|
- // }
|
|
|
- position: relative;
|
|
|
- .animation-icon {
|
|
|
- width: 24px;
|
|
|
- height: 24px;
|
|
|
- // background: red;
|
|
|
- position: absolute;
|
|
|
- top: 50%;
|
|
|
- left: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- background-repeat: no-repeat;
|
|
|
- background-position: 0% 0%;
|
|
|
- background-size: auto 24px;
|
|
|
- &:hover {
|
|
|
- .tip {
|
|
|
- opacity: 0.8;
|
|
|
- }
|
|
|
- }
|
|
|
- .tip {
|
|
|
- color: white;
|
|
|
- position: absolute;
|
|
|
- transform-origin: top center;
|
|
|
- background: #000000;
|
|
|
- border-radius: 4px;
|
|
|
- opacity: 0;
|
|
|
- padding: 10px;
|
|
|
- margin: 10px;
|
|
|
- font-size: 12px;
|
|
|
- transition: opacity 0.3s ease;
|
|
|
- pointer-events: none;
|
|
|
- white-space: nowrap;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
- margin-left: 0;
|
|
|
- margin-right: 0;
|
|
|
- z-index: 10;
|
|
|
- bottom: 100%;
|
|
|
- }
|
|
|
-
|
|
|
- &.action {
|
|
|
- animation: humanAction 1s steps(25) infinite;
|
|
|
- }
|
|
|
- @keyframes humanAction {
|
|
|
- 0% {
|
|
|
- background-position: 0% 0%;
|
|
|
- }
|
|
|
- 100% {
|
|
|
- background-position: 100% 0%;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- &.bor {
|
|
|
- height: 16px;
|
|
|
- border-right: 1px solid;
|
|
|
- border-image: linear-gradient(to bottom, rgba(194, 194, 194, 0.3), rgba(255, 255, 255, 0.3)) 1;
|
|
|
-
|
|
|
- padding: 0 34px;
|
|
|
- cursor: default;
|
|
|
- > .iconfont {
|
|
|
- font-size: 18px;
|
|
|
- transform: rotate(180deg);
|
|
|
- cursor: pointer;
|
|
|
- &.active {
|
|
|
- transform: rotate(0deg);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|