|  | @@ -0,0 +1,654 @@
 | 
	
		
			
				|  |  | +<!-- 弹窗列表 -->
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +  <div class="musicwikiList">
 | 
	
		
			
				|  |  | +    <div class="headCon">
 | 
	
		
			
				|  |  | +      <div class="headLeft">
 | 
	
		
			
				|  |  | +        <img class="tipImg" :src="tipImgObj[type]" alt="" />
 | 
	
		
			
				|  |  | +        <div class="title">{{ titObj[type] }}</div>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +      <div class="headright">
 | 
	
		
			
				|  |  | +        <img @click="emits('close')" class="closeBtn" src="../../cloudCoachElement/cloudCoachList/imgs/close.png" alt="" />
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    </div>
 | 
	
		
			
				|  |  | +    <div class="content">
 | 
	
		
			
				|  |  | +      <div class="tabTools">
 | 
	
		
			
				|  |  | +        <div class="tabBox">
 | 
	
		
			
				|  |  | +          <div class="tabCon" ref="tabConDom" @wheel.prevent="handleMousewheelTabCon">
 | 
	
		
			
				|  |  | +            <div
 | 
	
		
			
				|  |  | +              class="tab"
 | 
	
		
			
				|  |  | +              @click="handleResourcesTypeChange(item)"
 | 
	
		
			
				|  |  | +              :class="{ active: item.id === queryData.resourcesType }"
 | 
	
		
			
				|  |  | +              v-for="item in resourcesTypeOption"
 | 
	
		
			
				|  |  | +              :key="item.id"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              {{ item.name }}
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div v-if="horizontalScrollbar" class="tabChangeCon">
 | 
	
		
			
				|  |  | +            <div class="tabChangeLeft" @click="handleScrollTabCon(-150)"></div>
 | 
	
		
			
				|  |  | +            <div class="tabChangeRight" @click="handleScrollTabCon(150)"></div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <div class="query">
 | 
	
		
			
				|  |  | +          <Input :placeholder="'请输入搜索关键词'" v-model:value="queryData.keyword" clearable @enter="handleQuery" @clear="handleQuery">
 | 
	
		
			
				|  |  | +            <template #prefix>
 | 
	
		
			
				|  |  | +              <img class="img" src="../../cloudCoachElement/cloudCoachList/imgs/query.png" alt="" />
 | 
	
		
			
				|  |  | +            </template>
 | 
	
		
			
				|  |  | +            <template #suffix>
 | 
	
		
			
				|  |  | +              <div class="queryBtn" @click="handleQuery">搜索</div>
 | 
	
		
			
				|  |  | +            </template>
 | 
	
		
			
				|  |  | +          </Input>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +      <div class="musicListCon">
 | 
	
		
			
				|  |  | +        <div class="queryFrom">
 | 
	
		
			
				|  |  | +          <div class="queryFromList" v-if="classificationOption.length">
 | 
	
		
			
				|  |  | +            <div class="tit">分类:</div>
 | 
	
		
			
				|  |  | +            <div class="queryFromCon">
 | 
	
		
			
				|  |  | +              <div
 | 
	
		
			
				|  |  | +                @click="handleClassificationChange(item)"
 | 
	
		
			
				|  |  | +                v-for="item in classificationOption"
 | 
	
		
			
				|  |  | +                :key="item.id"
 | 
	
		
			
				|  |  | +                :class="['queryTip', queryData.classification === item.id && 'active']"
 | 
	
		
			
				|  |  | +              >
 | 
	
		
			
				|  |  | +                {{ item.name }}
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="queryFromList" v-if="typeOption.length">
 | 
	
		
			
				|  |  | +            <div class="tit">类型:</div>
 | 
	
		
			
				|  |  | +            <div class="queryFromCon">
 | 
	
		
			
				|  |  | +              <template v-for="item in typeOption">
 | 
	
		
			
				|  |  | +                <div
 | 
	
		
			
				|  |  | +                  :class="['queryTip', queryData.type.id === item.id && 'active']"
 | 
	
		
			
				|  |  | +                  @click="handleTypeChange(item)"
 | 
	
		
			
				|  |  | +                  v-if="item.childrenList.length === 0"
 | 
	
		
			
				|  |  | +                  :key="item.id"
 | 
	
		
			
				|  |  | +                >
 | 
	
		
			
				|  |  | +                  {{ item.name }}
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +                <Popover v-model:value="item.isExpand" trigger="mouseenter" v-else :offset="-4" :key="item.id + '_'">
 | 
	
		
			
				|  |  | +                  <template #content>
 | 
	
		
			
				|  |  | +                    <PopoverMenuItem
 | 
	
		
			
				|  |  | +                      @click="
 | 
	
		
			
				|  |  | +                        () => {
 | 
	
		
			
				|  |  | +                          handleTypeChange(row)
 | 
	
		
			
				|  |  | +                          item.isExpand = false
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                      "
 | 
	
		
			
				|  |  | +                      v-for="row in item.childrenList"
 | 
	
		
			
				|  |  | +                      :key="row.id"
 | 
	
		
			
				|  |  | +                      :active="row.id === queryData.type.id"
 | 
	
		
			
				|  |  | +                      >{{ row.name }}</PopoverMenuItem
 | 
	
		
			
				|  |  | +                    >
 | 
	
		
			
				|  |  | +                  </template>
 | 
	
		
			
				|  |  | +                  <div class="queryTip" :class="{ hoverActive: isActiveSubjectPop(item) }">
 | 
	
		
			
				|  |  | +                    <div>{{ queryData.type.id !== item.id && isActiveSubjectPop(item) ? queryData.type.name : item.name }}</div>
 | 
	
		
			
				|  |  | +                    <img src="../../cloudCoachElement/cloudCoachList/imgs/jt.png" alt="" />
 | 
	
		
			
				|  |  | +                  </div>
 | 
	
		
			
				|  |  | +                </Popover>
 | 
	
		
			
				|  |  | +              </template>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +        <div class="musicListConBox" v-loading="loading">
 | 
	
		
			
				|  |  | +          <div class="musicList" :class="{ empty: !musicList.length && !loading }">
 | 
	
		
			
				|  |  | +            <template v-if="musicList.length && !loading">
 | 
	
		
			
				|  |  | +              <musicListVue :musicList="musicList" @handle-add="handleAdd" @handle-preview="handlePreview" v-if="type === 'MUSIC'" />
 | 
	
		
			
				|  |  | +              <musicianListVue :musicList="musicList" @handle-add="handleAdd" @handle-preview="handlePreview" v-else-if="type === 'MUSICIAN'" />
 | 
	
		
			
				|  |  | +              <instrumentListVue :musicList="musicList" @handle-add="handleAdd" @handle-preview="handlePreview" v-else />
 | 
	
		
			
				|  |  | +            </template>
 | 
	
		
			
				|  |  | +            <Empty v-if="!musicList.length && !loading" />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="pagination" v-show="musicList.length">
 | 
	
		
			
				|  |  | +            <el-pagination
 | 
	
		
			
				|  |  | +              layout="prev, pager, next"
 | 
	
		
			
				|  |  | +              :default-page-size="queryData.rows"
 | 
	
		
			
				|  |  | +              :current-page="queryData.page"
 | 
	
		
			
				|  |  | +              @current-change="handleCurrentChange"
 | 
	
		
			
				|  |  | +              :total="queryData.total"
 | 
	
		
			
				|  |  | +            />
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    </div>
 | 
	
		
			
				|  |  | +  </div>
 | 
	
		
			
				|  |  | +  <Modal
 | 
	
		
			
				|  |  | +    :contentStyle="{
 | 
	
		
			
				|  |  | +      width: '70%',
 | 
	
		
			
				|  |  | +      minWidth: '1200px',
 | 
	
		
			
				|  |  | +      height: '86%',
 | 
	
		
			
				|  |  | +      boxShadow: '0px 2px 10px 0px rgba(0,0,0,0.08)',
 | 
	
		
			
				|  |  | +      borderRadius: '16px',
 | 
	
		
			
				|  |  | +      border: '1px solid #DEDEDE',
 | 
	
		
			
				|  |  | +      padding: '0'
 | 
	
		
			
				|  |  | +    }"
 | 
	
		
			
				|  |  | +    v-model:visible="previewMusicObjVisible"
 | 
	
		
			
				|  |  | +  >
 | 
	
		
			
				|  |  | +    <musicPreview
 | 
	
		
			
				|  |  | +      :musicObj="previewMusicObj"
 | 
	
		
			
				|  |  | +      :type="type"
 | 
	
		
			
				|  |  | +      @close="
 | 
	
		
			
				|  |  | +        () => {
 | 
	
		
			
				|  |  | +          previewMusicObjVisible = false
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      "
 | 
	
		
			
				|  |  | +    />
 | 
	
		
			
				|  |  | +  </Modal>
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<script setup lang="ts">
 | 
	
		
			
				|  |  | +import { getKnowledgeWikiCategoryType, getKnowledgeWikiPage } from "@/api/musicResources"
 | 
	
		
			
				|  |  | +import { ElLoading, ElPagination } from "element-plus"
 | 
	
		
			
				|  |  | +import Input from "@/components/Input.vue"
 | 
	
		
			
				|  |  | +import Popover from "@/components/Popover.vue"
 | 
	
		
			
				|  |  | +import PopoverMenuItem from "@/components/PopoverMenuItem.vue"
 | 
	
		
			
				|  |  | +import Empty from "@/components/Empty"
 | 
	
		
			
				|  |  | +import Modal from "@/components/Modal.vue"
 | 
	
		
			
				|  |  | +import { httpAjax } from "@/plugins/httpAjax"
 | 
	
		
			
				|  |  | +import { reactive, ref, nextTick } from "vue"
 | 
	
		
			
				|  |  | +import musicPreview from "./musicPreview.vue"
 | 
	
		
			
				|  |  | +import mqjsImg from "@/views/Editor/CanvasTool/imgs/mqjs.png"
 | 
	
		
			
				|  |  | +import yyjImg from "@/views/Editor/CanvasTool/imgs/yyj.png"
 | 
	
		
			
				|  |  | +import yqbkImg from "@/views/Editor/CanvasTool/imgs/yqbk.png"
 | 
	
		
			
				|  |  | +import { CODE_ERR_CANCELED } from "@/libs/auth"
 | 
	
		
			
				|  |  | +import musicListVue from "./components/musicList.vue"
 | 
	
		
			
				|  |  | +import musicianListVue from "./components/musicianList.vue"
 | 
	
		
			
				|  |  | +import instrumentListVue from "./components/instrumentList.vue"
 | 
	
		
			
				|  |  | +import { type pptContentType } from "@/views/components/element/musicResourcesElement"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const props = defineProps<{
 | 
	
		
			
				|  |  | +  type: Exclude<pptContentType, "THEORY">
 | 
	
		
			
				|  |  | +}>()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const emits = defineEmits<{
 | 
	
		
			
				|  |  | +  (event: "update", item: Record<string, any>, type: Exclude<pptContentType, "THEORY">): void
 | 
	
		
			
				|  |  | +  (event: "close"): void
 | 
	
		
			
				|  |  | +}>()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const titObj = {
 | 
	
		
			
				|  |  | +  MUSIC: "名曲鉴赏",
 | 
	
		
			
				|  |  | +  INSTRUMENT: "乐器百科",
 | 
	
		
			
				|  |  | +  MUSICIAN: "音乐家"
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +const tipImgObj = {
 | 
	
		
			
				|  |  | +  MUSIC: mqjsImg,
 | 
	
		
			
				|  |  | +  INSTRUMENT: yqbkImg,
 | 
	
		
			
				|  |  | +  MUSICIAN: yyjImg
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const musicList = ref<any[]>([])
 | 
	
		
			
				|  |  | +const loading = ref(true)
 | 
	
		
			
				|  |  | +const vLoading = ElLoading.directive
 | 
	
		
			
				|  |  | +// 资源类型
 | 
	
		
			
				|  |  | +const resourcesTypeOption = ref<any[]>([])
 | 
	
		
			
				|  |  | +const classificationOption = ref<any[]>([])
 | 
	
		
			
				|  |  | +const typeOption = ref<any[]>([])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 不同类型 每页显示不同的数量
 | 
	
		
			
				|  |  | +const pageRowObj = {
 | 
	
		
			
				|  |  | +  MUSIC: 21,
 | 
	
		
			
				|  |  | +  INSTRUMENT: 24,
 | 
	
		
			
				|  |  | +  MUSICIAN: 24
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const queryData = reactive({
 | 
	
		
			
				|  |  | +  page: 1,
 | 
	
		
			
				|  |  | +  rows: pageRowObj[props.type],
 | 
	
		
			
				|  |  | +  total: 0,
 | 
	
		
			
				|  |  | +  keyword: "",
 | 
	
		
			
				|  |  | +  resourcesType: "",
 | 
	
		
			
				|  |  | +  classification: "",
 | 
	
		
			
				|  |  | +  type: {
 | 
	
		
			
				|  |  | +    id: "",
 | 
	
		
			
				|  |  | +    name: ""
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +getQueryList()
 | 
	
		
			
				|  |  | +function getQueryList() {
 | 
	
		
			
				|  |  | +  httpAjax(getKnowledgeWikiCategoryType, props.type).then(res => {
 | 
	
		
			
				|  |  | +    if (res.code === 200) {
 | 
	
		
			
				|  |  | +      resourcesTypeOption.value = res.data?.rows || []
 | 
	
		
			
				|  |  | +      // 初始化第三层数据
 | 
	
		
			
				|  |  | +      resourcesTypeOption.value.map(item => {
 | 
	
		
			
				|  |  | +        item.childrenList?.map((itemVal: any) => {
 | 
	
		
			
				|  |  | +          itemVal.childrenList?.map((itemV: any) => {
 | 
	
		
			
				|  |  | +            if (itemV.childrenList?.length > 0) {
 | 
	
		
			
				|  |  | +              itemV.childrenList = [
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                  id: itemV.id,
 | 
	
		
			
				|  |  | +                  name: "全部",
 | 
	
		
			
				|  |  | +                  childrenList: []
 | 
	
		
			
				|  |  | +                },
 | 
	
		
			
				|  |  | +                ...itemV.childrenList
 | 
	
		
			
				|  |  | +              ]
 | 
	
		
			
				|  |  | +              Object.assign(itemV, { isExpand: ref(false) })
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          })
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +      handleResourcesTypeChange(resourcesTypeOption.value[0])
 | 
	
		
			
				|  |  | +      // 判断 有没有滚动条
 | 
	
		
			
				|  |  | +      nextTick(() => {
 | 
	
		
			
				|  |  | +        hasHorizontalScrollbar()
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleResourcesTypeChange(item: Record<string, any>) {
 | 
	
		
			
				|  |  | +  queryData.resourcesType = item.id
 | 
	
		
			
				|  |  | +  classificationOption.value = []
 | 
	
		
			
				|  |  | +  queryData.classification = ""
 | 
	
		
			
				|  |  | +  typeOption.value = []
 | 
	
		
			
				|  |  | +  queryData.type = {
 | 
	
		
			
				|  |  | +    id: "",
 | 
	
		
			
				|  |  | +    name: ""
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (item.childrenList?.length) {
 | 
	
		
			
				|  |  | +    classificationOption.value = [
 | 
	
		
			
				|  |  | +      {
 | 
	
		
			
				|  |  | +        id: item.id,
 | 
	
		
			
				|  |  | +        name: "全部",
 | 
	
		
			
				|  |  | +        childrenList: []
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      ...item.childrenList
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  | +    queryData.classification = item.id
 | 
	
		
			
				|  |  | +    handleClassificationChange(classificationOption.value[0])
 | 
	
		
			
				|  |  | +    return
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  handleQuery()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleClassificationChange(item: Record<string, any>) {
 | 
	
		
			
				|  |  | +  queryData.classification = item.id
 | 
	
		
			
				|  |  | +  typeOption.value = []
 | 
	
		
			
				|  |  | +  queryData.type = {
 | 
	
		
			
				|  |  | +    id: "",
 | 
	
		
			
				|  |  | +    name: ""
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (item.childrenList?.length) {
 | 
	
		
			
				|  |  | +    typeOption.value = [
 | 
	
		
			
				|  |  | +      {
 | 
	
		
			
				|  |  | +        id: item.id,
 | 
	
		
			
				|  |  | +        name: "全部",
 | 
	
		
			
				|  |  | +        childrenList: []
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      ...item.childrenList
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  | +    handleTypeChange(typeOption.value[0])
 | 
	
		
			
				|  |  | +    return
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  handleQuery()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleTypeChange(item: Record<string, any>) {
 | 
	
		
			
				|  |  | +  queryData.type = {
 | 
	
		
			
				|  |  | +    id: item.id,
 | 
	
		
			
				|  |  | +    name: item.name
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  handleQuery()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +function isActiveSubjectPop(item: any) {
 | 
	
		
			
				|  |  | +  return item.childrenList.some((i: any) => {
 | 
	
		
			
				|  |  | +    return i.id === queryData.type.id
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleCurrentChange(e: number) {
 | 
	
		
			
				|  |  | +  queryData.page = e
 | 
	
		
			
				|  |  | +  handleGetQuery()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +function handleQuery() {
 | 
	
		
			
				|  |  | +  queryData.page = 1
 | 
	
		
			
				|  |  | +  queryData.rows = pageRowObj[props.type]
 | 
	
		
			
				|  |  | +  handleGetQuery()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +let controller: AbortController
 | 
	
		
			
				|  |  | +function handleGetQuery() {
 | 
	
		
			
				|  |  | +  loading.value = true
 | 
	
		
			
				|  |  | +  let { page, rows, keyword, resourcesType, classification, type } = queryData
 | 
	
		
			
				|  |  | +  const wikiCategoryId = type.id || classification || resourcesType
 | 
	
		
			
				|  |  | +  const params = {
 | 
	
		
			
				|  |  | +    keyword,
 | 
	
		
			
				|  |  | +    page,
 | 
	
		
			
				|  |  | +    rows,
 | 
	
		
			
				|  |  | +    type: props.type,
 | 
	
		
			
				|  |  | +    wikiCategoryId
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (controller) {
 | 
	
		
			
				|  |  | +    controller.abort()
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  controller = new AbortController()
 | 
	
		
			
				|  |  | +  httpAjax(getKnowledgeWikiPage, params, controller).then(res => {
 | 
	
		
			
				|  |  | +    // 自己关闭的时候不取消加载
 | 
	
		
			
				|  |  | +    if (res.code === CODE_ERR_CANCELED) {
 | 
	
		
			
				|  |  | +      return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (res.code === 200) {
 | 
	
		
			
				|  |  | +      musicList.value = res.data.rows.map((item: any) => {
 | 
	
		
			
				|  |  | +        item.highName = highlightedText(item.name, queryData.keyword)
 | 
	
		
			
				|  |  | +        return item
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +      queryData.total = res.data.total
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    loading.value = false
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +const highlightedText = (text: string, query: string) => {
 | 
	
		
			
				|  |  | +  if (!text) {
 | 
	
		
			
				|  |  | +    return ""
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (!query) {
 | 
	
		
			
				|  |  | +    return text
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  const regex = new RegExp(`(${query})`, "gi")
 | 
	
		
			
				|  |  | +  return text.replace(regex, '<span class="highlighted">$1</span>')
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 预览 */
 | 
	
		
			
				|  |  | +const previewMusicObjVisible = ref(false)
 | 
	
		
			
				|  |  | +const previewMusicObj = ref<Record<string, any>>({
 | 
	
		
			
				|  |  | +  id: "",
 | 
	
		
			
				|  |  | +  name: ""
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +function handlePreview(item: Record<string, any>) {
 | 
	
		
			
				|  |  | +  previewMusicObj.value.id = item.id
 | 
	
		
			
				|  |  | +  previewMusicObj.value.name = item.name
 | 
	
		
			
				|  |  | +  previewMusicObjVisible.value = true
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +function handleAdd(item: Record<string, any>) {
 | 
	
		
			
				|  |  | +  emits("update", item, props.type)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 横向拖动
 | 
	
		
			
				|  |  | +const tabConDom = ref<HTMLElement>()
 | 
	
		
			
				|  |  | +const horizontalScrollbar = ref(false)
 | 
	
		
			
				|  |  | +function handleMousewheelTabCon(event: WheelEvent) {
 | 
	
		
			
				|  |  | +  handleScrollTabCon(event.deltaY)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +function handleScrollTabCon(num: number) {
 | 
	
		
			
				|  |  | +  tabConDom.value?.scrollBy(num, 0)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +function hasHorizontalScrollbar() {
 | 
	
		
			
				|  |  | +  if (tabConDom.value) {
 | 
	
		
			
				|  |  | +    horizontalScrollbar.value = tabConDom.value.scrollWidth > tabConDom.value.clientWidth
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</script>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<style lang="scss" scoped>
 | 
	
		
			
				|  |  | +.musicwikiList {
 | 
	
		
			
				|  |  | +  width: 100%;
 | 
	
		
			
				|  |  | +  height: 100%;
 | 
	
		
			
				|  |  | +  .headCon {
 | 
	
		
			
				|  |  | +    width: 100%;
 | 
	
		
			
				|  |  | +    height: 64px;
 | 
	
		
			
				|  |  | +    border-bottom: 1px solid #eaeaea;
 | 
	
		
			
				|  |  | +    display: flex;
 | 
	
		
			
				|  |  | +    justify-content: space-between;
 | 
	
		
			
				|  |  | +    align-items: center;
 | 
	
		
			
				|  |  | +    .headLeft {
 | 
	
		
			
				|  |  | +      margin-left: 30px;
 | 
	
		
			
				|  |  | +      display: flex;
 | 
	
		
			
				|  |  | +      align-items: center;
 | 
	
		
			
				|  |  | +      .tipImg {
 | 
	
		
			
				|  |  | +        width: 24px;
 | 
	
		
			
				|  |  | +        height: 24px;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      .title {
 | 
	
		
			
				|  |  | +        font-weight: 600;
 | 
	
		
			
				|  |  | +        font-size: 18px;
 | 
	
		
			
				|  |  | +        color: #131415;
 | 
	
		
			
				|  |  | +        margin-left: 8px;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    .headright {
 | 
	
		
			
				|  |  | +      margin-right: 30px;
 | 
	
		
			
				|  |  | +      display: flex;
 | 
	
		
			
				|  |  | +      align-items: center;
 | 
	
		
			
				|  |  | +      .closeBtn {
 | 
	
		
			
				|  |  | +        width: 24px;
 | 
	
		
			
				|  |  | +        height: 24px;
 | 
	
		
			
				|  |  | +        cursor: pointer;
 | 
	
		
			
				|  |  | +        &:hover {
 | 
	
		
			
				|  |  | +          opacity: 0.8;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  .content {
 | 
	
		
			
				|  |  | +    width: 100%;
 | 
	
		
			
				|  |  | +    height: calc(100% - 64px);
 | 
	
		
			
				|  |  | +    display: flex;
 | 
	
		
			
				|  |  | +    flex-direction: column;
 | 
	
		
			
				|  |  | +    .tabTools {
 | 
	
		
			
				|  |  | +      height: 72px;
 | 
	
		
			
				|  |  | +      width: 100%;
 | 
	
		
			
				|  |  | +      padding: 18px 30px;
 | 
	
		
			
				|  |  | +      display: flex;
 | 
	
		
			
				|  |  | +      justify-content: space-between;
 | 
	
		
			
				|  |  | +      align-items: center;
 | 
	
		
			
				|  |  | +      .tabBox {
 | 
	
		
			
				|  |  | +        display: flex;
 | 
	
		
			
				|  |  | +        margin-right: 20px;
 | 
	
		
			
				|  |  | +        .tabCon {
 | 
	
		
			
				|  |  | +          display: flex;
 | 
	
		
			
				|  |  | +          overflow-x: auto;
 | 
	
		
			
				|  |  | +          &::-webkit-scrollbar {
 | 
	
		
			
				|  |  | +            display: none;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          .tab {
 | 
	
		
			
				|  |  | +            flex-shrink: 0;
 | 
	
		
			
				|  |  | +            margin-right: 32px;
 | 
	
		
			
				|  |  | +            font-weight: 400;
 | 
	
		
			
				|  |  | +            font-size: 16px;
 | 
	
		
			
				|  |  | +            color: #8b8d98;
 | 
	
		
			
				|  |  | +            line-height: 22px;
 | 
	
		
			
				|  |  | +            cursor: pointer;
 | 
	
		
			
				|  |  | +            &:hover {
 | 
	
		
			
				|  |  | +              opacity: 0.8;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            &:last-child {
 | 
	
		
			
				|  |  | +              margin-right: 0;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            &.active {
 | 
	
		
			
				|  |  | +              font-weight: 600;
 | 
	
		
			
				|  |  | +              color: #131415;
 | 
	
		
			
				|  |  | +              position: relative;
 | 
	
		
			
				|  |  | +              &::after {
 | 
	
		
			
				|  |  | +                content: "";
 | 
	
		
			
				|  |  | +                position: absolute;
 | 
	
		
			
				|  |  | +                width: 100%;
 | 
	
		
			
				|  |  | +                height: 10px;
 | 
	
		
			
				|  |  | +                background: linear-gradient(90deg, #77bbff 0%, rgba(163, 231, 255, 0.22) 100%);
 | 
	
		
			
				|  |  | +                bottom: 0;
 | 
	
		
			
				|  |  | +                left: 0;
 | 
	
		
			
				|  |  | +                z-index: -1;
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        .tabChangeCon {
 | 
	
		
			
				|  |  | +          margin-left: 16px;
 | 
	
		
			
				|  |  | +          flex-shrink: 0;
 | 
	
		
			
				|  |  | +          display: flex;
 | 
	
		
			
				|  |  | +          .tabChangeLeft {
 | 
	
		
			
				|  |  | +            width: 24px;
 | 
	
		
			
				|  |  | +            height: 24px;
 | 
	
		
			
				|  |  | +            background: url("./imgs/btnLeft.png") no-repeat;
 | 
	
		
			
				|  |  | +            background-size: 100% 100%;
 | 
	
		
			
				|  |  | +            cursor: pointer;
 | 
	
		
			
				|  |  | +            &:hover {
 | 
	
		
			
				|  |  | +              opacity: 0.8;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          .tabChangeRight {
 | 
	
		
			
				|  |  | +            margin-left: 16px;
 | 
	
		
			
				|  |  | +            width: 24px;
 | 
	
		
			
				|  |  | +            height: 24px;
 | 
	
		
			
				|  |  | +            background: url("./imgs/btnRight..png") no-repeat;
 | 
	
		
			
				|  |  | +            background-size: 100% 100%;
 | 
	
		
			
				|  |  | +            cursor: pointer;
 | 
	
		
			
				|  |  | +            &:hover {
 | 
	
		
			
				|  |  | +              opacity: 0.8;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      .query {
 | 
	
		
			
				|  |  | +        width: 400px;
 | 
	
		
			
				|  |  | +        height: 36px;
 | 
	
		
			
				|  |  | +        flex-shrink: 0;
 | 
	
		
			
				|  |  | +        &::v-deep(.input) {
 | 
	
		
			
				|  |  | +          align-items: center;
 | 
	
		
			
				|  |  | +          padding: 0 3px 0 12px;
 | 
	
		
			
				|  |  | +          border-radius: 18px;
 | 
	
		
			
				|  |  | +          height: 100%;
 | 
	
		
			
				|  |  | +          &:not(.disabled):hover,
 | 
	
		
			
				|  |  | +          &.focused {
 | 
	
		
			
				|  |  | +            .img {
 | 
	
		
			
				|  |  | +              opacity: 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            .queryBtn {
 | 
	
		
			
				|  |  | +              opacity: 1;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          input {
 | 
	
		
			
				|  |  | +            font-size: 14px;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          .img {
 | 
	
		
			
				|  |  | +            width: 16px;
 | 
	
		
			
				|  |  | +            height: 16px;
 | 
	
		
			
				|  |  | +            opacity: 0.4;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          .queryBtn {
 | 
	
		
			
				|  |  | +            width: 60px;
 | 
	
		
			
				|  |  | +            height: 30px;
 | 
	
		
			
				|  |  | +            background: #198cfe;
 | 
	
		
			
				|  |  | +            border-radius: 16px;
 | 
	
		
			
				|  |  | +            font-weight: 500;
 | 
	
		
			
				|  |  | +            font-size: 14px;
 | 
	
		
			
				|  |  | +            color: #ffffff;
 | 
	
		
			
				|  |  | +            line-height: 30px;
 | 
	
		
			
				|  |  | +            text-align: center;
 | 
	
		
			
				|  |  | +            opacity: 0.4;
 | 
	
		
			
				|  |  | +            cursor: pointer;
 | 
	
		
			
				|  |  | +            &:hover {
 | 
	
		
			
				|  |  | +              opacity: 0.8 !important;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    .musicListCon {
 | 
	
		
			
				|  |  | +      width: 100%;
 | 
	
		
			
				|  |  | +      flex-grow: 1;
 | 
	
		
			
				|  |  | +      overflow: hidden;
 | 
	
		
			
				|  |  | +      display: flex;
 | 
	
		
			
				|  |  | +      flex-direction: column;
 | 
	
		
			
				|  |  | +      .queryFrom {
 | 
	
		
			
				|  |  | +        flex-shrink: 0;
 | 
	
		
			
				|  |  | +        padding: 0 30px;
 | 
	
		
			
				|  |  | +        .queryFromList {
 | 
	
		
			
				|  |  | +          display: flex;
 | 
	
		
			
				|  |  | +          margin-bottom: 4px;
 | 
	
		
			
				|  |  | +          .tit {
 | 
	
		
			
				|  |  | +            flex-shrink: 0;
 | 
	
		
			
				|  |  | +            font-weight: 500;
 | 
	
		
			
				|  |  | +            font-size: 14px;
 | 
	
		
			
				|  |  | +            color: #131415;
 | 
	
		
			
				|  |  | +            line-height: 32px;
 | 
	
		
			
				|  |  | +            margin-right: 16px;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +          .queryFromCon {
 | 
	
		
			
				|  |  | +            display: flex;
 | 
	
		
			
				|  |  | +            flex-wrap: wrap;
 | 
	
		
			
				|  |  | +            .queryTip {
 | 
	
		
			
				|  |  | +              margin: 0 16px 12px 0;
 | 
	
		
			
				|  |  | +              font-weight: 400;
 | 
	
		
			
				|  |  | +              font-size: 14px;
 | 
	
		
			
				|  |  | +              color: rgba(0, 0, 0, 0.6);
 | 
	
		
			
				|  |  | +              line-height: 20px;
 | 
	
		
			
				|  |  | +              padding: 6px 16px;
 | 
	
		
			
				|  |  | +              background: #f5f6fa;
 | 
	
		
			
				|  |  | +              border-radius: 6px;
 | 
	
		
			
				|  |  | +              cursor: pointer;
 | 
	
		
			
				|  |  | +              display: flex;
 | 
	
		
			
				|  |  | +              align-items: center;
 | 
	
		
			
				|  |  | +              & > img {
 | 
	
		
			
				|  |  | +                width: 7px;
 | 
	
		
			
				|  |  | +                height: 4px;
 | 
	
		
			
				|  |  | +                margin-left: 6px;
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +              &:hover {
 | 
	
		
			
				|  |  | +                background: #e8e9ed;
 | 
	
		
			
				|  |  | +                color: #5d5d5e;
 | 
	
		
			
				|  |  | +                > img {
 | 
	
		
			
				|  |  | +                  transform: rotate(180deg);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +              &.active {
 | 
	
		
			
				|  |  | +                background: #d2ecff;
 | 
	
		
			
				|  |  | +                color: rgba(0, 0, 0, 1);
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +              &.hoverActive {
 | 
	
		
			
				|  |  | +                background: #d2ecff;
 | 
	
		
			
				|  |  | +                color: rgba(0, 0, 0, 1);
 | 
	
		
			
				|  |  | +              }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      .isExpand {
 | 
	
		
			
				|  |  | +        flex-shrink: 0;
 | 
	
		
			
				|  |  | +        margin-bottom: 12px;
 | 
	
		
			
				|  |  | +        cursor: pointer;
 | 
	
		
			
				|  |  | +        display: flex;
 | 
	
		
			
				|  |  | +        justify-content: center;
 | 
	
		
			
				|  |  | +        font-weight: 400;
 | 
	
		
			
				|  |  | +        font-size: 14px;
 | 
	
		
			
				|  |  | +        color: #198cfe;
 | 
	
		
			
				|  |  | +        line-height: 20px;
 | 
	
		
			
				|  |  | +        align-items: center;
 | 
	
		
			
				|  |  | +        &:hover {
 | 
	
		
			
				|  |  | +          opacity: 0.8;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        &.active > img {
 | 
	
		
			
				|  |  | +          transform: rotate(0deg);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        & > img {
 | 
	
		
			
				|  |  | +          transform: rotate(180deg);
 | 
	
		
			
				|  |  | +          margin-left: 4px;
 | 
	
		
			
				|  |  | +          width: 10px;
 | 
	
		
			
				|  |  | +          height: 10px;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      .musicListConBox {
 | 
	
		
			
				|  |  | +        flex-grow: 1;
 | 
	
		
			
				|  |  | +        overflow: hidden;
 | 
	
		
			
				|  |  | +        .musicList {
 | 
	
		
			
				|  |  | +          padding: 4px 0;
 | 
	
		
			
				|  |  | +          height: calc(100% - 60px);
 | 
	
		
			
				|  |  | +          overflow: auto;
 | 
	
		
			
				|  |  | +          &.empty {
 | 
	
		
			
				|  |  | +            display: flex;
 | 
	
		
			
				|  |  | +            justify-content: center;
 | 
	
		
			
				|  |  | +            align-items: center;
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        .pagination {
 | 
	
		
			
				|  |  | +          padding: 0 30px;
 | 
	
		
			
				|  |  | +          display: flex;
 | 
	
		
			
				|  |  | +          justify-content: flex-end;
 | 
	
		
			
				|  |  | +          align-items: center;
 | 
	
		
			
				|  |  | +          height: 60px;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</style>
 |