|
@@ -2,102 +2,75 @@ import {
|
|
|
NBreadcrumb,
|
|
|
NBreadcrumbItem,
|
|
|
NButton,
|
|
|
+ NImage,
|
|
|
NSlider,
|
|
|
- NSpace
|
|
|
+ NSpace,
|
|
|
+ NSpin
|
|
|
} from 'naive-ui';
|
|
|
-import {
|
|
|
- computed,
|
|
|
- defineComponent,
|
|
|
- onMounted,
|
|
|
- reactive,
|
|
|
- ref,
|
|
|
- watch
|
|
|
-} from 'vue';
|
|
|
+import { computed, defineComponent, onMounted, reactive } from 'vue';
|
|
|
import styles from './detail.module.less';
|
|
|
import icon_back from '../../xiaoku-music/images/icon_back.png';
|
|
|
-import icon_separator from '../../xiaoku-music/images/icon_separator.png';
|
|
|
-import { useRoute, useRouter } from 'vue-router';
|
|
|
-import musicBg from '../../xiaoku-music/images/icon_default.png';
|
|
|
-import iconPan from '../images/icon-pan.png';
|
|
|
+import icon_arrow from '../../xiaoku-music/images/icon_arrow.png';
|
|
|
import icon_play from '../../xiaoku-music/images/icon_play.png';
|
|
|
import icon_pause from '../../xiaoku-music/images/icon_pause.png';
|
|
|
+import icon_default from '../../xiaoku-music/images/icon_default.png';
|
|
|
+import icon_separator from '../../xiaoku-music/images/icon_separator.png';
|
|
|
import iconT from '../images/icon-t.png';
|
|
|
import iconAddT from '../images/icon-add-t.png';
|
|
|
import iconPlusT from '../images/icon-plus-t.png';
|
|
|
-import { getSecondRPM } from '/src/utils';
|
|
|
-import { api_knowledgeWiki_detail } from '../api';
|
|
|
+import musicBg from '../../xiaoku-music/images/icon_default.png';
|
|
|
+import iconPan from '../images/icon-pan.png';
|
|
|
+import { useRoute, useRouter } from 'vue-router';
|
|
|
+import PlayLoading from '../../xiaoku-music/component/play-loading';
|
|
|
+import TheNoticeBar from '/src/components/TheNoticeBar';
|
|
|
import TheEmpty from '/src/components/TheEmpty';
|
|
|
+import PlayItem from '../../xiaoku-music/component/play-item';
|
|
|
+import { api_knowledgeWiki_detail } from '../api';
|
|
|
+import { state } from '/src/state';
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'instrument-detail',
|
|
|
setup() {
|
|
|
const route = useRoute();
|
|
|
const router = useRouter();
|
|
|
- const state = reactive({
|
|
|
- playState: 'pause',
|
|
|
+ const forms = reactive({
|
|
|
+ page: 1,
|
|
|
+ rows: 20,
|
|
|
+ status: true,
|
|
|
+ name: '', // 关键词
|
|
|
+ type: route.query.type
|
|
|
+ });
|
|
|
+ const data = reactive({
|
|
|
loading: false,
|
|
|
finshed: false,
|
|
|
reshing: false,
|
|
|
details: {} as any,
|
|
|
list: [] as any,
|
|
|
- fontSize: 18
|
|
|
- });
|
|
|
- let timer = null as any;
|
|
|
- const audioData = reactive({
|
|
|
- isFirst: true,
|
|
|
- duration: 0,
|
|
|
- currentTime: 0
|
|
|
+ listActive: 0,
|
|
|
+ playState: 'pause' as 'play' | 'pause',
|
|
|
+ showPlayer: false,
|
|
|
+ showPreivew: false,
|
|
|
+ previewUrl: '',
|
|
|
+ showCloseBtn: true,
|
|
|
+ fontSize: 18 // 默认18
|
|
|
});
|
|
|
- const audioRef = ref();
|
|
|
|
|
|
- const time = computed(() => {
|
|
|
- return `${getSecondRPM(audioData.currentTime)} / ${getSecondRPM(
|
|
|
- audioData.duration
|
|
|
- )}`;
|
|
|
+ /** 选中的item */
|
|
|
+ const activeItem = computed(() => {
|
|
|
+ return data.list[data.listActive] || {};
|
|
|
});
|
|
|
|
|
|
- /** 改变时间 */
|
|
|
- const handleChangeTime = (val: number) => {
|
|
|
- audioRef.value.pause();
|
|
|
- audioData.currentTime = val;
|
|
|
- clearTimeout(timer);
|
|
|
- timer = setTimeout(() => {
|
|
|
- audioRef.value.currentTime = val;
|
|
|
- if (state.playState === 'play') {
|
|
|
- audioRef.value.play();
|
|
|
- }
|
|
|
- timer = null;
|
|
|
- }, 300);
|
|
|
- };
|
|
|
-
|
|
|
- /** 加载成功 */
|
|
|
- const onLoadedmetadata = () => {
|
|
|
- audioData.duration = audioRef.value.duration;
|
|
|
- if (audioData.isFirst) {
|
|
|
- audioData.isFirst = false;
|
|
|
- return;
|
|
|
- }
|
|
|
- if (state.playState === 'play') {
|
|
|
- audioRef.value.play();
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- watch(
|
|
|
- () => state.playState,
|
|
|
- val => {
|
|
|
- console.log(val, 'val');
|
|
|
- if (val === 'play') {
|
|
|
- audioRef.value.play();
|
|
|
- } else {
|
|
|
- audioRef.value.pause();
|
|
|
- }
|
|
|
- }
|
|
|
- );
|
|
|
/** 播放曲目 */
|
|
|
const handlePlay = (item: any) => {
|
|
|
- const index = state.list.findIndex((_item: any) => _item.id === item.id);
|
|
|
+ const index = data.list.findIndex((_item: any) => _item.id === item.id);
|
|
|
if (index > -1) {
|
|
|
- state.playState = state.playState === 'play' ? 'pause' : 'play';
|
|
|
+ if (data.listActive === index) {
|
|
|
+ data.playState = data.playState === 'play' ? 'pause' : 'play';
|
|
|
+ } else {
|
|
|
+ data.playState = 'play';
|
|
|
+ }
|
|
|
+ data.showPlayer = true;
|
|
|
+ data.listActive = index;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -106,27 +79,36 @@ export default defineComponent({
|
|
|
type: 'play' | 'pause' | 'pre' | 'next' | 'favitor'
|
|
|
) => {
|
|
|
if (type === 'play') {
|
|
|
- state.playState = 'play';
|
|
|
+ data.playState = 'play';
|
|
|
} else if (type === 'pause') {
|
|
|
- state.playState = 'pause';
|
|
|
+ data.playState = 'pause';
|
|
|
+ } else if (type === 'pre') {
|
|
|
+ if (data.list[data.listActive - 1]) {
|
|
|
+ handlePlay(data.list[data.listActive - 1]);
|
|
|
+ }
|
|
|
+ } else if (type === 'next') {
|
|
|
+ if (data.list[data.listActive + 1]) {
|
|
|
+ handlePlay(data.list[data.listActive + 1]);
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
const getDetail = async () => {
|
|
|
- state.loading = true;
|
|
|
+ data.loading = true;
|
|
|
let res = {} as any;
|
|
|
try {
|
|
|
res = await api_knowledgeWiki_detail({ id: route.query.id });
|
|
|
} catch (error) {
|
|
|
console.log(error);
|
|
|
}
|
|
|
- if (state.reshing) {
|
|
|
- state.list = [];
|
|
|
- state.reshing = false;
|
|
|
+ if (data.reshing) {
|
|
|
+ data.list = [];
|
|
|
+ data.reshing = false;
|
|
|
}
|
|
|
|
|
|
- state.finshed = true;
|
|
|
- state.list = res.data.knowledgeWikiResources || [];
|
|
|
- state.list.forEach((item: any) => {
|
|
|
+ data.finshed = true;
|
|
|
+ data.list = res.data.knowledgeWikiResources || [];
|
|
|
+ data.list.forEach((item: any) => {
|
|
|
item.audioFileUrl = item.url;
|
|
|
});
|
|
|
const knowledgeWikiCategories = res.data.knowledgeWikiCategories || [];
|
|
@@ -134,12 +116,12 @@ export default defineComponent({
|
|
|
knowledgeWikiCategories.length > 0
|
|
|
? knowledgeWikiCategories[0].name
|
|
|
: '';
|
|
|
- const knowledgeWikiResources = res.data.knowledgeWikiResources || [];
|
|
|
- res.data.audioFileUrl =
|
|
|
- knowledgeWikiResources.length > 0 ? knowledgeWikiResources[0].url : '';
|
|
|
- state.details = res.data;
|
|
|
-
|
|
|
- state.loading = false;
|
|
|
+ res.data.intros = res.data.intros.replace(
|
|
|
+ /<video/gi,
|
|
|
+ '<video style="width: 100% !important;" controlslist="nodownload"'
|
|
|
+ );
|
|
|
+ data.details = res.data;
|
|
|
+ data.loading = false;
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
@@ -152,102 +134,139 @@ export default defineComponent({
|
|
|
style={{ cursor: 'pointer' }}
|
|
|
src={icon_back}
|
|
|
class={styles.iconBack}
|
|
|
- onClick={() => router.push({ path: '/content-music' })}
|
|
|
+ onClick={() => {
|
|
|
+ router.push('/content-music');
|
|
|
+ }}
|
|
|
/>
|
|
|
<NBreadcrumb separator="">
|
|
|
<NBreadcrumbItem
|
|
|
- onClick={() => router.push({ path: '/content-music' })}>
|
|
|
- 曲目鉴赏
|
|
|
+ onClick={() => {
|
|
|
+ router.push('/content-music');
|
|
|
+ }}>
|
|
|
+ 名曲鉴赏
|
|
|
</NBreadcrumbItem>
|
|
|
<img class={styles.separator} src={icon_separator} />
|
|
|
<NBreadcrumbItem>{route.query.name}</NBreadcrumbItem>
|
|
|
</NBreadcrumb>
|
|
|
</NSpace>
|
|
|
|
|
|
- <div class={[styles.wrap]}>
|
|
|
+ <div class={[styles.wrap, data.showPlayer ? styles.wrapBottom : '']}>
|
|
|
<div class={styles.content}>
|
|
|
<div class={styles.contentWrap}>
|
|
|
- <div class={styles.contentMusic}>
|
|
|
- <div class={styles.musicTop}>
|
|
|
+ <div class={[styles.musicList, 'musicList-container']}>
|
|
|
+ <div class={styles.wrapList}>
|
|
|
<div class={styles.musicInfo}>
|
|
|
<div class={styles.musicImg}>
|
|
|
<img
|
|
|
- src={state.details.avatar || musicBg}
|
|
|
+ src={data.details?.avatar || musicBg}
|
|
|
class={styles.img}
|
|
|
/>
|
|
|
- <img src={iconPan} class={styles.iconPan} />
|
|
|
+ <div class={styles.panSection}>
|
|
|
+ <img src={iconPan} class={styles.iconPan} />
|
|
|
+ <img
|
|
|
+ src={data.details?.avatar || musicBg}
|
|
|
+ class={styles.img2}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
<div class={styles.info}>
|
|
|
- <div class={styles.name}>{state.details.name}</div>
|
|
|
+ <div class={styles.name}>{data.details.name}</div>
|
|
|
<div class={styles.c}>
|
|
|
- <span>作曲:{state.details.composers}</span>
|
|
|
- <span>作词:{state.details.lyricists}</span>
|
|
|
+ <span>作曲:{data.details.composers}</span>
|
|
|
+ <span>作词:{data.details.lyricists}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- {state.details.audioFileUrl ? (
|
|
|
- <div class={styles.audio}>
|
|
|
- <div class={styles.playBtns}>
|
|
|
- <NButton
|
|
|
- color="rgba(57,130,246,1)"
|
|
|
- class={styles.playBtn}
|
|
|
- circle
|
|
|
- bordered={false}
|
|
|
- onClick={() => {
|
|
|
- //
|
|
|
- handleChangeAudio(
|
|
|
- state.playState === 'pause' ? 'play' : 'pause'
|
|
|
- );
|
|
|
+ <div class={styles.titlec}>
|
|
|
+ <i class={styles.icon2}></i>名曲鉴赏
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {data.list.map((item: any, index: any) => {
|
|
|
+ return (
|
|
|
+ <div class={styles.itemContainer}>
|
|
|
+ <div
|
|
|
+ class={[
|
|
|
+ styles.item
|
|
|
+ // data.listActive === index && styles.active
|
|
|
+ ]}
|
|
|
+ onClick={(e: Event) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ handlePlay(item);
|
|
|
}}>
|
|
|
- <img
|
|
|
- style={{
|
|
|
- display: state.playState === 'pause' ? '' : 'none'
|
|
|
- }}
|
|
|
- src={icon_play}
|
|
|
- />
|
|
|
- <img
|
|
|
- style={{
|
|
|
- display: state.playState === 'play' ? '' : 'none'
|
|
|
- }}
|
|
|
- src={icon_pause}
|
|
|
- />
|
|
|
- </NButton>
|
|
|
- </div>
|
|
|
- <div class={styles.timeWrap}>
|
|
|
- <NSlider
|
|
|
- tooltip={false}
|
|
|
- step={0.01}
|
|
|
- class={styles.timeProgress}
|
|
|
- value={audioData.currentTime}
|
|
|
- max={audioData.duration}
|
|
|
- onUpdate:value={val => handleChangeTime(val)}
|
|
|
- />
|
|
|
- <div class={styles.time}>{time.value}</div>
|
|
|
- <audio
|
|
|
- ref={audioRef}
|
|
|
- src={state.details.audioFileUrl}
|
|
|
- onLoadedmetadata={onLoadedmetadata}
|
|
|
- onEnded={() => {
|
|
|
- // emit('change', 'pause');
|
|
|
- }}
|
|
|
- onTimeupdate={() => {
|
|
|
- if (timer) return;
|
|
|
- audioData.currentTime = audioRef.value?.currentTime;
|
|
|
- }}></audio>
|
|
|
+ <div class={styles.img}>
|
|
|
+ <NImage
|
|
|
+ lazy
|
|
|
+ objectFit="cover"
|
|
|
+ previewDisabled={true}
|
|
|
+ src={item.titleImg || icon_default}
|
|
|
+ onLoad={e => {
|
|
|
+ (e.target as any).dataset.loaded = 'true';
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <PlayLoading
|
|
|
+ class={[
|
|
|
+ data.listActive === index &&
|
|
|
+ data.playState === 'play'
|
|
|
+ ? ''
|
|
|
+ : styles.showPlayLoading
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class={styles.title}>
|
|
|
+ <div class={styles.titleName}>
|
|
|
+ <TheNoticeBar text={item.name} />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <NButton
|
|
|
+ color="#259CFE"
|
|
|
+ textColor="#fff"
|
|
|
+ round
|
|
|
+ class={styles.btn}
|
|
|
+ type="primary"
|
|
|
+ onClick={(e: Event) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ handlePlay(item);
|
|
|
+ }}>
|
|
|
+ 播放
|
|
|
+ <img
|
|
|
+ src={
|
|
|
+ data.listActive === index &&
|
|
|
+ data.playState === 'play'
|
|
|
+ ? icon_pause
|
|
|
+ : icon_play
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </NButton>
|
|
|
+
|
|
|
+ <img class={styles.arrow} src={icon_arrow} />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ {!data.finshed && (
|
|
|
+ <div class={styles.loadingWrap}>
|
|
|
+ <NSpin show={true}></NSpin>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {!data.loading && data.list.length === 0 && (
|
|
|
+ <div class={styles.empty}>
|
|
|
+ <TheEmpty description="暂无名曲鉴赏"></TheEmpty>
|
|
|
</div>
|
|
|
- ) : (
|
|
|
- ''
|
|
|
)}
|
|
|
</div>
|
|
|
+ </div>
|
|
|
|
|
|
+ <div class={styles.musicStaff}>
|
|
|
+ <div class={styles.musicTitle}>
|
|
|
+ <i class={styles.icon1}></i>名曲故事
|
|
|
+ </div>
|
|
|
<div
|
|
|
class={styles.musicContent}
|
|
|
- v-html={state.details.intros}
|
|
|
- style={{ fontSize: state.fontSize + 'px' }}></div>
|
|
|
- {!state.loading && !state.details.intros && <TheEmpty />}
|
|
|
+ v-html={data.details?.intros}
|
|
|
+ style={{ fontSize: data.fontSize + 'px' }}></div>
|
|
|
</div>
|
|
|
|
|
|
<div class={styles.changeSizeSection}>
|
|
@@ -256,12 +275,12 @@ export default defineComponent({
|
|
|
src={iconAddT}
|
|
|
class={styles.iconAddT}
|
|
|
onClick={() => {
|
|
|
- if (state.fontSize >= 32) return;
|
|
|
- state.fontSize += 1;
|
|
|
+ if (data.fontSize >= 32) return;
|
|
|
+ data.fontSize += 1;
|
|
|
}}
|
|
|
/>
|
|
|
<NSlider
|
|
|
- v-model:value={state.fontSize}
|
|
|
+ v-model:value={data.fontSize}
|
|
|
vertical
|
|
|
min={12}
|
|
|
max={32}
|
|
@@ -270,14 +289,23 @@ export default defineComponent({
|
|
|
src={iconPlusT}
|
|
|
class={styles.iconPlusT}
|
|
|
onClick={() => {
|
|
|
- if (state.fontSize <= 12) return;
|
|
|
- state.fontSize -= 1;
|
|
|
+ if (data.fontSize <= 12) return;
|
|
|
+ data.fontSize -= 1;
|
|
|
}}
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ {data.list.length !== 0 && (
|
|
|
+ <PlayItem
|
|
|
+ show={data.showPlayer}
|
|
|
+ playState={data.playState}
|
|
|
+ item={activeItem.value}
|
|
|
+ onChange={value => handleChangeAudio(value)}
|
|
|
+ />
|
|
|
+ )}
|
|
|
</div>
|
|
|
);
|
|
|
}
|