|
@@ -1,4 +1,15 @@
|
|
|
-import { Button, Icon, Popup, Slider, Swipe, SwipeItem, Tab, Tabs } from 'vant'
|
|
|
+import {
|
|
|
+ Button,
|
|
|
+ closeToast,
|
|
|
+ Icon,
|
|
|
+ Popup,
|
|
|
+ showToast,
|
|
|
+ Slider,
|
|
|
+ Swipe,
|
|
|
+ SwipeItem,
|
|
|
+ Tab,
|
|
|
+ Tabs
|
|
|
+} from 'vant'
|
|
|
import {
|
|
|
defineComponent,
|
|
|
onMounted,
|
|
@@ -22,32 +33,40 @@ import MusicScore from './component/musicScore'
|
|
|
import iconMenu from './image/icon-menu.svg'
|
|
|
import iconDian from './image/icon-dian.svg'
|
|
|
import iconPoint from './image/icon-point.svg'
|
|
|
+import iconLoop from './image/icon-loop.svg'
|
|
|
+import iconLoopActive from './image/icon-loop-active.svg'
|
|
|
+import iconplay from './image/icon-play.svg'
|
|
|
+import iconpause from './image/icon-pause.svg'
|
|
|
import Points from './component/points'
|
|
|
+import { getSecondRPM } from '@/helpers/utils'
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'CoursewarePlay',
|
|
|
setup() {
|
|
|
- const handleInit = () => {
|
|
|
+ const handleInit = (type = 0) => {
|
|
|
postMessage({
|
|
|
api: 'setRequestedOrientation',
|
|
|
content: {
|
|
|
- orientation: 0
|
|
|
+ orientation: type
|
|
|
}
|
|
|
})
|
|
|
postMessage({
|
|
|
api: 'setBarStatus',
|
|
|
content: {
|
|
|
- status: 0
|
|
|
+ status: type
|
|
|
}
|
|
|
})
|
|
|
postMessage({
|
|
|
api: 'setStatusBarVisibility',
|
|
|
content: {
|
|
|
- isVisibility: 0
|
|
|
+ isVisibility: type
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
handleInit()
|
|
|
+ onUnmounted(() => {
|
|
|
+ handleInit(1)
|
|
|
+ })
|
|
|
|
|
|
const route = useRoute()
|
|
|
const data = reactive({
|
|
@@ -55,33 +74,52 @@ export default defineComponent({
|
|
|
active: '',
|
|
|
itemActive: '',
|
|
|
knowledgePointList: [] as any,
|
|
|
+ itemList: [] as any,
|
|
|
showHead: true,
|
|
|
players: [] as any
|
|
|
})
|
|
|
const activeData = reactive({
|
|
|
+ nowTime: 0,
|
|
|
model: true, // 遮罩
|
|
|
- currentTime: 10
|
|
|
+ videoBtns: true, // 视频
|
|
|
+ currentTime: 0,
|
|
|
+ duration: 0,
|
|
|
+ timer: null as any,
|
|
|
+ item: null as any
|
|
|
})
|
|
|
- const itemList = computed(() => {
|
|
|
+ const getItemList = () => {
|
|
|
const list: any = []
|
|
|
for (let i = 0; i < data.knowledgePointList.length; i++) {
|
|
|
const item = data.knowledgePointList[i]
|
|
|
for (let j = 0; j < item.materialList.length; j++) {
|
|
|
const material = item.materialList[j]
|
|
|
if (popupData.itemActive === '') {
|
|
|
- popupData.tabActive = material.knowledgePointId
|
|
|
popupData.tabName = item.name
|
|
|
+ popupData.tabActive = material.knowledgePointId
|
|
|
popupData.itemActive = material.id
|
|
|
popupData.itemName = material.name
|
|
|
+ popupData.activeIndex = 0
|
|
|
+ }
|
|
|
+ let videoItem = {}
|
|
|
+ if (material.type === 'VIDEO') {
|
|
|
+ videoItem = {
|
|
|
+ currentTime: 0,
|
|
|
+ duration: 0,
|
|
|
+ paused: true,
|
|
|
+ loop: false,
|
|
|
+ videoEle: null,
|
|
|
+ timer: null
|
|
|
+ }
|
|
|
}
|
|
|
list.push({
|
|
|
- ...material
|
|
|
+ ...material,
|
|
|
+ ...videoItem
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
- // console.log('🚀 ~ list', list)
|
|
|
+ console.log('🚀 ~ list', list)
|
|
|
return list
|
|
|
- })
|
|
|
+ }
|
|
|
const getDetail = async () => {
|
|
|
try {
|
|
|
const res: any = await request.get(
|
|
@@ -95,132 +133,77 @@ export default defineComponent({
|
|
|
n.index = 0
|
|
|
return n
|
|
|
})
|
|
|
+ data.itemList = getItemList()
|
|
|
}
|
|
|
} catch (error) {}
|
|
|
}
|
|
|
- const videoInit = () => {
|
|
|
- console.log(document.querySelectorAll('.player'))
|
|
|
- data.players = Plyr.setup('.player', {
|
|
|
- debug: false,
|
|
|
- ratio: '16:9',
|
|
|
- clickToPlay: true,
|
|
|
- controls: [
|
|
|
- 'play-large',
|
|
|
- 'play',
|
|
|
- 'progress',
|
|
|
- 'current-time',
|
|
|
- 'duration',
|
|
|
- 'mute',
|
|
|
- 'volume',
|
|
|
- 'restart'
|
|
|
- ]
|
|
|
- })
|
|
|
- data.players.forEach((p: Plyr) => {
|
|
|
- // console.log(p)
|
|
|
- p.on('play', () => {
|
|
|
- console.log('开始播放了')
|
|
|
- data.showHead = false
|
|
|
- })
|
|
|
- p.on('pause', () => {
|
|
|
- console.log('暂停了')
|
|
|
- data.showHead = true
|
|
|
- })
|
|
|
- p.on('controlsshown', () => {
|
|
|
- console.log('显示控件')
|
|
|
- data.showHead = true
|
|
|
- })
|
|
|
- p.on('controlshidden', () => {
|
|
|
- console.log('控件隐藏')
|
|
|
- data.showHead = false
|
|
|
- })
|
|
|
- })
|
|
|
- console.log('🚀 ~ player', data.players)
|
|
|
- }
|
|
|
- const testFile = ref('')
|
|
|
onMounted(() => {
|
|
|
- // const o = new ActiveXObject("wscript.shell")
|
|
|
getDetail()
|
|
|
- postMessage(
|
|
|
- {
|
|
|
- api: 'getCourseFilePath',
|
|
|
- content: {
|
|
|
- url: 'https://daya.ks3-cn-beijing.ksyuncs.com/01/1672976208474.jpg',
|
|
|
- materialId: '1610610237357969409',
|
|
|
- updateTime: '2023-01-04 20:12:58',
|
|
|
- type: 'VIDEO' // SONG VIDEO IMAGE
|
|
|
- }
|
|
|
- },
|
|
|
- (res) => {
|
|
|
- if (res?.content) {
|
|
|
- testFile.value = 'customScheme://' + res.content.localPath
|
|
|
- fetch(testFile.value)
|
|
|
- }
|
|
|
- }
|
|
|
- )
|
|
|
- })
|
|
|
- listenerMessage('getCourseFilePath', (res) => {
|
|
|
- if (res?.content) {
|
|
|
- testFile.value = res.content.localPath
|
|
|
- }
|
|
|
})
|
|
|
// 返回
|
|
|
const goback = () => {
|
|
|
// history.go(-1)
|
|
|
postMessage({ api: 'back' })
|
|
|
}
|
|
|
- // 所有的切换
|
|
|
- const handleChange = () => {
|
|
|
- // console.log('切换了')
|
|
|
- const iframes = document.querySelectorAll('.musicIframe')
|
|
|
- Array.from(iframes).map((f: any) => {
|
|
|
- f.contentWindow.postMessage({ api: 'setPlayState' }, '*')
|
|
|
- })
|
|
|
- data.players.forEach((p: any) => {
|
|
|
- p.stop()
|
|
|
- })
|
|
|
- }
|
|
|
- onUnmounted(() => {
|
|
|
- postMessage({
|
|
|
- api: 'setRequestedOrientation',
|
|
|
- content: {
|
|
|
- orientation: 1
|
|
|
- }
|
|
|
- })
|
|
|
- postMessage({
|
|
|
- api: 'setBarStatus',
|
|
|
- content: {
|
|
|
- status: 1
|
|
|
- }
|
|
|
- })
|
|
|
- postMessage({
|
|
|
- api: 'setStatusBarVisibility',
|
|
|
- content: {
|
|
|
- isVisibility: 1
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
|
|
|
+ const swipeRef = ref()
|
|
|
const popupData = reactive({
|
|
|
open: false,
|
|
|
- activeIndex: 0,
|
|
|
+ activeIndex: -1,
|
|
|
tabActive: '',
|
|
|
tabName: '',
|
|
|
itemActive: '',
|
|
|
itemName: ''
|
|
|
})
|
|
|
+ // 设置当前的激活状态
|
|
|
+ const setActiveData = () => {
|
|
|
+ handleStopVideo()
|
|
|
+ }
|
|
|
+ watch(() => popupData.activeIndex, setActiveData)
|
|
|
+
|
|
|
+ // 停止所有的播放
|
|
|
+ const handleStopVideo = () => {
|
|
|
+ data.itemList.forEach((m: any) => {
|
|
|
+ m.videoEle?.pause()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // 获取name
|
|
|
+ const setAllName = () => {
|
|
|
+ const item = data.itemList.find((n: any) => n.id == popupData.itemActive)
|
|
|
+ const tab = data.knowledgePointList.find((n: any) => n.id == popupData.tabActive)
|
|
|
+ if (item) {
|
|
|
+ popupData.itemName = item.name
|
|
|
+ }
|
|
|
+ if (tab) {
|
|
|
+ popupData.tabName = tab.name
|
|
|
+ }
|
|
|
+ }
|
|
|
// 切换素材
|
|
|
const toggleMaterial = () => {
|
|
|
- const index = itemList.value.findIndex((n: any) => n.id == popupData.itemActive)
|
|
|
- popupData.activeIndex = index
|
|
|
- console.log('🚀 ~ popupData', popupData.activeIndex)
|
|
|
+ const index = data.itemList.findIndex((n: any) => n.id == popupData.itemActive)
|
|
|
+ if (index > -1) {
|
|
|
+ popupData.activeIndex = index
|
|
|
+ swipeRef.value?.swipeTo(index)
|
|
|
+ setAllName()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 轮播切换
|
|
|
+ const handleSwipeChange = (val: any) => {
|
|
|
+ popupData.activeIndex = val
|
|
|
+ const item = data.itemList[val]
|
|
|
+ if (item) {
|
|
|
+ popupData.tabActive = item.knowledgePointId
|
|
|
+ popupData.itemActive = item.id
|
|
|
+ setAllName()
|
|
|
+ }
|
|
|
}
|
|
|
// 上一个知识点, 下一个知识点
|
|
|
const handlePreAndNext = (type: string) => {
|
|
|
- console.log(popupData.tabActive)
|
|
|
- const tabIndex = data.knowledgePointList.findIndex((n: any) => n.id == popupData.tabActive)
|
|
|
- const itemIndex = itemList.value.findIndex((n: any) => n.id == popupData.itemActive)
|
|
|
-
|
|
|
- console.log("🚀 ~ tab", tabIndex, itemIndex)
|
|
|
+ if (type === 'up') {
|
|
|
+ swipeRef.value?.prev()
|
|
|
+ } else {
|
|
|
+ swipeRef.value?.next()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 去点名,签退
|
|
@@ -235,48 +218,191 @@ export default defineComponent({
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
+
|
|
|
+ // 双击
|
|
|
+ const handleDbClick = (item: any) => {
|
|
|
+ // console.log(activeData.item)
|
|
|
+ if (item && item.type === 'VIDEO') {
|
|
|
+ const videoEle: HTMLVideoElement = document.querySelector(`[data-vid='${item.id}']`)!
|
|
|
+ if (videoEle) {
|
|
|
+ if (videoEle.paused) {
|
|
|
+ closeToast()
|
|
|
+ videoEle.play()
|
|
|
+ } else {
|
|
|
+ showToast('已暂停')
|
|
|
+ videoEle.pause()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ item.timer = setTimeout(() => {
|
|
|
+ activeData.model = false
|
|
|
+ }, 3000)
|
|
|
+ console.dir(videoEle)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 视频播放
|
|
|
+ const handleVideoPlay = (e: Event) => {
|
|
|
+ const videoEle = e.target! as unknown as HTMLVideoElement
|
|
|
+ // console.log(videoEle.paused, videoEle.currentTime, videoEle.duration)
|
|
|
+ if (videoEle.paused) return
|
|
|
+ activeData.currentTime = videoEle.currentTime
|
|
|
+ activeData.duration = videoEle.duration
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调整播放进度
|
|
|
+ const handleChangeSlider = (val: any, m: any) => {
|
|
|
+ if (m?.videoEle) {
|
|
|
+ m.videoEle.currentTime = val
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return () => (
|
|
|
<div class={styles.coursewarePlay}>
|
|
|
<Swipe
|
|
|
style={{ height: '100vh' }}
|
|
|
+ ref={swipeRef}
|
|
|
showIndicators={false}
|
|
|
loop={false}
|
|
|
- initialSwipe={popupData.activeIndex}
|
|
|
vertical
|
|
|
lazyRender={true}
|
|
|
- onChange={(val: any) => {
|
|
|
- // item.index = val
|
|
|
- // popupData.itemActive = `${item.id}-${item?.materialList?.[item.index]?.id}`
|
|
|
- }}
|
|
|
+ onChange={handleSwipeChange}
|
|
|
>
|
|
|
- {itemList.value.map((m: any) => {
|
|
|
+ {data.itemList.map((m: any, mIndex: number) => {
|
|
|
return (
|
|
|
<SwipeItem>
|
|
|
- {m.type === 'VIDEO' ? (
|
|
|
- <div class={styles.videoItem}>
|
|
|
- <video class="player">
|
|
|
- <source src={m.content} type="video/mp4" />
|
|
|
- </video>
|
|
|
- </div>
|
|
|
- ) : m.type === 'IMG' ? (
|
|
|
- <div class={styles.imgItem}>
|
|
|
- <img src={m.content} />
|
|
|
- </div>
|
|
|
- ) : (
|
|
|
- <div class={styles.songItem}>
|
|
|
- <MusicScore music={m} />
|
|
|
+ <>
|
|
|
+ <div
|
|
|
+ class={styles.itemDiv}
|
|
|
+ onClick={() => {
|
|
|
+ clearTimeout(activeData.timer)
|
|
|
+ clearTimeout(m.timer)
|
|
|
+ if (Date.now() - activeData.nowTime < 300) {
|
|
|
+ handleDbClick(m)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ activeData.nowTime = Date.now()
|
|
|
+ activeData.timer = setTimeout(() => {
|
|
|
+ activeData.model = !activeData.model
|
|
|
+ }, 300)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {m.type === 'VIDEO' ? (
|
|
|
+ <>
|
|
|
+ <video
|
|
|
+ preload='auto'
|
|
|
+ class="player"
|
|
|
+ data-vid={m.id}
|
|
|
+ src={m.content}
|
|
|
+ loop={m.loop}
|
|
|
+ onLoadedmetadata={(e: Event) => {
|
|
|
+ const videoEle = e.target as unknown as HTMLVideoElement
|
|
|
+ // console.log('video加载成功', videoEle)
|
|
|
+ videoEle.currentTime = .5
|
|
|
+ m.currentTime = videoEle.currentTime
|
|
|
+ m.duration = videoEle.duration
|
|
|
+ m.videoEle = videoEle
|
|
|
+ }}
|
|
|
+ onTimeupdate={(e: Event) => {
|
|
|
+ const videoEle = e.target as unknown as HTMLVideoElement
|
|
|
+ // console.log('video播放中')
|
|
|
+ m.currentTime = videoEle.currentTime
|
|
|
+ }}
|
|
|
+ onPlay={() => {
|
|
|
+ console.log('播放')
|
|
|
+ m.paused = false
|
|
|
+ }}
|
|
|
+ onPause={() => {
|
|
|
+ clearTimeout(m.timer)
|
|
|
+ console.log('暂停')
|
|
|
+ m.paused = true
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <source src={m.content} type="video/mp4" />
|
|
|
+ </video>
|
|
|
+ <Transition name="bottom">
|
|
|
+ {activeData.model && (
|
|
|
+ <div class={styles.bottomFixedContainer}>
|
|
|
+ <div class={styles.time}>
|
|
|
+ <span>{getSecondRPM(m.currentTime)}</span>
|
|
|
+ <span>{getSecondRPM(m.duration)}</span>
|
|
|
+ </div>
|
|
|
+ <div class={styles.slider}>
|
|
|
+ <Slider
|
|
|
+ buttonSize={16}
|
|
|
+ step={0.01}
|
|
|
+ v-model:modelValue={m.currentTime}
|
|
|
+ onUpdate:modelValue={(val: any) => handleChangeSlider(val, m)}
|
|
|
+ min={0}
|
|
|
+ max={m.duration}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class={styles.actions}>
|
|
|
+ <div>
|
|
|
+ {m.paused ? (
|
|
|
+ <Icon
|
|
|
+ name={iconplay}
|
|
|
+ onClick={(e: Event) => {
|
|
|
+ e.stopPropagation()
|
|
|
+ clearTimeout(m.timer)
|
|
|
+ console.log('点击播放', m.videoEle)
|
|
|
+ m.videoEle?.play()
|
|
|
+ m.paused = false
|
|
|
+ m.timer = setTimeout(() => {
|
|
|
+ activeData.model = false
|
|
|
+ }, 3000)
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <Icon
|
|
|
+ name={iconpause}
|
|
|
+ onClick={(e: Event) => {
|
|
|
+ e.stopPropagation()
|
|
|
+ console.log('点击暂停')
|
|
|
+ m.videoEle?.pause()
|
|
|
+ m.paused = true
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ {m.loop ? (
|
|
|
+ <Icon
|
|
|
+ name={iconLoopActive}
|
|
|
+ onClick={(e: Event) => {
|
|
|
+ e.stopPropagation()
|
|
|
+ m.loop = false
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : (
|
|
|
+ <Icon
|
|
|
+ name={iconLoop}
|
|
|
+ onClick={(e: Event) => {
|
|
|
+ e.stopPropagation()
|
|
|
+ m.loop = true
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ <div>{popupData.itemName}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </Transition>
|
|
|
+ </>
|
|
|
+ ) : m.type === 'IMG' ? (
|
|
|
+ <img src={m.content} />
|
|
|
+ ) : (
|
|
|
+ <MusicScore music={m} />
|
|
|
+ )}
|
|
|
+ {/* <Transition name="van-fade">
|
|
|
+ {activeData.model && <div class={styles.playModel}></div>}
|
|
|
+ </Transition> */}
|
|
|
</div>
|
|
|
- )}
|
|
|
+ </>
|
|
|
</SwipeItem>
|
|
|
)
|
|
|
})}
|
|
|
</Swipe>
|
|
|
- <div
|
|
|
- class={styles.playModel}
|
|
|
- onClick={() => {
|
|
|
- activeData.model = !activeData.model
|
|
|
- }}
|
|
|
- ></div>
|
|
|
+
|
|
|
<Transition name="top">
|
|
|
{activeData.model && (
|
|
|
<div class={styles.headerContainer}>
|
|
@@ -336,30 +462,6 @@ export default defineComponent({
|
|
|
)}
|
|
|
</Transition>
|
|
|
|
|
|
- <Transition name="bottom">
|
|
|
- {activeData.model && (
|
|
|
- <div class={styles.bottomFixedContainer}>
|
|
|
- <div class={styles.time}>
|
|
|
- <span>03:12</span>
|
|
|
- <span>10:12</span>
|
|
|
- </div>
|
|
|
- <Slider
|
|
|
- buttonSize={16}
|
|
|
- style={{ margin: '8px 0' }}
|
|
|
- v-model:modelValue={activeData.currentTime}
|
|
|
- min={0}
|
|
|
- max={100}
|
|
|
- />
|
|
|
- <div class={styles.actions}>
|
|
|
- <div>
|
|
|
- <Icon name="play-circle" />
|
|
|
- <Icon name="pause-circle" />
|
|
|
- </div>
|
|
|
- <div>长笛的呼吸练习</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- )}
|
|
|
- </Transition>
|
|
|
<Popup
|
|
|
class={styles.popup}
|
|
|
overlayClass={styles.overlayClass}
|