123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- <template>
- <div
- class="tour-list 333"
- v-if="tours.length > 0"
- :class="{ ban: flying || isSelect, barshow: showTours }"
- >
- <teleport to=".kankan-app">
- <!-- 导览字幕 -->
- <div
- class="tours-captions"
- :class="{ active: showTours }"
- v-if="tours.length > 0 && isPlay && !tours[partId].list[frameId].tagId"
- >
- <!-- <div class="tours-captions" :class="{ active: showTours }" > -->
- <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 class="part-content" ref="tourScroll">
- <!-- 多个片段 -->
- <ul class="part-list" v-if="tours.length > 1">
- <li
- class="part-item"
- v-for="(item, index) in tours"
- :key="index"
- @click="changeFrame(1, index)"
- :class="{
- active: partId == index && progressNum > 0,
- loopspan: item.name.length > spanlength && partId == index,
- disabled: isPlay && partId != index,
- }"
- :name="index"
- >
- <span v-if="partId == index">{{ item.name }}</span>
- <span v-else>{{
- item.name.length > spanlength
- ? item.name.slice(0, spanlength)
- : item.name
- }}</span>
- <div v-if="partId == index && progressNum > 0" class="tourbar">
- <div :style="`width:${progressNum}%;`" class="tourline"></div>
- </div>
- </li>
- </ul>
- <!-- 只有一个片段 -->
- <ul class="part-list part-frame" v-else>
- <li
- class="part-item"
- v-for="(item, index) in tours[0].list"
- :key="index"
- @click="changeFrame(2, index)"
- :style="`background-image:url(${common.changeUrl(
- item.enter.cover
- )});`"
- :class="{
- active: frameId == index && progressNum > 0,
- activeborder: frameId == index && progressNum <= 0,
- disabled: isPlay && frameId != index,
- }"
- :name="index"
- >
- <div v-if="frameId == index && progressNum > 0" class="tourbar">
- <div :style="`width:${progressNum}%;`" class="tourline"></div>
- </div>
- </li>
- </ul>
- </div>
- </div>
- </template>
- <script setup>
- import { computed, inject, onMounted, watch, ref, nextTick } from "vue";
- import { Scrollbar, Dialog } from "@/global_components";
- import { useApp, getApp } from "@/app";
- import { useStore } from "vuex";
- import common from "@/utils/common";
- import { useMusicPlayer } from "@/utils/sound";
- const musicPlayer = useMusicPlayer();
- const spanlength = ref(5);
- const triggerTour = inject("triggerTour");
- const isOpenTours = inject("isOpenTours");
- let timer = null;
- const isSelect = ref(false);
- const store = useStore();
- const tourScroll = ref(null);
- const flying = computed(() => store.getters["flying"]);
- const controls = computed(() => store.getters["scene/metadata"].controls || {});
- const showTours = computed(() => store.getters["tour/showTours"]);
- 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;
- });
- const onModeChange = (name) => {
- store.commit("setMode", 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);
- }
- };
- 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: "center",
- behavior: "smooth",
- inline: "center",
- });
- }, 100);
- });
- };
- const hanlderTour = async () => {
- let player = await getApp().TourManager.player;
- player.on("play", (data) => {
- // musicPlayer.pause(true)
- window.parent.postMessage(
- {
- source: "qjkankan",
- event: "toggleBgmStatus",
- params: {
- status: false,
- },
- },
- "*"
- );
- });
- player.on("pause", (tours) => {
- console.log("pause", player);
- // musicPlayer.resume()
- window.parent.postMessage(
- {
- source: "qjkankan",
- event: "toggleBgmStatus",
- params: {
- status: true,
- },
- },
- "*"
- );
- progressNum.value = 0;
- cancelTimer();
- store.commit("tour/setData", { isPlay: false });
- });
- player.on("end", (tours) => {
- // musicPlayer.resume()
- window.parent.postMessage(
- {
- source: "qjkankan",
- event: "toggleBgmStatus",
- params: {
- status: true,
- },
- },
- "*"
- );
- progressNum.value = 100;
- slideScroll();
- store.commit("tour/setData", { isPlay: false });
- cancelTimer();
- });
- let currPartId = null;
- let currProgress = 0;
- let currFrames = 0;
- player.on("progress", (data) => {
- if (tours.value.length == 1) {
- progressNum.value = data.progress * 100;
- } else {
- if (currPartId != data.partId) {
- currPartId = data.partId;
- currFrames = tours.value[data.partId].list.length;
- currProgress = 0;
- } else {
- currProgress += data.progress / currFrames;
- if (currProgress >= 100) {
- currProgress = 100;
- }
- progressNum.value = currProgress;
- }
- }
- store.commit("tour/setData", {
- partId: data.partId,
- frameId: data.frameId,
- isPlay: true,
- });
- });
- };
- 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 });
- nextTick(() => {
- if (isPlay.value) {
- slideScroll();
- }
- });
- };
- const changeFrame = async (type, id) => {
- progressNum.value = 0;
- // recorder.selectFrame(id)
- let player = await getApp().TourManager.player;
- // player.selectFrame(id)
- isSelect.value = true;
- if (type == 1) {
- player.selectPart(id);
- console.log(tours.value[id].frameId);
- let f_id = 0;
- if (tours.value[id].frameId) {
- f_id = tours.value[id].frameId;
- }
- player.selectFrame(f_id).then(() => {
- isSelect.value = false;
- });
- store.commit("tour/setData", {
- frameId: f_id,
- partId: id,
- });
- } else {
- player.selectFrame(id).then(() => {
- isSelect.value = false;
- });
- store.commit("tour/setData", {
- frameId: id,
- });
- }
- slideScroll();
- };
- const onClickHandler = async () => {
- if (isPlay.value) {
- let player = await getApp().TourManager.player;
- player.pause();
- // musicPlayer.resume()
- window.parent.postMessage(
- {
- source: "qjkankan",
- event: "toggleBgmStatus",
- params: {
- status: true,
- },
- },
- "*"
- );
- }
- };
- watch(triggerTour, () => {
- playTour();
- });
- watch(isOpenTours, () => {
- openTours();
- });
- watch(isPlay, () => {
- window.parent.postMessage(
- {
- source: "qjkankan",
- event: "isPlayTours",
- params: {
- isPlay: isPlay.value,
- },
- },
- "*"
- );
- });
- onMounted(() => {
- useApp().then(async (sdk) => {
- hanlderTour();
- });
- nextTick(() => {
- let player = document.querySelector('.player[name="main"]');
- player.addEventListener("click", onClickHandler);
- });
- });
- </script>
- <style lang="scss" scoped>
- $width: 1150px;
- .controls-left-buttons {
- margin-left: 20px;
- margin-bottom: 20px;
- display: flex;
- }
- .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 {
- position: fixed;
- bottom: 68px;
- left: 50%;
- transform: translateX(-50%);
- text-align: center;
- max-width: $width;
- overflow: hidden;
- max-height: 0;
- transition: 0.3s all ease;
- z-index: 9;
- &.ban {
- pointer-events: none;
- }
- .part-content {
- display: flex;
- flex-direction: row;
- overflow: hidden;
- padding: 10px 30px;
- background: linear-gradient(
- 268deg,
- rgba(0, 0, 0, 0) 0%,
- rgba(0, 0, 0, 0.5) 8%,
- rgba(0, 0, 0, 0.5) 92%,
- rgba(0, 0, 0, 0) 100%
- );
- .part-list {
- display: flex;
- > li {
- width: 90px;
- height: 40px;
- background: rgba(24, 24, 24, 0.5);
- line-height: 40px;
- margin: 0 6px;
- cursor: pointer;
- border-radius: 4px;
- > span,
- > div > span {
- cursor: pointer;
- display: inline-block;
- color: rgba(255, 255, 255, 0.8);
- }
- &.loopspan {
- > span,
- > div > span {
- animation: 5s wordsLoop linear infinite normal;
- }
- }
- &.active {
- position: relative;
- > span {
- color: var(--colors-primary-base);
- }
- .tourbar {
- position: absolute;
- width: 78px;
- left: 6px;
- right: 6px;
- bottom: 4px;
- height: 2px;
- border-radius: 2px;
- background: #000;
- overflow: hidden;
- .tourline {
- width: 50%;
- height: 100%;
- background: var(--colors-primary-base);
- }
- }
- }
- &:hover {
- opacity: 0.7;
- }
- }
- .activeborder {
- border: 1px solid var(--editor-main-color);
- }
- }
- .part-frame {
- > li {
- width: 120px;
- height: 80px;
- background-size: cover;
- &.active {
- .tourbar {
- position: absolute;
- width: 100%;
- left: 0;
- right: 0;
- bottom: 0;
- height: 4px;
- background: #000;
- overflow: hidden;
- opacity: 0.5;
- .tourline {
- width: 50%;
- height: 100%;
- background: var(--colors-primary-base);
- }
- }
- }
- }
- }
- }
- }
- .barshow {
- max-height: 102px;
- }
- @keyframes wordsLoop {
- 0% {
- transform: translateX(100%);
- -webkit-transform: translateX(100%);
- }
- 100% {
- transform: translateX(-180%);
- -webkit-transform: translateX(-180%);
- }
- }
- </style>
- <style lang="scss">
- .tours-captions {
- position: absolute;
- bottom: 64px;
- left: 20px;
- width: 480px;
- word-break: break-all;
- text-shadow: 0 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: 5rem;
- }
- .captions-title {
- font-size: 28px;
- margin-bottom: 10px;
- font-weight: 700;
- }
- .captions-desc {
- font-size: 16px;
- line-height: 24px;
- }
- }
- </style>
|