detail.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import {
  2. NBreadcrumb,
  3. NBreadcrumbItem,
  4. NButton,
  5. NImage,
  6. NSlider,
  7. NSpace,
  8. NSpin
  9. } from 'naive-ui';
  10. import { computed, defineComponent, onMounted, reactive, watch } from 'vue';
  11. import styles from './detail.module.less';
  12. // import icon_back from '../../xiaoku-music/images/icon_back.png';
  13. import icon_arrow from '../../../xiaoku-music/images/icon_arrow.png';
  14. import icon_play from '../../../xiaoku-music/images/icon_play.png';
  15. import icon_pause from '../../../xiaoku-music/images/icon_pause.png';
  16. import icon_default from '../../../xiaoku-music/images/icon_default.png';
  17. // import icon_separator from '../../xiaoku-music/images/icon_separator.png';
  18. import iconT from '/src/views/content-information/images/icon-t.png';
  19. import iconAddT from '/src/views/content-information/images/icon-add-t.png';
  20. import iconPlusT from '/src/views/content-information/images/icon-plus-t.png';
  21. import { useRoute, useRouter } from 'vue-router';
  22. import PlayLoading from '../../../xiaoku-music/component/play-loading';
  23. import TheNoticeBar from '/src/components/TheNoticeBar';
  24. import TheEmpty from '/src/components/TheEmpty';
  25. import PlayItem from '../../../xiaoku-music/component/play-item';
  26. import { api_knowledgeWiki_detail } from '/src/views/content-information/api';
  27. export default defineComponent({
  28. name: 'instrument-detail',
  29. props: {
  30. id: {
  31. type: String,
  32. default: ''
  33. },
  34. type: {
  35. type: String,
  36. default: ''
  37. },
  38. activeStatus: {
  39. type: Boolean,
  40. default: false
  41. }
  42. },
  43. setup(props, { expose }) {
  44. const route = useRoute();
  45. const router = useRouter();
  46. const forms = reactive({
  47. page: 1,
  48. rows: 20,
  49. status: true,
  50. name: '', // 关键词
  51. type: route.query.type
  52. });
  53. const data = reactive({
  54. loading: false,
  55. finshed: false,
  56. reshing: false,
  57. details: {} as any,
  58. list: [] as any,
  59. listActive: 0,
  60. playState: 'pause' as 'play' | 'pause',
  61. showPlayer: false,
  62. showPreivew: false,
  63. previewUrl: '',
  64. showCloseBtn: true,
  65. fontSize: 18 // 默认18
  66. });
  67. /** 选中的item */
  68. const activeItem = computed(() => {
  69. return data.list[data.listActive] || {};
  70. });
  71. /** 播放曲目 */
  72. const handlePlay = (item: any) => {
  73. const index = data.list.findIndex((_item: any) => _item.id === item.id);
  74. if (index > -1) {
  75. if (data.listActive === index) {
  76. data.playState = data.playState === 'play' ? 'pause' : 'play';
  77. } else {
  78. data.playState = 'play';
  79. }
  80. data.showPlayer = true;
  81. data.listActive = index;
  82. }
  83. };
  84. /** 音频控制 */
  85. const handleChangeAudio = (
  86. type: 'play' | 'pause' | 'pre' | 'next' | 'favitor'
  87. ) => {
  88. if (type === 'play') {
  89. data.playState = 'play';
  90. } else if (type === 'pause') {
  91. data.playState = 'pause';
  92. } else if (type === 'pre') {
  93. if (data.list[data.listActive - 1]) {
  94. handlePlay(data.list[data.listActive - 1]);
  95. }
  96. } else if (type === 'next') {
  97. if (data.list[data.listActive + 1]) {
  98. handlePlay(data.list[data.listActive + 1]);
  99. }
  100. }
  101. };
  102. const getDetail = async () => {
  103. data.loading = true;
  104. let res = {} as any;
  105. try {
  106. res = await api_knowledgeWiki_detail({
  107. id: props.id || route.query.id
  108. });
  109. } catch (error) {
  110. console.log(error);
  111. }
  112. if (data.reshing) {
  113. data.list = [];
  114. data.reshing = false;
  115. }
  116. data.finshed = true;
  117. data.list = res.data.knowledgeWikiResources || [];
  118. data.list.forEach((item: any) => {
  119. item.audioFileUrl = item.url;
  120. item.musicSheetName = item.name;
  121. });
  122. const knowledgeWikiCategories = res.data.knowledgeWikiCategories || [];
  123. res.data.knowledgeName =
  124. knowledgeWikiCategories.length > 0
  125. ? knowledgeWikiCategories[0].knowledgeWikiCategoryTypeName
  126. : '';
  127. res.data.intros = res.data.intros.replace(
  128. /<video/gi,
  129. '<video style="width: 100% !important;" controlslist="nodownload"'
  130. );
  131. data.details = res.data;
  132. data.loading = false;
  133. };
  134. onMounted(() => {
  135. getDetail();
  136. });
  137. watch(
  138. () => props.activeStatus,
  139. () => {
  140. if (!props.activeStatus) {
  141. handleChangeAudio('pause');
  142. }
  143. }
  144. );
  145. expose({
  146. handleChangeAudio
  147. });
  148. return () => (
  149. <div
  150. class={[
  151. styles.container,
  152. props.type === 'preview' && styles.containerPreview,
  153. props.type === 'modal' && styles.containerModal
  154. ]}>
  155. <div class={[styles.wrap, data.showPlayer ? styles.wrapBottom : '']}>
  156. <div class={styles.content}>
  157. <div class={styles.contentWrap}>
  158. <div class={[styles.musicList, 'musicList-container']}>
  159. <div class={styles.wrapList}>
  160. <div class={styles.instrumentGroup}>
  161. <NImage
  162. class={[
  163. styles.instrumentImg,
  164. forms.type === 'MUSICIAN' && styles.otherImg
  165. ]}
  166. src={data.details?.avatar}
  167. objectFit="cover"
  168. />
  169. <p class={styles.instrumentName}>{data.details.name}</p>
  170. <p class={styles.instrumentTag}>
  171. {data.details.knowledgeName}
  172. </p>
  173. </div>
  174. <div class={styles.titlec}>
  175. <i class={styles.icon2}></i>代表作
  176. </div>
  177. {data.list.map((item: any, index: any) => {
  178. return (
  179. <div class={styles.itemContainer}>
  180. <div
  181. class={[
  182. styles.item
  183. // data.listActive === index && styles.active
  184. ]}
  185. onClick={(e: Event) => {
  186. e.stopPropagation();
  187. handlePlay(item);
  188. }}>
  189. <div class={styles.img}>
  190. <NImage
  191. lazy
  192. objectFit="cover"
  193. previewDisabled={true}
  194. src={item.titleImg || icon_default}
  195. onLoad={e => {
  196. (e.target as any).dataset.loaded = 'true';
  197. }}
  198. />
  199. <PlayLoading
  200. class={[
  201. data.listActive === index &&
  202. data.playState === 'play'
  203. ? ''
  204. : styles.showPlayLoading
  205. ]}
  206. />
  207. </div>
  208. <div class={styles.title}>
  209. <div class={styles.titleName}>
  210. <TheNoticeBar
  211. text={item.name}
  212. style={{ marginRight: '12px' }}
  213. />
  214. </div>
  215. </div>
  216. <NButton
  217. color="#259CFE"
  218. textColor="#fff"
  219. round
  220. class={styles.btn}
  221. type="primary"
  222. onClick={(e: Event) => {
  223. e.stopPropagation();
  224. handlePlay(item);
  225. }}>
  226. 播放
  227. <img
  228. src={
  229. data.listActive === index &&
  230. data.playState === 'play'
  231. ? icon_pause
  232. : icon_play
  233. }
  234. />
  235. </NButton>
  236. <img class={styles.arrow} src={icon_arrow} />
  237. </div>
  238. </div>
  239. );
  240. })}
  241. {!data.finshed && (
  242. <div class={styles.loadingWrap}>
  243. <NSpin show={true}></NSpin>
  244. </div>
  245. )}
  246. {!data.loading && data.list.length === 0 && (
  247. <div class={styles.empty}>
  248. <TheEmpty description="暂无代表作"></TheEmpty>
  249. </div>
  250. )}
  251. </div>
  252. </div>
  253. <div class={styles.musicStaff}>
  254. <div class={styles.musicTitle}>
  255. <i
  256. class={
  257. forms.type === 'MUSICIAN' ? styles.icon3 : styles.icon1
  258. }></i>
  259. {forms.type === 'MUSICIAN' ? '个人简介' : '乐器简介'}
  260. </div>
  261. <div
  262. class={styles.musicContent}
  263. v-html={data.details?.intros}
  264. style={{ fontSize: data.fontSize + 'px' }}></div>
  265. </div>
  266. <div class={styles.changeSizeSection}>
  267. <img src={iconT} class={styles.iconT} />
  268. <img
  269. src={iconAddT}
  270. class={styles.iconAddT}
  271. onClick={() => {
  272. if (data.fontSize >= 32) return;
  273. data.fontSize += 1;
  274. }}
  275. />
  276. <NSlider
  277. v-model:value={data.fontSize}
  278. vertical
  279. min={12}
  280. max={32}
  281. />
  282. <img
  283. src={iconPlusT}
  284. class={styles.iconPlusT}
  285. onClick={() => {
  286. if (data.fontSize <= 12) return;
  287. data.fontSize -= 1;
  288. }}
  289. />
  290. </div>
  291. </div>
  292. </div>
  293. </div>
  294. {data.list.length !== 0 && (
  295. <PlayItem
  296. type={props.type}
  297. show={data.showPlayer}
  298. playState={data.playState}
  299. item={activeItem.value}
  300. onChange={value => handleChangeAudio(value)}
  301. />
  302. )}
  303. </div>
  304. );
  305. }
  306. });