tours.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. <template>
  2. <div class="tour-list" v-if="tours.length > 0" :class="{ ban: flying || isSelect,barshow: showTours }">
  3. <div class="part-content" ref="tourScroll">
  4. <!-- 多个片段 -->
  5. <ul class="part-list" v-if="tours.length>1">
  6. <li class="part-item" v-for="(item, index) in tours" :key="index"
  7. @click="changeFrame(1, index)"
  8. :class="{
  9. active: partId == index && progressNum > 0,
  10. loopspan: item.name.length > spanlength && partId == index,
  11. disabled: isPlay && partId != index }"
  12. :name="index">
  13. <span v-if="partId == index">{{item.name}}</span>
  14. <span v-else>{{ item.name.length > spanlength ? item.name.slice(0, spanlength) : item.name }}</span>
  15. <div v-if="partId == index && progressNum > 0" class="tourbar">
  16. <div :style="`width:${progressNum}%;`" class="tourline"></div>
  17. </div>
  18. </li>
  19. </ul>
  20. <!-- 只有一个片段 -->
  21. <ul class="part-list" v-else>
  22. <li class="part-item" v-for="(item, index) in tours[0].list" :key="index"
  23. @click="changeFrame(2, index)"
  24. :class="{
  25. active: frameId == index && progressNum > 0,
  26. disabled: isPlay && frameId != index }"
  27. :name="index">
  28. <span>片段</span>
  29. <div v-if="frameId == index && progressNum > 0" class="tourbar">
  30. <div :style="`width:${progressNum}%;`" class="tourline"></div>
  31. </div>
  32. </li>
  33. </ul>
  34. </div>
  35. </div>
  36. </template>
  37. <script setup>
  38. import { computed, inject, onMounted,watch, ref, nextTick } from 'vue'
  39. import { Scrollbar, Dialog } from '@/global_components'
  40. import { useApp, getApp } from '@/app'
  41. import { useStore } from 'vuex'
  42. import common from '@/utils/common'
  43. import { useMusicPlayer } from '@/utils/sound'
  44. const musicPlayer = useMusicPlayer()
  45. const spanlength = ref(5)
  46. const triggerTour = inject("triggerTour");
  47. const isOpenTours = inject("isOpenTours");
  48. let timer = null
  49. const isSelect = ref(false)
  50. const store = useStore()
  51. const tourScroll = ref(null)
  52. const flying = computed(() => store.getters['flying'])
  53. const controls = computed(() => store.getters['scene/metadata'].controls || {})
  54. const showTours = computed(() => store.getters['tour/showTours'])
  55. const partId = computed(() => {
  56. let id = store.getters['tour/partId']
  57. if (isPlay.value) {
  58. slideScroll()
  59. }
  60. return id
  61. })
  62. const frameId = computed(() => {
  63. let id = store.getters['tour/frameId']
  64. if (isPlay.value) {
  65. slideScroll()
  66. }
  67. return id
  68. })
  69. const progressNum = ref(0)
  70. const isPlay = computed(() => {
  71. let status = store.getters['tour/isPlay']
  72. let map = document.querySelector('.kankan-app div[xui_min_map]')
  73. if (map) {
  74. if (status) {
  75. map.classList.add('disabled')
  76. } else {
  77. map.classList.remove('disabled')
  78. }
  79. }
  80. return status
  81. })
  82. const isInit = ref(false)
  83. const tours = computed(() => {
  84. let tours = store.getters['tour/tours']
  85. if (tours.length > 0) {
  86. if (tourScroll.value && !isInit.value) {
  87. isInit.value = true
  88. new Scrollbar(tourScroll.value, { onlyHorizontal: true })
  89. }
  90. }
  91. return tours
  92. })
  93. const onModeChange = name => {
  94. store.commit('setMode', name)
  95. }
  96. const playTour = async () => {
  97. let player = await getApp().TourManager.player
  98. if (isPlay.value) {
  99. store.commit('tour/setData', { isPlay: true })
  100. player.pause()
  101. } else {
  102. store.commit('tour/setData', { isPlay: true })
  103. player.play(partId.value)
  104. }
  105. }
  106. const hanlderTourPartPlay = time => {
  107. if (!timer) {
  108. timer = KanKan.Animate.transitions.start(progress => {
  109. progressNum.value = progress * 100
  110. }, time)
  111. }
  112. }
  113. const cancelTimer = () => {
  114. if (timer) {
  115. KanKan.Animate.transitions.cancel(timer)
  116. timer = null
  117. }
  118. }
  119. const slideScroll = () => {
  120. nextTick(() => {
  121. let t = setTimeout(() => {
  122. clearTimeout(t)
  123. let id = tours.value.length > 1 ? partId.value : frameId.value
  124. let item = document.querySelector(`.part-item[name="${id}"]`)
  125. item.scrollIntoView({ block: 'center', behavior: 'smooth', inline: 'center' })
  126. }, 100)
  127. })
  128. }
  129. const hanlderTour = async () => {
  130. let player = await getApp().TourManager.player
  131. player.on('play', data => {
  132. musicPlayer.pause(true)
  133. })
  134. player.on('pause', tours => {
  135. console.log('pause', player)
  136. musicPlayer.resume()
  137. progressNum.value = 0
  138. cancelTimer()
  139. store.commit('tour/setData', { isPlay: false })
  140. })
  141. player.on('end', tours => {
  142. musicPlayer.resume()
  143. progressNum.value = 100
  144. slideScroll()
  145. store.commit('tour/setData', { isPlay: false })
  146. cancelTimer()
  147. })
  148. let currPartId = null
  149. let currProgress = 0
  150. let currFrames = 0
  151. player.on('progress', data => {
  152. if (tours.value.length == 1) {
  153. progressNum.value = data.progress * 100
  154. } else {
  155. if (currPartId != data.partId) {
  156. currPartId = data.partId
  157. currFrames = tours.value[data.partId].list.length
  158. currProgress = 0
  159. } else {
  160. currProgress += data.progress / currFrames
  161. if (currProgress >= 100) {
  162. currProgress = 100
  163. }
  164. progressNum.value = currProgress
  165. }
  166. }
  167. store.commit('tour/setData', { partId: data.partId, frameId: data.frameId, isPlay: true })
  168. })
  169. }
  170. const getPartTime = partId => {
  171. cancelTimer()
  172. let time = 0
  173. for (let i = 0; i < tours.value[partId].list.length; i++) {
  174. if (!tours.value[partId].list[i]._end) {
  175. time += tours.value[partId].list[i].time - 0
  176. if (!tours.value[partId].list[i]._notrans) {
  177. time += 1000
  178. }
  179. }
  180. }
  181. return time
  182. }
  183. const openTours = () => {
  184. // showTours.value = !showTours.value
  185. store.commit('tour/setData', { showTours: !showTours.value })
  186. nextTick(() => {
  187. if (isPlay.value) {
  188. slideScroll()
  189. }
  190. })
  191. }
  192. const changeFrame = async (type, id) => {
  193. progressNum.value = 0
  194. // recorder.selectFrame(id)
  195. let player = await getApp().TourManager.player
  196. // player.selectFrame(id)
  197. isSelect.value = true
  198. if (type == 1) {
  199. player.selectPart(id)
  200. console.log(tours.value[id].frameId)
  201. let f_id = 0
  202. if (tours.value[id].frameId) {
  203. f_id = tours.value[id].frameId
  204. }
  205. player.selectFrame(f_id).then(() => {
  206. isSelect.value = false
  207. })
  208. store.commit('tour/setData', {
  209. frameId: f_id,
  210. partId: id,
  211. })
  212. } else {
  213. player.selectFrame(id).then(() => {
  214. isSelect.value = false
  215. })
  216. store.commit('tour/setData', {
  217. frameId: id,
  218. })
  219. }
  220. slideScroll()
  221. }
  222. const onClickHandler = async () => {
  223. if (isPlay.value) {
  224. let player = await getApp().TourManager.player
  225. player.pause()
  226. musicPlayer.resume()
  227. }
  228. }
  229. watch(triggerTour,()=>{
  230. playTour()
  231. })
  232. watch(isOpenTours,()=>{
  233. openTours()
  234. })
  235. watch(isPlay,()=>{
  236. window.parent.postMessage(
  237. {
  238. source: "qjkankan",
  239. event: "isPlayTours",
  240. params: {
  241. isPlay:isPlay.value,
  242. },
  243. },
  244. "*"
  245. );
  246. })
  247. onMounted(() => {
  248. useApp().then(async sdk => {
  249. hanlderTour()
  250. })
  251. nextTick(() => {
  252. let player = document.querySelector('.player[name="main"]')
  253. player.addEventListener('click', onClickHandler)
  254. })
  255. })
  256. </script>
  257. <style lang="scss" scoped>
  258. $width: 1150px;
  259. .controls-left-buttons {
  260. margin-left: 20px;
  261. margin-bottom: 20px;
  262. display: flex;
  263. }
  264. .buttons.tour {
  265. margin-right: 10px;
  266. >div {
  267. margin-left: 0px;
  268. margin-right: 0px;
  269. padding: 0 10px;
  270. &.show-list {
  271. border-left: solid 1px var(--editor-font-color);
  272. }
  273. .icon-pull-down {
  274. font-size: 12px;
  275. }
  276. span {
  277. right: -10px;
  278. }
  279. }
  280. }
  281. .tour-list {
  282. position: fixed;
  283. bottom: 68px;
  284. left: 50%;
  285. transform: translateX(-50%);
  286. text-align: center;
  287. max-width: $width;
  288. overflow: hidden;
  289. max-height: 0;
  290. transition: .3s all ease;
  291. z-index: 9;
  292. &.ban {
  293. pointer-events: none;
  294. }
  295. .part-content {
  296. display: flex;
  297. flex-direction: row;
  298. overflow: hidden;
  299. padding: 10px 30px;
  300. min-width: 400px;
  301. 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%);
  302. .part-list {
  303. display: flex;
  304. >li {
  305. width: 90px;
  306. height: 40px;
  307. background: rgba(24, 24, 24, .5);
  308. line-height: 40px;
  309. margin: 0 6px;
  310. cursor: pointer;
  311. >span,
  312. >div>span {
  313. cursor: pointer;
  314. display: inline-block;
  315. color: rgba(255, 255, 255, 0.8);
  316. }
  317. &.loopspan {
  318. >span,
  319. >div>span {
  320. animation: 5s wordsLoop linear infinite normal;
  321. }
  322. }
  323. &.active {
  324. position: relative;
  325. .tourbar {
  326. position: absolute;
  327. width: 78px;
  328. left: 6px;
  329. right: 6px;
  330. bottom: 4px;
  331. height: 2px;
  332. border-radius: 2px;
  333. background: #000;
  334. overflow: hidden;
  335. .tourline {
  336. width: 50%;
  337. height: 100%;
  338. background: var(--colors-primary-base);
  339. }
  340. }
  341. }
  342. &:hover {
  343. opacity: 0.7;
  344. }
  345. }
  346. }
  347. }
  348. }
  349. .barshow {
  350. max-height: 62px;
  351. }
  352. @keyframes wordsLoop {
  353. 0% {
  354. transform: translateX(100%);
  355. -webkit-transform: translateX(100%);
  356. }
  357. 100% {
  358. transform: translateX(-100%);
  359. -webkit-transform: translateX(-100%);
  360. }
  361. }
  362. </style>