|  | @@ -1,517 +1,536 @@
 | 
	
		
			
				|  |  | -import { PropType, Transition, defineComponent, ref } from 'vue';
 | 
	
		
			
				|  |  | -import styles from './index.module.less';
 | 
	
		
			
				|  |  | -import { NButton, NCard, NImage, NModal, NSpin, useMessage } from 'naive-ui';
 | 
	
		
			
				|  |  | -import iconImage from '@common/images/icon-image.png';
 | 
	
		
			
				|  |  | -import iconVideo from '@common/images/icon-video.png';
 | 
	
		
			
				|  |  | -import iconAudio from '@common/images/icon-audio.png';
 | 
	
		
			
				|  |  | -import iconMusic from '@common/images/icon-music.png';
 | 
	
		
			
				|  |  | -import iconPPT from '@common/images/icon-ppt.png';
 | 
	
		
			
				|  |  | -import iconOther from '@common/images/icon-other.png';
 | 
	
		
			
				|  |  | -import iconCollectDefault from '@common/images/icon-collect-default.png';
 | 
	
		
			
				|  |  | -import iconCollectActive from '@common/images/icon-collect-active.png';
 | 
	
		
			
				|  |  | -import iconDownload from '@common/images/icon-download.png';
 | 
	
		
			
				|  |  | -import TheNoticeBar from '../TheNoticeBar';
 | 
	
		
			
				|  |  | -import AudioPlayer from './audio-player';
 | 
	
		
			
				|  |  | -import VideoPlayer from './video-player';
 | 
	
		
			
				|  |  | -import { PageEnum } from '/src/enums/pageEnum';
 | 
	
		
			
				|  |  | -import { api_musicSheetDetail } from '/src/api/user';
 | 
	
		
			
				|  |  | -import JSZip, { file } from 'jszip';
 | 
	
		
			
				|  |  | -import { saveAs } from 'file-saver';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// LISTEN:听音,RHYTHM:节奏,THEORY:乐理知识,MUSIC_WIKI:曲目 INSTRUMENT:乐器 MUSICIAN:音乐家)
 | 
	
		
			
				|  |  | -type itemType = {
 | 
	
		
			
				|  |  | -  id: string | number;
 | 
	
		
			
				|  |  | -  type:
 | 
	
		
			
				|  |  | -    | 'IMG'
 | 
	
		
			
				|  |  | -    | 'VIDEO'
 | 
	
		
			
				|  |  | -    | 'SONG'
 | 
	
		
			
				|  |  | -    | 'MUSIC'
 | 
	
		
			
				|  |  | -    | 'PPT'
 | 
	
		
			
				|  |  | -    | 'LISTEN'
 | 
	
		
			
				|  |  | -    | 'RHYTHM'
 | 
	
		
			
				|  |  | -    | 'THEORY'
 | 
	
		
			
				|  |  | -    | 'MUSIC_WIKI'
 | 
	
		
			
				|  |  | -    | 'INSTRUMENT'
 | 
	
		
			
				|  |  | -    | 'MUSICIAN';
 | 
	
		
			
				|  |  | -  coverImg: string;
 | 
	
		
			
				|  |  | -  content?: string;
 | 
	
		
			
				|  |  | -  title: string;
 | 
	
		
			
				|  |  | -  isCollect: boolean;
 | 
	
		
			
				|  |  | -  isSelected: boolean; // 精选
 | 
	
		
			
				|  |  | -  exist?: boolean; // 是否已经选
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -export default defineComponent({
 | 
	
		
			
				|  |  | -  name: 'card-type',
 | 
	
		
			
				|  |  | -  props: {
 | 
	
		
			
				|  |  | -    // 是否是选中状态
 | 
	
		
			
				|  |  | -    isActive: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: false
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    /** 是否可以拖拽 */
 | 
	
		
			
				|  |  | -    draggable: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: false
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    // 是否可以收藏
 | 
	
		
			
				|  |  | -    isCollect: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: true
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    // 是否显示收藏
 | 
	
		
			
				|  |  | -    isShowCollect: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: true
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    // 是否显示添加按钮
 | 
	
		
			
				|  |  | -    isShowAdd: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: false
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    // 是否禁用添加按钮
 | 
	
		
			
				|  |  | -    isShowAddDisabled: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: false
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    // 鼠标移动上面的时候是否自动播放,或者可以点击
 | 
	
		
			
				|  |  | -    disabledMouseHover: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: true
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    // 是否预览
 | 
	
		
			
				|  |  | -    isPreview: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: true
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    item: {
 | 
	
		
			
				|  |  | -      type: Object as PropType<itemType>,
 | 
	
		
			
				|  |  | -      default: () => ({})
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    /** 是否下架 */
 | 
	
		
			
				|  |  | -    offShelf: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: false
 | 
	
		
			
				|  |  | -    },
 | 
	
		
			
				|  |  | -    /** 是否可以下载 */
 | 
	
		
			
				|  |  | -    isDownload: {
 | 
	
		
			
				|  |  | -      type: Boolean,
 | 
	
		
			
				|  |  | -      default: false
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  /**
 | 
	
		
			
				|  |  | -   * @type {string} click 点击事件
 | 
	
		
			
				|  |  | -   * @type {string} collect 收藏
 | 
	
		
			
				|  |  | -   * @type {string} add 添加
 | 
	
		
			
				|  |  | -   * @type {string} offShelf 下架
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -  emits: ['click', 'collect', 'add', 'offShelf'],
 | 
	
		
			
				|  |  | -  setup(props, { emit }) {
 | 
	
		
			
				|  |  | -    const message = useMessage();
 | 
	
		
			
				|  |  | -    const isAnimation = ref(false);
 | 
	
		
			
				|  |  | -    const downloadStatus = ref(false);
 | 
	
		
			
				|  |  | -    const formatType = (type: string) => {
 | 
	
		
			
				|  |  | -      let typeImg = iconOther;
 | 
	
		
			
				|  |  | -      switch (type) {
 | 
	
		
			
				|  |  | -        case 'IMG':
 | 
	
		
			
				|  |  | -          typeImg = iconImage;
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        case 'VIDEO':
 | 
	
		
			
				|  |  | -          typeImg = iconVideo;
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        case 'SONG':
 | 
	
		
			
				|  |  | -          typeImg = iconAudio;
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        case 'MUSIC':
 | 
	
		
			
				|  |  | -          typeImg = iconMusic;
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -        case 'PPT':
 | 
	
		
			
				|  |  | -          typeImg = iconPPT;
 | 
	
		
			
				|  |  | -          break;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      return typeImg;
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // 获取文件blob格式
 | 
	
		
			
				|  |  | -    const getFileBlob = (url: string) => {
 | 
	
		
			
				|  |  | -      return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | -        const request = new XMLHttpRequest();
 | 
	
		
			
				|  |  | -        request.open('GET', url, true);
 | 
	
		
			
				|  |  | -        request.responseType = 'blob';
 | 
	
		
			
				|  |  | -        request.onload = (res: any) => {
 | 
	
		
			
				|  |  | -          if (res.target.status == 200) {
 | 
	
		
			
				|  |  | -            resolve(res.target.response);
 | 
	
		
			
				|  |  | -          } else {
 | 
	
		
			
				|  |  | -            reject(res);
 | 
	
		
			
				|  |  | -          }
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        request.send();
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // 多个文件下载
 | 
	
		
			
				|  |  | -    const downLoadMultiFile = (files: any, filesName: string) => {
 | 
	
		
			
				|  |  | -      const zip = new JSZip();
 | 
	
		
			
				|  |  | -      const result = [];
 | 
	
		
			
				|  |  | -      for (const i in files) {
 | 
	
		
			
				|  |  | -        const promise = getFileBlob(files[i].url).then((res: any) => {
 | 
	
		
			
				|  |  | -          zip.file(files[i].name, res, { binary: true });
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -        result.push(promise);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      Promise.all(result)
 | 
	
		
			
				|  |  | -        .then(() => {
 | 
	
		
			
				|  |  | -          zip.generateAsync({ type: 'blob' }).then(res => {
 | 
	
		
			
				|  |  | -            saveAs(
 | 
	
		
			
				|  |  | -              res,
 | 
	
		
			
				|  |  | -              filesName
 | 
	
		
			
				|  |  | -                ? filesName + Date.now() + '.zip'
 | 
	
		
			
				|  |  | -                : `文件夹${Date.now()}.zip`
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -          });
 | 
	
		
			
				|  |  | -        })
 | 
	
		
			
				|  |  | -        .catch(() => {
 | 
	
		
			
				|  |  | -          message.error('下载失败');
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      downloadStatus.value = false;
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    const downloadFile = (filename: string, fileUrl: string) => {
 | 
	
		
			
				|  |  | -      // 发起Fetch请求
 | 
	
		
			
				|  |  | -      fetch(fileUrl)
 | 
	
		
			
				|  |  | -        .then(response => response.blob())
 | 
	
		
			
				|  |  | -        .then(blob => {
 | 
	
		
			
				|  |  | -          saveAs(blob, filename);
 | 
	
		
			
				|  |  | -          setTimeout(() => {
 | 
	
		
			
				|  |  | -            downloadStatus.value = false;
 | 
	
		
			
				|  |  | -          }, 100);
 | 
	
		
			
				|  |  | -        })
 | 
	
		
			
				|  |  | -        .catch(() => {
 | 
	
		
			
				|  |  | -          message.error('下载失败');
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      downloadStatus.value = false;
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    const getFileName = (url: any) => {
 | 
	
		
			
				|  |  | -      // 使用正则表达式获取文件名
 | 
	
		
			
				|  |  | -      const tempUrl = url.split('?');
 | 
	
		
			
				|  |  | -      const fileNameRegex = /\/([^\\/]+)$/; // 匹配最后一个斜杠后的内容
 | 
	
		
			
				|  |  | -      const match = tempUrl[0].match(fileNameRegex);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      if (match) {
 | 
	
		
			
				|  |  | -        return match[1];
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        return '';
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -    const onDownload = async (e: MouseEvent) => {
 | 
	
		
			
				|  |  | -      e.stopPropagation();
 | 
	
		
			
				|  |  | -      e.preventDefault();
 | 
	
		
			
				|  |  | -      const item = props.item;
 | 
	
		
			
				|  |  | -      if (!item.content) {
 | 
	
		
			
				|  |  | -        message.error('下载失败');
 | 
	
		
			
				|  |  | -        return;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      if (downloadStatus.value) return false;
 | 
	
		
			
				|  |  | -      downloadStatus.value = true;
 | 
	
		
			
				|  |  | -      const suffix: any = item.content?.split('.');
 | 
	
		
			
				|  |  | -      const fileName = item.title + '.' + suffix[suffix?.length - 1];
 | 
	
		
			
				|  |  | -      if (item.type === 'MUSIC') {
 | 
	
		
			
				|  |  | -        const { data } = await api_musicSheetDetail(item.content);
 | 
	
		
			
				|  |  | -        const urls = [];
 | 
	
		
			
				|  |  | -        if (data.xmlFileUrl) {
 | 
	
		
			
				|  |  | -          urls.push({
 | 
	
		
			
				|  |  | -            url: data.xmlFileUrl,
 | 
	
		
			
				|  |  | -            name: getFileName(data.xmlFileUrl)
 | 
	
		
			
				|  |  | -          });
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        if (data.background && data.background.length > 0) {
 | 
	
		
			
				|  |  | -          data.background.forEach((item: any) => {
 | 
	
		
			
				|  |  | -            urls.push({
 | 
	
		
			
				|  |  | -              url: item.audioFileUrl,
 | 
	
		
			
				|  |  | -              name: getFileName(item.audioFileUrl)
 | 
	
		
			
				|  |  | -            });
 | 
	
		
			
				|  |  | -          });
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        downLoadMultiFile(urls, item.title);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // setTimeout(() => {
 | 
	
		
			
				|  |  | -        //   downloadStatus.value = false;
 | 
	
		
			
				|  |  | -        // }, 1000);
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        downloadFile(fileName, item.content);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return () => (
 | 
	
		
			
				|  |  | -      <div
 | 
	
		
			
				|  |  | -        onClick={() => emit('click', props.item)}
 | 
	
		
			
				|  |  | -        key={props.item.id}
 | 
	
		
			
				|  |  | -        draggable={!props.draggable ? false : props.item.exist ? false : true}
 | 
	
		
			
				|  |  | -        class={[
 | 
	
		
			
				|  |  | -          styles['card-section'],
 | 
	
		
			
				|  |  | -          'card-section-container',
 | 
	
		
			
				|  |  | -          !props.draggable ? '' : props.item.exist ? '' : styles.cardDrag
 | 
	
		
			
				|  |  | -        ]}
 | 
	
		
			
				|  |  | -        onMouseenter={() => {
 | 
	
		
			
				|  |  | -          isAnimation.value = true;
 | 
	
		
			
				|  |  | -        }}
 | 
	
		
			
				|  |  | -        onMouseleave={() => {
 | 
	
		
			
				|  |  | -          isAnimation.value = false;
 | 
	
		
			
				|  |  | -        }}
 | 
	
		
			
				|  |  | -        onDragstart={(e: any) => {
 | 
	
		
			
				|  |  | -          console.log('dragstart', Date.now());
 | 
	
		
			
				|  |  | -          e.dataTransfer.setData('text', JSON.stringify(props.item));
 | 
	
		
			
				|  |  | -        }}>
 | 
	
		
			
				|  |  | -        {/* 判断是否下架 */}
 | 
	
		
			
				|  |  | -        {props.offShelf && (
 | 
	
		
			
				|  |  | -          <div class={styles.offShelfBg}>
 | 
	
		
			
				|  |  | -            <p class={styles.offShelfTips}>该资源已被下架</p>
 | 
	
		
			
				|  |  | -            <NButton
 | 
	
		
			
				|  |  | -              type="primary"
 | 
	
		
			
				|  |  | -              class={styles.offShelfBtn}
 | 
	
		
			
				|  |  | -              onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | -                e.stopPropagation();
 | 
	
		
			
				|  |  | -                emit('offShelf');
 | 
	
		
			
				|  |  | -              }}>
 | 
	
		
			
				|  |  | -              确认
 | 
	
		
			
				|  |  | -            </NButton>
 | 
	
		
			
				|  |  | -          </div>
 | 
	
		
			
				|  |  | -        )}
 | 
	
		
			
				|  |  | -        <NCard
 | 
	
		
			
				|  |  | -          class={[
 | 
	
		
			
				|  |  | -            styles['card-section-content'],
 | 
	
		
			
				|  |  | -            props.isShowAdd ? '' : styles.course,
 | 
	
		
			
				|  |  | -            props.isActive ? styles.isActive : '',
 | 
	
		
			
				|  |  | -            props.item.exist ? styles.showAddBtn : '' // 是否已添加
 | 
	
		
			
				|  |  | -          ]}
 | 
	
		
			
				|  |  | -          style={{ cursor: 'pointer' }}>
 | 
	
		
			
				|  |  | -          {{
 | 
	
		
			
				|  |  | -            cover: () => (
 | 
	
		
			
				|  |  | -              <>
 | 
	
		
			
				|  |  | -                {/* 图片 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'IMG' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={props.disabledMouseHover}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg}
 | 
	
		
			
				|  |  | -                    previewSrc={props.item.content}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 乐谱 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'MUSIC' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="contain"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 音频 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'SONG' && (
 | 
	
		
			
				|  |  | -                  <AudioPlayer
 | 
	
		
			
				|  |  | -                    content={props.item.content}
 | 
	
		
			
				|  |  | -                    cover={props.item.coverImg}
 | 
	
		
			
				|  |  | -                    previewDisabled={props.disabledMouseHover}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 视频 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'VIDEO' && (
 | 
	
		
			
				|  |  | -                  <VideoPlayer
 | 
	
		
			
				|  |  | -                    cover={props.item.coverImg}
 | 
	
		
			
				|  |  | -                    content={props.item.content}
 | 
	
		
			
				|  |  | -                    previewDisabled={props.disabledMouseHover}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* ppt */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'PPT' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg || PageEnum.PPT_DEFAULT_COVER}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 节奏练习 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'RHYTHM' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg || PageEnum.RHYTHM_DEFAULT_COVER}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                {/* 听音练习 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'LISTEN' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 乐理 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'THEORY' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg || PageEnum.THEORY_DEFAULT_COVER}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 名曲 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'MUSIC_WIKI' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg || PageEnum.MUSIC_DEFAULT_COVER}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 乐器 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'INSTRUMENT' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={
 | 
	
		
			
				|  |  | -                      props.item.coverImg || PageEnum.INSTRUMENT_DEFAULT_COVER
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -                {/* 音乐家 */}
 | 
	
		
			
				|  |  | -                {props.item.type === 'MUSICIAN' && (
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | -                    lazy
 | 
	
		
			
				|  |  | -                    previewDisabled={true}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                    src={props.item.coverImg || PageEnum.MUSICIAN_DEFAULT_COVER}
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -              </>
 | 
	
		
			
				|  |  | -            ),
 | 
	
		
			
				|  |  | -            footer: () => (
 | 
	
		
			
				|  |  | -              <div class={styles.footer}>
 | 
	
		
			
				|  |  | -                <div class={[styles.title, 'footerTitle']}>
 | 
	
		
			
				|  |  | -                  <NImage
 | 
	
		
			
				|  |  | -                    class={[styles.titleType]}
 | 
	
		
			
				|  |  | -                    src={formatType(props.item.type)}
 | 
	
		
			
				|  |  | -                    objectFit="cover"
 | 
	
		
			
				|  |  | -                  />
 | 
	
		
			
				|  |  | -                  <span class={[styles.titleContent, 'titleContent']}>
 | 
	
		
			
				|  |  | -                    <TheNoticeBar
 | 
	
		
			
				|  |  | -                      isAnimation={isAnimation.value}
 | 
	
		
			
				|  |  | -                      text={props.item.title}
 | 
	
		
			
				|  |  | -                    />
 | 
	
		
			
				|  |  | -                  </span>
 | 
	
		
			
				|  |  | -                </div>
 | 
	
		
			
				|  |  | -                {/* 收藏 */}
 | 
	
		
			
				|  |  | -                <div class={styles.btnGroup}>
 | 
	
		
			
				|  |  | -                  {props.isDownload && (
 | 
	
		
			
				|  |  | -                    <div class={styles.btnItem} onClick={onDownload}>
 | 
	
		
			
				|  |  | -                      <NSpin show={downloadStatus.value} size={'small'}>
 | 
	
		
			
				|  |  | -                        <img
 | 
	
		
			
				|  |  | -                          src={iconDownload}
 | 
	
		
			
				|  |  | -                          key="3"
 | 
	
		
			
				|  |  | -                          class={[styles.iconCollect]}
 | 
	
		
			
				|  |  | -                        />
 | 
	
		
			
				|  |  | -                      </NSpin>
 | 
	
		
			
				|  |  | -                    </div>
 | 
	
		
			
				|  |  | -                  )}
 | 
	
		
			
				|  |  | -                  {props.isShowCollect && (
 | 
	
		
			
				|  |  | -                    <div
 | 
	
		
			
				|  |  | -                      class={[styles.iconCollect, styles.btnItem]}
 | 
	
		
			
				|  |  | -                      onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | -                        e.stopPropagation();
 | 
	
		
			
				|  |  | -                        e.preventDefault();
 | 
	
		
			
				|  |  | -                        // 判断是否可以收藏
 | 
	
		
			
				|  |  | -                        if (props.isCollect) {
 | 
	
		
			
				|  |  | -                          emit('collect', props.item);
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                      }}>
 | 
	
		
			
				|  |  | -                      <Transition name="favitor" mode="out-in">
 | 
	
		
			
				|  |  | -                        {props.item.isCollect ? (
 | 
	
		
			
				|  |  | -                          <img
 | 
	
		
			
				|  |  | -                            src={iconCollectActive}
 | 
	
		
			
				|  |  | -                            key="1"
 | 
	
		
			
				|  |  | -                            class={[
 | 
	
		
			
				|  |  | -                              styles.iconCollect,
 | 
	
		
			
				|  |  | -                              props.isCollect ? styles.isCollect : ''
 | 
	
		
			
				|  |  | -                            ]}
 | 
	
		
			
				|  |  | -                          />
 | 
	
		
			
				|  |  | -                        ) : (
 | 
	
		
			
				|  |  | -                          <img
 | 
	
		
			
				|  |  | -                            src={iconCollectDefault}
 | 
	
		
			
				|  |  | -                            key="2"
 | 
	
		
			
				|  |  | -                            class={[
 | 
	
		
			
				|  |  | -                              styles.iconCollect,
 | 
	
		
			
				|  |  | -                              props.isCollect ? styles.isCollect : ''
 | 
	
		
			
				|  |  | -                            ]}
 | 
	
		
			
				|  |  | -                          />
 | 
	
		
			
				|  |  | -                        )}
 | 
	
		
			
				|  |  | -                      </Transition>
 | 
	
		
			
				|  |  | -                    </div>
 | 
	
		
			
				|  |  | -                  )}
 | 
	
		
			
				|  |  | -                </div>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                {/* 精选 */}
 | 
	
		
			
				|  |  | -                {props.item.isSelected && (
 | 
	
		
			
				|  |  | -                  <span class={styles.iconSelected}></span>
 | 
	
		
			
				|  |  | -                )}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                {/* 添加按钮 */}
 | 
	
		
			
				|  |  | -                {props.isShowAdd &&
 | 
	
		
			
				|  |  | -                  (props.item.exist ? (
 | 
	
		
			
				|  |  | -                    <NButton
 | 
	
		
			
				|  |  | -                      type="primary"
 | 
	
		
			
				|  |  | -                      class={[
 | 
	
		
			
				|  |  | -                        styles.addBtn,
 | 
	
		
			
				|  |  | -                        props.item.exist ? styles.addBtnDisabled : ''
 | 
	
		
			
				|  |  | -                      ]}
 | 
	
		
			
				|  |  | -                      disabled={props.item.exist || props.isShowAddDisabled}
 | 
	
		
			
				|  |  | -                      onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | -                        e.stopPropagation();
 | 
	
		
			
				|  |  | -                        e.preventDefault();
 | 
	
		
			
				|  |  | -                        emit('add', props.item);
 | 
	
		
			
				|  |  | -                      }}>
 | 
	
		
			
				|  |  | -                      {props.item.exist ? '已添加' : '添加'}
 | 
	
		
			
				|  |  | -                    </NButton>
 | 
	
		
			
				|  |  | -                  ) : (
 | 
	
		
			
				|  |  | -                    !props.isShowAddDisabled && (
 | 
	
		
			
				|  |  | -                      <NButton
 | 
	
		
			
				|  |  | -                        type="primary"
 | 
	
		
			
				|  |  | -                        class={[
 | 
	
		
			
				|  |  | -                          styles.addBtn,
 | 
	
		
			
				|  |  | -                          props.item.exist ? styles.addBtnDisabled : ''
 | 
	
		
			
				|  |  | -                        ]}
 | 
	
		
			
				|  |  | -                        disabled={props.item.exist || props.isShowAddDisabled}
 | 
	
		
			
				|  |  | -                        onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | -                          e.stopPropagation();
 | 
	
		
			
				|  |  | -                          e.preventDefault();
 | 
	
		
			
				|  |  | -                          emit('add', props.item);
 | 
	
		
			
				|  |  | -                        }}>
 | 
	
		
			
				|  |  | -                        {props.item.exist ? '已添加' : '添加'}
 | 
	
		
			
				|  |  | -                      </NButton>
 | 
	
		
			
				|  |  | -                    )
 | 
	
		
			
				|  |  | -                  ))}
 | 
	
		
			
				|  |  | -              </div>
 | 
	
		
			
				|  |  | -            )
 | 
	
		
			
				|  |  | -          }}
 | 
	
		
			
				|  |  | -        </NCard>
 | 
	
		
			
				|  |  | -      </div>
 | 
	
		
			
				|  |  | -    );
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -});
 | 
	
		
			
				|  |  | +import { PropType, Transition, defineComponent, ref } from 'vue';
 | 
	
		
			
				|  |  | +import styles from './index.module.less';
 | 
	
		
			
				|  |  | +import {
 | 
	
		
			
				|  |  | +  ImageRenderToolbarProps,
 | 
	
		
			
				|  |  | +  NButton,
 | 
	
		
			
				|  |  | +  NCard,
 | 
	
		
			
				|  |  | +  NImage,
 | 
	
		
			
				|  |  | +  NModal,
 | 
	
		
			
				|  |  | +  NSpin,
 | 
	
		
			
				|  |  | +  useMessage
 | 
	
		
			
				|  |  | +} from 'naive-ui';
 | 
	
		
			
				|  |  | +import iconImage from '@common/images/icon-image.png';
 | 
	
		
			
				|  |  | +import iconVideo from '@common/images/icon-video.png';
 | 
	
		
			
				|  |  | +import iconAudio from '@common/images/icon-audio.png';
 | 
	
		
			
				|  |  | +import iconMusic from '@common/images/icon-music.png';
 | 
	
		
			
				|  |  | +import iconPPT from '@common/images/icon-ppt.png';
 | 
	
		
			
				|  |  | +import iconOther from '@common/images/icon-other.png';
 | 
	
		
			
				|  |  | +import iconCollectDefault from '@common/images/icon-collect-default.png';
 | 
	
		
			
				|  |  | +import iconCollectActive from '@common/images/icon-collect-active.png';
 | 
	
		
			
				|  |  | +import iconDownload from '@common/images/icon-download.png';
 | 
	
		
			
				|  |  | +import TheNoticeBar from '../TheNoticeBar';
 | 
	
		
			
				|  |  | +import AudioPlayer from './audio-player';
 | 
	
		
			
				|  |  | +import VideoPlayer from './video-player';
 | 
	
		
			
				|  |  | +import { PageEnum } from '/src/enums/pageEnum';
 | 
	
		
			
				|  |  | +import { api_musicSheetDetail } from '/src/api/user';
 | 
	
		
			
				|  |  | +import JSZip, { file } from 'jszip';
 | 
	
		
			
				|  |  | +import { saveAs } from 'file-saver';
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// LISTEN:听音,RHYTHM:节奏,THEORY:乐理知识,MUSIC_WIKI:曲目 INSTRUMENT:乐器 MUSICIAN:音乐家)
 | 
	
		
			
				|  |  | +type itemType = {
 | 
	
		
			
				|  |  | +  id: string | number;
 | 
	
		
			
				|  |  | +  type:
 | 
	
		
			
				|  |  | +    | 'IMG'
 | 
	
		
			
				|  |  | +    | 'VIDEO'
 | 
	
		
			
				|  |  | +    | 'SONG'
 | 
	
		
			
				|  |  | +    | 'MUSIC'
 | 
	
		
			
				|  |  | +    | 'PPT'
 | 
	
		
			
				|  |  | +    | 'LISTEN'
 | 
	
		
			
				|  |  | +    | 'RHYTHM'
 | 
	
		
			
				|  |  | +    | 'THEORY'
 | 
	
		
			
				|  |  | +    | 'MUSIC_WIKI'
 | 
	
		
			
				|  |  | +    | 'INSTRUMENT'
 | 
	
		
			
				|  |  | +    | 'MUSICIAN';
 | 
	
		
			
				|  |  | +  coverImg: string;
 | 
	
		
			
				|  |  | +  content?: string;
 | 
	
		
			
				|  |  | +  title: string;
 | 
	
		
			
				|  |  | +  isCollect: boolean;
 | 
	
		
			
				|  |  | +  isSelected: boolean; // 精选
 | 
	
		
			
				|  |  | +  exist?: boolean; // 是否已经选
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default defineComponent({
 | 
	
		
			
				|  |  | +  name: 'card-type',
 | 
	
		
			
				|  |  | +  props: {
 | 
	
		
			
				|  |  | +    // 是否是选中状态
 | 
	
		
			
				|  |  | +    isActive: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    /** 是否可以拖拽 */
 | 
	
		
			
				|  |  | +    draggable: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 是否可以收藏
 | 
	
		
			
				|  |  | +    isCollect: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: true
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 是否显示收藏
 | 
	
		
			
				|  |  | +    isShowCollect: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: true
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 是否显示添加按钮
 | 
	
		
			
				|  |  | +    isShowAdd: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 是否禁用添加按钮
 | 
	
		
			
				|  |  | +    isShowAddDisabled: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 鼠标移动上面的时候是否自动播放,或者可以点击
 | 
	
		
			
				|  |  | +    disabledMouseHover: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: true
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 是否预览
 | 
	
		
			
				|  |  | +    isPreview: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: true
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    item: {
 | 
	
		
			
				|  |  | +      type: Object as PropType<itemType>,
 | 
	
		
			
				|  |  | +      default: () => ({})
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    /** 是否下架 */
 | 
	
		
			
				|  |  | +    offShelf: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    /** 是否可以下载 */
 | 
	
		
			
				|  |  | +    isDownload: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: false
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * @type {string} click 点击事件
 | 
	
		
			
				|  |  | +   * @type {string} collect 收藏
 | 
	
		
			
				|  |  | +   * @type {string} add 添加
 | 
	
		
			
				|  |  | +   * @type {string} offShelf 下架
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  emits: ['click', 'collect', 'add', 'offShelf'],
 | 
	
		
			
				|  |  | +  setup(props, { emit }) {
 | 
	
		
			
				|  |  | +    const message = useMessage();
 | 
	
		
			
				|  |  | +    const isAnimation = ref(false);
 | 
	
		
			
				|  |  | +    const downloadStatus = ref(false);
 | 
	
		
			
				|  |  | +    const formatType = (type: string) => {
 | 
	
		
			
				|  |  | +      let typeImg = iconOther;
 | 
	
		
			
				|  |  | +      switch (type) {
 | 
	
		
			
				|  |  | +        case 'IMG':
 | 
	
		
			
				|  |  | +          typeImg = iconImage;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'VIDEO':
 | 
	
		
			
				|  |  | +          typeImg = iconVideo;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'SONG':
 | 
	
		
			
				|  |  | +          typeImg = iconAudio;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'MUSIC':
 | 
	
		
			
				|  |  | +          typeImg = iconMusic;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +        case 'PPT':
 | 
	
		
			
				|  |  | +          typeImg = iconPPT;
 | 
	
		
			
				|  |  | +          break;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      return typeImg;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 获取文件blob格式
 | 
	
		
			
				|  |  | +    const getFileBlob = (url: string) => {
 | 
	
		
			
				|  |  | +      return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | +        const request = new XMLHttpRequest();
 | 
	
		
			
				|  |  | +        request.open('GET', url, true);
 | 
	
		
			
				|  |  | +        request.responseType = 'blob';
 | 
	
		
			
				|  |  | +        request.onload = (res: any) => {
 | 
	
		
			
				|  |  | +          if (res.target.status == 200) {
 | 
	
		
			
				|  |  | +            resolve(res.target.response);
 | 
	
		
			
				|  |  | +          } else {
 | 
	
		
			
				|  |  | +            reject(res);
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        request.send();
 | 
	
		
			
				|  |  | +      });
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 多个文件下载
 | 
	
		
			
				|  |  | +    const downLoadMultiFile = (files: any, filesName: string) => {
 | 
	
		
			
				|  |  | +      const zip = new JSZip();
 | 
	
		
			
				|  |  | +      const result = [];
 | 
	
		
			
				|  |  | +      for (const i in files) {
 | 
	
		
			
				|  |  | +        const promise = getFileBlob(files[i].url).then((res: any) => {
 | 
	
		
			
				|  |  | +          zip.file(files[i].name, res, { binary: true });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +        result.push(promise);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      Promise.all(result)
 | 
	
		
			
				|  |  | +        .then(() => {
 | 
	
		
			
				|  |  | +          zip.generateAsync({ type: 'blob' }).then(res => {
 | 
	
		
			
				|  |  | +            saveAs(
 | 
	
		
			
				|  |  | +              res,
 | 
	
		
			
				|  |  | +              filesName
 | 
	
		
			
				|  |  | +                ? filesName + Date.now() + '.zip'
 | 
	
		
			
				|  |  | +                : `文件夹${Date.now()}.zip`
 | 
	
		
			
				|  |  | +            );
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        .catch(() => {
 | 
	
		
			
				|  |  | +          message.error('下载失败');
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      downloadStatus.value = false;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const downloadFile = (filename: string, fileUrl: string) => {
 | 
	
		
			
				|  |  | +      // 发起Fetch请求
 | 
	
		
			
				|  |  | +      fetch(fileUrl)
 | 
	
		
			
				|  |  | +        .then(response => response.blob())
 | 
	
		
			
				|  |  | +        .then(blob => {
 | 
	
		
			
				|  |  | +          saveAs(blob, filename);
 | 
	
		
			
				|  |  | +          setTimeout(() => {
 | 
	
		
			
				|  |  | +            downloadStatus.value = false;
 | 
	
		
			
				|  |  | +          }, 100);
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        .catch(() => {
 | 
	
		
			
				|  |  | +          message.error('下载失败');
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      downloadStatus.value = false;
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const getFileName = (url: any) => {
 | 
	
		
			
				|  |  | +      // 使用正则表达式获取文件名
 | 
	
		
			
				|  |  | +      const tempUrl = url.split('?');
 | 
	
		
			
				|  |  | +      const fileNameRegex = /\/([^\\/]+)$/; // 匹配最后一个斜杠后的内容
 | 
	
		
			
				|  |  | +      const match = tempUrl[0].match(fileNameRegex);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (match) {
 | 
	
		
			
				|  |  | +        return match[1];
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        return '';
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    const onDownload = async (e: MouseEvent) => {
 | 
	
		
			
				|  |  | +      e.stopPropagation();
 | 
	
		
			
				|  |  | +      e.preventDefault();
 | 
	
		
			
				|  |  | +      const item = props.item;
 | 
	
		
			
				|  |  | +      if (!item.content) {
 | 
	
		
			
				|  |  | +        message.error('下载失败');
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      if (downloadStatus.value) return false;
 | 
	
		
			
				|  |  | +      downloadStatus.value = true;
 | 
	
		
			
				|  |  | +      const suffix: any = item.content?.split('.');
 | 
	
		
			
				|  |  | +      const fileName = item.title + '.' + suffix[suffix?.length - 1];
 | 
	
		
			
				|  |  | +      if (item.type === 'MUSIC') {
 | 
	
		
			
				|  |  | +        const { data } = await api_musicSheetDetail(item.content);
 | 
	
		
			
				|  |  | +        const urls = [];
 | 
	
		
			
				|  |  | +        if (data.xmlFileUrl) {
 | 
	
		
			
				|  |  | +          urls.push({
 | 
	
		
			
				|  |  | +            url: data.xmlFileUrl,
 | 
	
		
			
				|  |  | +            name: getFileName(data.xmlFileUrl)
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        if (data.background && data.background.length > 0) {
 | 
	
		
			
				|  |  | +          data.background.forEach((item: any) => {
 | 
	
		
			
				|  |  | +            urls.push({
 | 
	
		
			
				|  |  | +              url: item.audioFileUrl,
 | 
	
		
			
				|  |  | +              name: getFileName(item.audioFileUrl)
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        downLoadMultiFile(urls, item.title);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // setTimeout(() => {
 | 
	
		
			
				|  |  | +        //   downloadStatus.value = false;
 | 
	
		
			
				|  |  | +        // }, 1000);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        downloadFile(fileName, item.content);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return () => (
 | 
	
		
			
				|  |  | +      <div
 | 
	
		
			
				|  |  | +        onClick={() => emit('click', props.item)}
 | 
	
		
			
				|  |  | +        key={props.item.id}
 | 
	
		
			
				|  |  | +        draggable={!props.draggable ? false : props.item.exist ? false : true}
 | 
	
		
			
				|  |  | +        class={[
 | 
	
		
			
				|  |  | +          styles['card-section'],
 | 
	
		
			
				|  |  | +          'card-section-container',
 | 
	
		
			
				|  |  | +          !props.draggable ? '' : props.item.exist ? '' : styles.cardDrag
 | 
	
		
			
				|  |  | +        ]}
 | 
	
		
			
				|  |  | +        onMouseenter={() => {
 | 
	
		
			
				|  |  | +          isAnimation.value = true;
 | 
	
		
			
				|  |  | +        }}
 | 
	
		
			
				|  |  | +        onMouseleave={() => {
 | 
	
		
			
				|  |  | +          isAnimation.value = false;
 | 
	
		
			
				|  |  | +        }}
 | 
	
		
			
				|  |  | +        onDragstart={(e: any) => {
 | 
	
		
			
				|  |  | +          console.log('dragstart', Date.now());
 | 
	
		
			
				|  |  | +          e.dataTransfer.setData('text', JSON.stringify(props.item));
 | 
	
		
			
				|  |  | +        }}>
 | 
	
		
			
				|  |  | +        {/* 判断是否下架 */}
 | 
	
		
			
				|  |  | +        {props.offShelf && (
 | 
	
		
			
				|  |  | +          <div class={styles.offShelfBg}>
 | 
	
		
			
				|  |  | +            <p class={styles.offShelfTips}>该资源已被下架</p>
 | 
	
		
			
				|  |  | +            <NButton
 | 
	
		
			
				|  |  | +              type="primary"
 | 
	
		
			
				|  |  | +              class={styles.offShelfBtn}
 | 
	
		
			
				|  |  | +              onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | +                e.stopPropagation();
 | 
	
		
			
				|  |  | +                emit('offShelf');
 | 
	
		
			
				|  |  | +              }}>
 | 
	
		
			
				|  |  | +              确认
 | 
	
		
			
				|  |  | +            </NButton>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        )}
 | 
	
		
			
				|  |  | +        <NCard
 | 
	
		
			
				|  |  | +          class={[
 | 
	
		
			
				|  |  | +            styles['card-section-content'],
 | 
	
		
			
				|  |  | +            props.isShowAdd ? '' : styles.course,
 | 
	
		
			
				|  |  | +            props.isActive ? styles.isActive : '',
 | 
	
		
			
				|  |  | +            props.item.exist ? styles.showAddBtn : '' // 是否已添加
 | 
	
		
			
				|  |  | +          ]}
 | 
	
		
			
				|  |  | +          style={{ cursor: 'pointer' }}>
 | 
	
		
			
				|  |  | +          {{
 | 
	
		
			
				|  |  | +            cover: () => (
 | 
	
		
			
				|  |  | +              <>
 | 
	
		
			
				|  |  | +                {/* 图片 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'IMG' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={props.disabledMouseHover}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg}
 | 
	
		
			
				|  |  | +                    previewSrc={props.item.content}
 | 
	
		
			
				|  |  | +                    renderToolbar={({ nodes }: ImageRenderToolbarProps) => {
 | 
	
		
			
				|  |  | +                      return [
 | 
	
		
			
				|  |  | +                        nodes.prev,
 | 
	
		
			
				|  |  | +                        nodes.next,
 | 
	
		
			
				|  |  | +                        nodes.rotateCounterclockwise,
 | 
	
		
			
				|  |  | +                        nodes.rotateClockwise,
 | 
	
		
			
				|  |  | +                        nodes.resizeToOriginalSize,
 | 
	
		
			
				|  |  | +                        nodes.zoomOut,
 | 
	
		
			
				|  |  | +                        nodes.close
 | 
	
		
			
				|  |  | +                      ];
 | 
	
		
			
				|  |  | +                    }}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 乐谱 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'MUSIC' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="contain"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 音频 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'SONG' && (
 | 
	
		
			
				|  |  | +                  <AudioPlayer
 | 
	
		
			
				|  |  | +                    content={props.item.content}
 | 
	
		
			
				|  |  | +                    cover={props.item.coverImg}
 | 
	
		
			
				|  |  | +                    previewDisabled={props.disabledMouseHover}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 视频 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'VIDEO' && (
 | 
	
		
			
				|  |  | +                  <VideoPlayer
 | 
	
		
			
				|  |  | +                    cover={props.item.coverImg}
 | 
	
		
			
				|  |  | +                    content={props.item.content}
 | 
	
		
			
				|  |  | +                    previewDisabled={props.disabledMouseHover}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* ppt */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'PPT' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg || PageEnum.PPT_DEFAULT_COVER}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 节奏练习 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'RHYTHM' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg || PageEnum.RHYTHM_DEFAULT_COVER}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                {/* 听音练习 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'LISTEN' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 乐理 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'THEORY' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg || PageEnum.THEORY_DEFAULT_COVER}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 名曲 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'MUSIC_WIKI' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg || PageEnum.MUSIC_DEFAULT_COVER}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 乐器 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'INSTRUMENT' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={
 | 
	
		
			
				|  |  | +                      props.item.coverImg || PageEnum.INSTRUMENT_DEFAULT_COVER
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +                {/* 音乐家 */}
 | 
	
		
			
				|  |  | +                {props.item.type === 'MUSICIAN' && (
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.cover, styles.image]}
 | 
	
		
			
				|  |  | +                    lazy
 | 
	
		
			
				|  |  | +                    previewDisabled={true}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                    src={props.item.coverImg || PageEnum.MUSICIAN_DEFAULT_COVER}
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +              </>
 | 
	
		
			
				|  |  | +            ),
 | 
	
		
			
				|  |  | +            footer: () => (
 | 
	
		
			
				|  |  | +              <div class={styles.footer}>
 | 
	
		
			
				|  |  | +                <div class={[styles.title, 'footerTitle']}>
 | 
	
		
			
				|  |  | +                  <NImage
 | 
	
		
			
				|  |  | +                    class={[styles.titleType]}
 | 
	
		
			
				|  |  | +                    src={formatType(props.item.type)}
 | 
	
		
			
				|  |  | +                    objectFit="cover"
 | 
	
		
			
				|  |  | +                  />
 | 
	
		
			
				|  |  | +                  <span class={[styles.titleContent, 'titleContent']}>
 | 
	
		
			
				|  |  | +                    <TheNoticeBar
 | 
	
		
			
				|  |  | +                      isAnimation={isAnimation.value}
 | 
	
		
			
				|  |  | +                      text={props.item.title}
 | 
	
		
			
				|  |  | +                    />
 | 
	
		
			
				|  |  | +                  </span>
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +                {/* 收藏 */}
 | 
	
		
			
				|  |  | +                <div class={styles.btnGroup}>
 | 
	
		
			
				|  |  | +                  {props.isDownload && (
 | 
	
		
			
				|  |  | +                    <div class={styles.btnItem} onClick={onDownload}>
 | 
	
		
			
				|  |  | +                      <NSpin show={downloadStatus.value} size={'small'}>
 | 
	
		
			
				|  |  | +                        <img
 | 
	
		
			
				|  |  | +                          src={iconDownload}
 | 
	
		
			
				|  |  | +                          key="3"
 | 
	
		
			
				|  |  | +                          class={[styles.iconCollect]}
 | 
	
		
			
				|  |  | +                        />
 | 
	
		
			
				|  |  | +                      </NSpin>
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  | +                  )}
 | 
	
		
			
				|  |  | +                  {props.isShowCollect && (
 | 
	
		
			
				|  |  | +                    <div
 | 
	
		
			
				|  |  | +                      class={[styles.iconCollect, styles.btnItem]}
 | 
	
		
			
				|  |  | +                      onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | +                        e.stopPropagation();
 | 
	
		
			
				|  |  | +                        e.preventDefault();
 | 
	
		
			
				|  |  | +                        // 判断是否可以收藏
 | 
	
		
			
				|  |  | +                        if (props.isCollect) {
 | 
	
		
			
				|  |  | +                          emit('collect', props.item);
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                      }}>
 | 
	
		
			
				|  |  | +                      <Transition name="favitor" mode="out-in">
 | 
	
		
			
				|  |  | +                        {props.item.isCollect ? (
 | 
	
		
			
				|  |  | +                          <img
 | 
	
		
			
				|  |  | +                            src={iconCollectActive}
 | 
	
		
			
				|  |  | +                            key="1"
 | 
	
		
			
				|  |  | +                            class={[
 | 
	
		
			
				|  |  | +                              styles.iconCollect,
 | 
	
		
			
				|  |  | +                              props.isCollect ? styles.isCollect : ''
 | 
	
		
			
				|  |  | +                            ]}
 | 
	
		
			
				|  |  | +                          />
 | 
	
		
			
				|  |  | +                        ) : (
 | 
	
		
			
				|  |  | +                          <img
 | 
	
		
			
				|  |  | +                            src={iconCollectDefault}
 | 
	
		
			
				|  |  | +                            key="2"
 | 
	
		
			
				|  |  | +                            class={[
 | 
	
		
			
				|  |  | +                              styles.iconCollect,
 | 
	
		
			
				|  |  | +                              props.isCollect ? styles.isCollect : ''
 | 
	
		
			
				|  |  | +                            ]}
 | 
	
		
			
				|  |  | +                          />
 | 
	
		
			
				|  |  | +                        )}
 | 
	
		
			
				|  |  | +                      </Transition>
 | 
	
		
			
				|  |  | +                    </div>
 | 
	
		
			
				|  |  | +                  )}
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                {/* 精选 */}
 | 
	
		
			
				|  |  | +                {props.item.isSelected && (
 | 
	
		
			
				|  |  | +                  <span class={styles.iconSelected}></span>
 | 
	
		
			
				|  |  | +                )}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                {/* 添加按钮 */}
 | 
	
		
			
				|  |  | +                {props.isShowAdd &&
 | 
	
		
			
				|  |  | +                  (props.item.exist ? (
 | 
	
		
			
				|  |  | +                    <NButton
 | 
	
		
			
				|  |  | +                      type="primary"
 | 
	
		
			
				|  |  | +                      class={[
 | 
	
		
			
				|  |  | +                        styles.addBtn,
 | 
	
		
			
				|  |  | +                        props.item.exist ? styles.addBtnDisabled : ''
 | 
	
		
			
				|  |  | +                      ]}
 | 
	
		
			
				|  |  | +                      disabled={props.item.exist || props.isShowAddDisabled}
 | 
	
		
			
				|  |  | +                      onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | +                        e.stopPropagation();
 | 
	
		
			
				|  |  | +                        e.preventDefault();
 | 
	
		
			
				|  |  | +                        emit('add', props.item);
 | 
	
		
			
				|  |  | +                      }}>
 | 
	
		
			
				|  |  | +                      {props.item.exist ? '已添加' : '添加'}
 | 
	
		
			
				|  |  | +                    </NButton>
 | 
	
		
			
				|  |  | +                  ) : (
 | 
	
		
			
				|  |  | +                    !props.isShowAddDisabled && (
 | 
	
		
			
				|  |  | +                      <NButton
 | 
	
		
			
				|  |  | +                        type="primary"
 | 
	
		
			
				|  |  | +                        class={[
 | 
	
		
			
				|  |  | +                          styles.addBtn,
 | 
	
		
			
				|  |  | +                          props.item.exist ? styles.addBtnDisabled : ''
 | 
	
		
			
				|  |  | +                        ]}
 | 
	
		
			
				|  |  | +                        disabled={props.item.exist || props.isShowAddDisabled}
 | 
	
		
			
				|  |  | +                        onClick={(e: MouseEvent) => {
 | 
	
		
			
				|  |  | +                          e.stopPropagation();
 | 
	
		
			
				|  |  | +                          e.preventDefault();
 | 
	
		
			
				|  |  | +                          emit('add', props.item);
 | 
	
		
			
				|  |  | +                        }}>
 | 
	
		
			
				|  |  | +                        {props.item.exist ? '已添加' : '添加'}
 | 
	
		
			
				|  |  | +                      </NButton>
 | 
	
		
			
				|  |  | +                    )
 | 
	
		
			
				|  |  | +                  ))}
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +          }}
 | 
	
		
			
				|  |  | +        </NCard>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +});
 |