| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563 | import { computed, defineComponent, nextTick, onMounted, reactive, ref, shallowRef, watch } from "vue"import styles from "./index.module.scss"import NavContainer from "@/businessComponents/navContainer"import { ElEmpty, ElMessage, ElScrollbar } from "element-plus"import Dictionary from "@/components/dictionary"import MyInput from "@/components/myInput"import { NImage, NPopselect, NSpin, NTooltip } from "naive-ui"import PlayItem from "./component/play-item"import icon_default from "../../img/cloudPractice/icon_default.png"import iconBtnPause from "../../img/cloudPractice/icon-btn-pause.png"import iconBtnPlay from "../../img/cloudPractice/icon-btn-play.png"import btnSubmit from "../../img/cloudPractice/btn-submit.png"import iconTransfer from "../../img/cloudPractice/icon-transfer.png"import iconDownload from "../../img/cloudPractice/icon-download.png"import { httpAjaxErrMsg } from "@/plugin/httpAjax"import {   queryPage2_gym,   queryPage2_gyt,   queryPage2_klx,   querySubjectIds_gym,   querySubjectIds_gyt,   querySubjectIds_klx,   queryTree_gym,   queryTree_gyt,   queryTree_klx,   selectCondition_klx,   cbsDetail_gym} from "@/api/cloudPractice.api"import axios from "axios"import { getInstrumentName } from "@/libs/instruments"import { formatXML, getCustomInfo, onlyVisible } from "./instrument"import { useFunction } from "./useData"import userStore from "@/store/modules/user"import PlayLoading from "./component/play-loading"import PracticeForm from "@/businessComponents/practiceForm"import { saveAs } from "file-saver"import JSZip from "jszip"import { svgtoblob } from "./formatSvgToImg"import { penShow, whitePenShow } from "@/businessComponents/globalTools/globalTools"import { handleFullscreen } from "@/libs/fullscreen"export default defineComponent({   name: "cloudPractice",   setup() {      const userStoreHook = userStore()      const { goToCloud, getPreViewCloud, isPracticeShow, practiceUrl, handlePracticeClose } = useFunction()      const navs = [         {            name: "主页",            url: "/"         },         {            name: "云练习"         }      ]      const spinRef = ref()      const state = reactive({         finshed: false,         reshing: false,         page: 1,         rows: 20,         details: {} as any,         iframeSrc: "",         listActive: 0, // 当前选中的对象         firstTreeId: null as any, // 左侧         categoryId: null as any, // 类型         categoryName: "" as any, // 类型名称         categoryList: [] as any[],         levelList: [] as any[], // 级别         levelId: null as any,         typeList: [] as any[], // 类型         typeId: -1 as any,         subjectList: [] as any[], // 声部列表         subjectId: -1 as any,         list: [] as any[],         searchStatus: false,         queryStr: "", // 搜索条件         partList: [] as any[],         partNames: [] as any[],         selectedPartName: "" as any,         selectedTrack: "" as any,         selectedPartIndex: 0,         partXmlIndex: 0,         musicPdfUrl: "", // 五线谱文件         imgs: [] as any[], // 图片列表         categoryShow: false, // 是否展开         playState: "pause" as "play" | "pause", // 播放状态         showPlayer: false // 是否显示播放器      })      const partColumns = ref<any>([])      /** 选中的item */      const activeItem = computed(() => {         const list = state.list[state.listActive] || {}         let tempList: any = {}         if (userStoreHook.roles === "GYM") {            // const item = list.background?.[0]            // const audioFileUrl = item?.musicSheetType === "CONCERT" ? item?.metronomeUrl : item?.metronomeMp3Url || item?.mp3Url            tempList = {               id: list?.id,               name: list?.name,               // background: list?.background,               // xmlUrl: item?.xmlUrl,               // musicSheetType: item?.musicSheetType,               audioFileUrl: list.audioFileUrl,               titleImg: list?.titleImg               // musicImg: list.titleImg               // musicJianImg: list.musicJianSvg,               // musicFirstImg: list.musicFirstSvg,               // isScoreRender: item?.isScoreRender,               // defaultScoreRender: item?.defaultScoreRender,               // musicPdfUrl: item?.musicPdfUrl // 独奏使用PDF            }         } else if (userStoreHook.roles === "GYT") {            tempList = {               id: list?.id,               name: list?.musicSheetName,               background: list?.background,               xmlUrl: list?.xmlFileUrl,               musicSheetType: list?.musicSheetType,               audioFileUrl: list?.audioFileUrl,               titleImg: list?.titleImg,               musicImg: list.musicImg,               musicJianImg: list.musicJianSvg,               musicFirstImg: list.musicFirstSvg,               isScoreRender: list?.isScoreRender,               defaultScoreRender: list?.defaultScoreRender,               musicPdfUrl: list?.musicPdfUrl            }         } else if (userStoreHook.roles === "KLX") {            const item: any = list.background?.[0]            tempList = {               id: list?.id,               name: list?.musicSheetName,               background: list?.background,               xmlUrl: list?.xmlFileUrl,               musicSheetType: list?.musicSheetType,               audioFileUrl: item?.audioFileUrl,               titleImg: list?.titleImg,               musicImg: list.musicImg,               musicJianImg: list.musicJianSvg,               musicFirstImg: list.musicFirstSvg,               isScoreRender: false,               defaultScoreRender: false,               musicPdfUrl: list?.musicPdfUrl            }         }         return tempList      })      const songPrevNextStatus = computed(() => {         let prev = true,            next = true         if (state.listActive === 0) {            prev = false         }         if (state.listActive >= state.list.length - 1) {            next = false         }         return {            prev,            next         }      })      const downloadStatus = ref(false)      const loading = ref(false)      const staffLoading = ref(false)      const storeData = shallowRef<any[]>([])      const handleSearchList_gym = async () => {         loading.value = true         await httpAjaxErrMsg(queryTree_gym).then(async res => {            loading.value = false            if (res.code === 200) {               storeData.value = res.data || []               await setDefaultData()            }         })      }      const handleGetSubject_gym = async () => {         loading.value = true         await httpAjaxErrMsg(querySubjectIds_gym, { categoriesId: state.categoryId || state.firstTreeId }).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || []               state.subjectList = result.map((item: any) => {                  return {                     label: item.name,                     value: item.id,                     instrumentIds: item.instrumentIds                  }               })               state.subjectList.unshift({                  label: "全部声部",                  value: -1               })               const userSubjectId = userStoreHook.userInfo.subjectId               if (userSubjectId) {                  const tempSubjectId = userSubjectId.split(",")[0]                  state.subjectList.forEach((item: any) => {                     // 判断是否存在声部编号                     if (item.value === Number(tempSubjectId)) {                        state.subjectId = Number(tempSubjectId)                     }                  })               }            }         })      }      const handleGetList_gym = async () => {         loading.value = true         const params = {            page: state.page,            rows: state.rows,            subjectId: state.subjectId === -1 ? null : state.subjectId,            categoriesId: state.typeId === -1 ? state.levelId : state.typeId,            search: state.queryStr         }         await httpAjaxErrMsg(queryPage2_gym, params).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || []               if (state.reshing) {                  state.list = []                  state.reshing = false               }               if (Array.isArray(result.rows)) {                  state.list = [...state.list, ...result.rows]                  state.finshed = state.page >= result.totalPage               } else {                  state.finshed = true               }            } else {               state.finshed = true            }         })      }      const handleGetDetail_gym = async () => {         loading.value = true         const { id } = state.list[state.listActive] || {}         if (!id) return         await httpAjaxErrMsg(cbsDetail_gym, id, { simpleFlag: "1" }).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || {}               state.details = result            }         })      }      /** 管乐团数据查询 */      const handleSearchList_gyt = async () => {         loading.value = true         await httpAjaxErrMsg(queryTree_gyt, {            enable: true,            page: 1,            parentId: 0,            rows: 10         }).then(res => {            loading.value = false            if (res.code === 200) {               storeData.value = res.data || []               setDefaultData()            }         })      }      const handleGetSubject_gyt = async () => {         loading.value = true         await httpAjaxErrMsg(querySubjectIds_gyt, {            enableFlag: true,            page: 1,            rows: 100         }).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || []               state.subjectList = result.map((item: any) => {                  return {                     label: item.name,                     value: item.id,                     instrumentIds: item.instrumentIds                  }               })               state.subjectList.unshift({                  label: "全部声部",                  value: -1               })               const userSubjectId = userStoreHook.userInfo.subjectId               if (userSubjectId) {                  const tempSubjectId = userSubjectId.split(",")[0]                  state.subjectList.forEach((item: any) => {                     // 判断是否存在声部编号                     if (item.value === Number(tempSubjectId)) {                        state.subjectId = Number(tempSubjectId)                     }                  })               }            }         })      }      const handleGetList_gyt = async () => {         loading.value = true         const params = {            page: state.page,            rows: state.rows,            musicSubject: state.subjectId === -1 ? null : state.subjectId,            musicSheetCategoriesId: state.typeId === -1 ? state.levelId : state.typeId,            keyword: state.queryStr,            detailFlag: true,            status: 1         }         await httpAjaxErrMsg(queryPage2_gyt, params).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || {}               if (state.reshing) {                  state.list = []                  state.reshing = false               }               if (Array.isArray(result.rows)) {                  result.rows.forEach((item: any) => {                     item.name = item.musicSheetName                  })                  state.list = [...state.list, ...result.rows]                  state.finshed = state.page >= result.pages               } else {                  state.finshed = true               }            } else {               state.finshed = true            }         })      }      /** 酷乐秀机构数据查询 */      const handleSearchList_klx = async () => {         loading.value = true         await httpAjaxErrMsg(queryTree_klx, {            enable: true,            page: 1,            parentId: 0,            rows: 10         }).then(async res => {            loading.value = false            if (res.code === 200) {               const result = res.data || []               const tempList: any = []               result.forEach((item: any) => {                  if (item.musicNum > 0) {                     const subjectCounts = item.subjectCounts ? true : false                     const musicCounts = item.musicCounts ? true : false                     const ensembleCounts = item.ensembleCounts ? true : false                     const list: any = []                     if (subjectCounts) {                        list.push({                           label: "基础云练",                           value: "SUBJECT"                        })                     }                     if (musicCounts) {                        list.push({                           label: "独奏云练",                           value: "MUSIC"                        })                     }                     if (ensembleCounts) {                        list.push({                           label: "合奏云练",                           value: "ENSEMBLE"                        })                     }                     tempList.push({                        value: item.id,                        label: item.name,                        musicSheetCategoriesList: list                     })                  }               })               state.categoryList = tempList               await setDefaultData()            } else {               state.finshed = true            }         })      }      const handleGetSubject_klx = async () => {         loading.value = true         await httpAjaxErrMsg(querySubjectIds_klx, {            queryType: "list",            page: 1,            rows: 100         }).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data?.rows || []               state.subjectList = result.map((item: any) => {                  return {                     label: item.name,                     value: item.id,                     instrumentIds: item.instrumentIds                  }               })               state.subjectList.unshift({                  label: "全部声部",                  value: -1               })               const userSubjectId = userStoreHook.userInfo.subjectId               if (userSubjectId) {                  const tempSubjectId = userSubjectId.split(",")[0]                  state.subjectList.forEach((item: any) => {                     // 判断是否存在声部编号                     if (item.value === Number(tempSubjectId)) {                        state.subjectId = Number(tempSubjectId)                     }                  })               }            }         })      }      const handleGetList_klx = async () => {         if (!state.categoryId) return         loading.value = true         const params = {            page: state.page,            rows: state.rows,            albumId: state.categoryId,            subjectId: state.subjectId === -1 ? null : state.subjectId,            subjectType: state.firstTreeId,            level: state.levelId === -1 ? null : state.levelId,            type: state.typeId === -1 ? null : state.typeId,            keyword: state.queryStr         }         await httpAjaxErrMsg(queryPage2_klx, params).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || {}               if (state.reshing) {                  state.list = []                  state.reshing = false               }               if (Array.isArray(result.rows)) {                  result.rows.forEach((item: any) => {                     item.name = item.musicSheetName                  })                  state.list = [...state.list, ...result.rows]                  state.finshed = state.page >= result.totalPage               } else {                  state.finshed = true               }            } else {               state.finshed = true            }         })      }      const handleSelectCondition_klx = async () => {         if (!state.categoryId || !state.firstTreeId) return         loading.value = true         const params = {            tenantAlbumId: state.categoryId,            subjectType: state.firstTreeId         }         await httpAjaxErrMsg(selectCondition_klx, params).then(res => {            loading.value = false            if (res.code === 200) {               const result = res.data || {}               if (result.levelList && result.levelList.length > 0) {                  state.levelList = result.levelList.map((item: any) => {                     return {                        label: item.value,                        value: item.id                     }                  })                  state.levelList.unshift({                     label: "全部级别",                     value: -1                  })                  state.levelId = -1               } else {                  state.levelList = []               }               if (result.typeList && result.typeList.length > 0) {                  state.typeList = result.typeList.map((item: any) => {                     return {                        label: item.value,                        value: item.id                     }                  })                  state.typeList.unshift({                     label: "全部类型",                     value: -1                  })                  state.typeId = -1               } else {                  state.typeList = []               }            }         })      }      /** 条件查询 */      const handleAllSearchList = async () => {         //  GYM,GYT,KLX 区分   查询搜索条件数据         if (userStoreHook.roles === "GYM") {            await handleSearchList_gym()         } else if (userStoreHook.roles === "GYT") {            await handleSearchList_gyt()         } else if (userStoreHook.roles === "KLX") {            await handleSearchList_klx()         }      }      const handleAllGetSubject = async () => {         //  GYM,GYT,KLX 区分   查询声部数据         if (userStoreHook.roles === "GYM") {            await handleGetSubject_gym()         } else if (userStoreHook.roles === "GYT") {            await handleGetSubject_gyt()         } else if (userStoreHook.roles === "KLX") {            await handleGetSubject_klx()         }      }      const handleAllGetList = async () => {         //  GYM,GYT,KLX 区分   查询声部数据·         if (userStoreHook.roles === "GYM") {            await handleGetList_gym()         } else if (userStoreHook.roles === "GYT") {            await handleGetList_gyt()         } else if (userStoreHook.roles === "KLX") {            await handleGetList_klx()         }      }      const handleGetDetail = async () => {         //  GYM,GYT,KLX 区分   查询声部数据·         if (userStoreHook.roles === "GYM") {            await handleGetDetail_gym()         } else if (userStoreHook.roles === "GYT") {            // await handleGetList_gyt()         } else if (userStoreHook.roles === "KLX") {            // await handleGetList_klx()         }      }      /** 初始化数据 */      const setDefaultData = async (type?: "first" | "category" | "level" | "type") => {         if (userStoreHook.roles === "GYM") {            await initCategories_gym(type)         } else if (userStoreHook.roles === "GYT") {            initCategories_gyt(type)         } else if (userStoreHook.roles === "KLX") {            await initCategories_klx(type)         }      }      const initCategories_gym = async (type?: "first" | "category" | "level" | "type") => {         if (storeData.value.length > 0 && !["category", "level", "type"].includes(type as any)) {            let result: any = []            if (type === "first" && state.firstTreeId) {               result = storeData.value.find((item: any) => item.id === state.firstTreeId)?.sysMusicScoreCategoriesList || []            } else {               state.firstTreeId = storeData.value[0]?.id               result = storeData.value[0]?.sysMusicScoreCategoriesList || []            }            state.categoryList = result.map((item: any) => {               return {                  label: item.name,                  value: item.id,                  sysMusicScoreCategoriesList: item.sysMusicScoreCategoriesList || []               }            })            state.categoryId = null            state.categoryName = null            state.levelId = null            state.typeId = -1         }         if (state.categoryList.length > 0 && !["level", "type"].includes(type as any)) {            let result: any = []            if (type === "category" && state.categoryId) {               result = state.categoryList.find((item: any) => item.value === state.categoryId)?.sysMusicScoreCategoriesList || []            } else {               state.categoryId = state.categoryList[0]?.value               state.categoryName = state.categoryList[0]?.label               result = state.categoryList[0]?.sysMusicScoreCategoriesList || []            }            state.levelList = result.map((item: any) => {               return {                  label: item.name,                  value: item.id,                  sysMusicScoreCategoriesList: item.sysMusicScoreCategoriesList || []               }            })            type && (await handleGetSubject_gym())         }         if (state.levelList.length > 0) {            let result: any = []            if (type === "level" && state.levelId) {               result = state.levelList.find((item: any) => item.value === state.levelId)?.sysMusicScoreCategoriesList               state.typeId = -1            } else {               state.levelId = state.levelList[0]?.value               result = state.levelList[0]?.sysMusicScoreCategoriesList || []            }            state.typeList = result.map((item: any) => {               return {                  label: item.name,                  value: item.id               }            })            state.typeList.unshift({               label: "全部",               value: -1            })         }      }      const initCategories_gyt = (type?: "first" | "category" | "level" | "type") => {         if (storeData.value.length > 0 && !["level", "type"].includes(type as any)) {            let result: any = []            if (type === "first" && state.firstTreeId) {               result = storeData.value.find((item: any) => item.id === state.firstTreeId)?.musicSheetCategoriesList || []            } else {               state.firstTreeId = storeData.value[0]?.id               result = storeData.value[0]?.musicSheetCategoriesList || []            }            state.levelList = result.map((item: any) => {               return {                  label: item.name,                  value: item.id,                  musicSheetCategoriesList: item.musicSheetCategoriesList || []               }            })            state.levelId = null            state.typeId = -1         }         if (state.levelList.length > 0) {            let result: any = []            if (type === "level" && state.levelId) {               result = state.levelList.find((item: any) => item.value === state.levelId)?.musicSheetCategoriesList            } else {               state.levelId = state.levelList[0]?.value               result = state.levelList[0]?.musicSheetCategoriesList || []            }            state.typeList = result.map((item: any) => {               return {                  label: item.name,                  value: item.id               }            })            state.typeList.unshift({               label: "全部",               value: -1            })            state.typeId = -1         }      }      const initCategories_klx = async (type?: "first" | "category" | "level" | "type") => {         if (state.categoryList.length > 0 && !["level", "type", "first"].includes(type as any)) {            let result: any = []            if (type === "category" && state.categoryId) {               result = state.categoryList.find((item: any) => item.value === state.categoryId)?.musicSheetCategoriesList || []            } else {               state.categoryId = state.categoryList[0]?.value               state.categoryName = state.categoryList[0]?.label               result = state.categoryList[0]?.musicSheetCategoriesList || []            }            storeData.value = result.map((item: any) => {               return {                  id: item.value,                  name: item.label               }            })         }         if (storeData.value.length > 0 && !["level", "type"].includes(type as any)) {            if (type === "first" && state.firstTreeId) {               await handleSelectCondition_klx()            } else {               //               state.firstTreeId = storeData.value[0]?.id               await handleSelectCondition_klx()            }            state.levelId = -1            state.typeId = -1         }      }      const __init = async () => {         await handleAllSearchList()         await handleAllGetSubject()         await handleAllGetList()         await handleGetDetail() // 默认获取数据         await toDetail()         renderStaff()      }      // 全屏显示      handleFullscreen(true, false)      __init()      const handleResh = () => {         if (loading.value || state.finshed) return         state.page = state.page + 1         handleAllGetList()      }      const handleGetList = async () => {         if (loading.value) return         state.listActive = 0         state.showPlayer = false         state.playState = "pause"         state.partNames = []         state.partList = []         state.details = {}         state.selectedPartName = ""         state.selectedTrack = ""         state.selectedPartIndex = 0         // state.musicPdfUrl = ""         state.partXmlIndex = 0         document.querySelector(".musicList-container")?.scroll(0, 0)         state.page = 1         state.finshed = false         state.reshing = true         state.list = []         await handleAllGetList()      }      const toDetailGYM = async () => {         const row: any = activeItem.value         const details: any = state.details         state.imgs = []         if (details.musicSheetType === "SINGLE") {            loading.value = false            state.musicPdfUrl = details.musicPdfUrl            return         }         // state.partNames = await getPartNames(row.xmlUrl)         let partList = details.musicSheetSoundList || []         partList = partList.filter((item: any) => item.audioPlayType === "PLAY")         partList = partList.filter((item: any) => !item.track?.toLocaleUpperCase()?.includes("COMMON"))         partColumns.value = partList.map((item: any, index: number) => {            const instrumentName = getInstrumentName(item.track)            // const xmlIndex = state.partNames.findIndex((name: any) => name.trim() === item.track)            return {               label: item.track + (instrumentName ? `(${instrumentName})` : ""),               instrumentName: instrumentName,               track: item.track,               musicPdfUrl: item.musicPdfUrl,               // xmlIndex: -1,               value: index            }         })         // 初始化数据         // 是否显示总谱         if (row.isScoreRender) {            partColumns.value.unshift({               label: "总谱",               instrumentName: null,               track: null,               musicPdfUrl: "",               xmlIndex: 999,               value: 999            })            if (row.defaultScoreRender) {               state.selectedPartIndex = 999            }         }         console.log(partColumns.value, "partColumns.value")         // gym 现在单独处理 管乐迷根据查询条件来筛选谱面         let defaultShowStaff         // 这里筛选当前的声轨         const soundCodes = filterSoundCodes()         if (soundCodes) {            const soundCodesArr = soundCodes.split(",").map((code: string) => {               return code                  .toLowerCase()                  .replace(/^\d+|\d+$/g, "")                  .trim()            })            defaultShowStaff = partColumns.value.find((item: any) =>               soundCodesArr.includes(                  item.track &&                     item.track                        .toLowerCase()                        .replace(/^\d+|\d+$/g, "")                        .trim()               )            )         }         defaultShowStaff || (defaultShowStaff = partColumns.value.find((item: any) => item.value === state.selectedPartIndex))         state.selectedPartName = defaultShowStaff?.instrumentName         state.selectedTrack = defaultShowStaff?.track         state.partXmlIndex = defaultShowStaff?.xmlIndex         state.selectedPartIndex = defaultShowStaff?.value         if (details.isScoreRender && details.defaultScoreRender) {            state.musicPdfUrl = details?.musicPdfUrl || ""         } else {            state.musicPdfUrl = defaultShowStaff?.musicPdfUrl || ""         }      }      const toDetail = async () => {         if (userStoreHook.roles === "GYM") {            await toDetailGYM()            return         }         const row: any = activeItem.value         state.imgs = []         if (row.musicSheetType === "SINGLE") {            loading.value = false            state.musicPdfUrl = row.musicPdfUrl            // if (userStoreHook.roles === "GYM") {            //    const imgs = row.musicImg ? row.musicImg.split(",") : []            //    imgs.forEach(async (item: string, index: number) => {            //       const imgCanvas = await imgToCanvas(item)            //       const img = await canvasAddTitle(imgCanvas, row.name)            //       state.imgs.push({            //          name: index + 1 + ".png",            //          url: img            //       })            //    })            // }         }         state.partNames = await getPartNames(row.xmlUrl)         let partList = row.background || []         partList = partList.filter((item: any) => !item.track?.toLocaleUpperCase()?.includes("COMMON"))         partColumns.value = partList.map((item: any, index: number) => {            const instrumentName = getInstrumentName(item.track)            const xmlIndex = state.partNames.findIndex((name: any) => name.trim() === item.track)            let musicPdfUrl = ""            if (userStoreHook.roles === "GYM") {               musicPdfUrl = item.soundMusicPdfUrl            } else if (userStoreHook.roles === "GYT") {               musicPdfUrl = item.musicPdfUrl            } else if (userStoreHook.roles === "KLX") {               musicPdfUrl = item.musicPdfUrl            }            return {               label: item.track + (instrumentName ? `(${instrumentName})` : ""),               instrumentName: instrumentName,               track: item.track,               musicPdfUrl,               xmlIndex,               value: index            }         })         // 初始化数据         // 是否显示总谱         if (row.isScoreRender) {            partColumns.value.unshift({               label: "总谱",               instrumentName: null,               track: null,               musicPdfUrl: "",               xmlIndex: 999,               value: 999            })            if (row.defaultScoreRender) {               state.selectedPartIndex = 999            }         }         // gym 现在单独处理 管乐迷根据查询条件来筛选谱面         // let defaultShowStaff         // if (userStoreHook.roles === "GYM") {         //    // 这里筛选当前的声轨         //    const soundCodes = await filterSoundCodes()         //    if (soundCodes) {         //       const soundCodesArr = soundCodes.split(",").map((code: string) => {         //          return code         //             .toLowerCase()         //             .replace(/^\d+|\d+$/g, "")         //             .trim()         //       })         //       defaultShowStaff = partColumns.value.find((item: any) =>         //          soundCodesArr.includes(         //             item.track &&         //                item.track         //                   .toLowerCase()         //                   .replace(/^\d+|\d+$/g, "")         //                   .trim()         //          )         //       )         //    }         //    defaultShowStaff || (defaultShowStaff = partColumns.value.find((item: any) => item.value === state.selectedPartIndex))         // } else {         const defaultShowStaff = partColumns.value.find((item: any) => item.value === state.selectedPartIndex)         // }         state.selectedPartName = defaultShowStaff?.instrumentName         state.selectedTrack = defaultShowStaff?.track         state.partXmlIndex = defaultShowStaff?.xmlIndex         state.selectedPartIndex = defaultShowStaff?.value         if (row.isScoreRender && row.defaultScoreRender) {            state.musicPdfUrl = row?.musicPdfUrl || ""         } else {            state.musicPdfUrl = defaultShowStaff?.musicPdfUrl || ""         }      }      const getPartNames = async (xmlUrl: string) => {         const partNames: string[] = []         try {            const res: any = await axios.get(xmlUrl)            const xml: any = new DOMParser().parseFromString(res.data, "text/xml")            for (const item of xml.getElementsByTagName("part-name")) {               if (item.textContent) {                  partNames.push(item.textContent)               }            }         } catch (error) {            //         }         return partNames.filter((text: string) => text.toLocaleUpperCase() !== "COMMON") || []      }      const musicIframeLoad = async () => {         if (userStoreHook.roles === "GYM") {            // 判断是用哪个渲染的            loading.value = false            staffLoading.value = false            return         }         const iframeRef: any = document.getElementById("staffIframeRef")         if (iframeRef && iframeRef.contentWindow?.renderXml) {            staffLoading.value = true            const res: any = await axios.get(activeItem.value.xmlUrl)            const parseXmlInfo = getCustomInfo(res.data)            const xml = formatXML(parseXmlInfo.parsedXML)            if (activeItem.value.isScoreRender) {               const canSelectTracks: any = []               const background = activeItem.value.background || []               background.forEach((item: any) => {                  canSelectTracks.push(item.track)               })               iframeRef.contentWindow.renderXml(xml, activeItem.value.isScoreRender)            } else {               const currentXml = onlyVisible(xml, state.partXmlIndex)               iframeRef.contentWindow.renderXml(currentXml)            }         }      }      const resetRender = async () => {         const iframeRef: any = document.getElementById("staffIframeRef")         if (userStoreHook.roles === "GYM") {            iframeRef.contentWindow.location.replace(getPreViewCloud(activeItem.value.id, state.partXmlIndex, state.selectedTrack))            // state.iframeSrc = getPreViewCloud(activeItem.value.id, state.partXmlIndex)            return         }         if (iframeRef && iframeRef.contentWindow?.renderXml) {            staffLoading.value = true            const res: any = await axios.get(activeItem.value.xmlUrl)            const parseXmlInfo = getCustomInfo(res.data)            const xml = formatXML(parseXmlInfo.parsedXML)            if (activeItem.value.isScoreRender) {               iframeRef.contentWindow.renderXml(xml, activeItem.value.isScoreRender)            } else {               const currentXml = onlyVisible(xml, state.partXmlIndex)               iframeRef.contentWindow.renderXml(currentXml)            }         }      }      const renderStaff = async () => {         try {            if (state.musicPdfUrl) {               state.iframeSrc = "/pdf/web/viewer.html?file=" + encodeURIComponent(state.musicPdfUrl) + "&t=" + Date.now()               // https://cdn.oss.dayaedu.com/daya202409/UOFW4q5.pdf               // https://cdn.oss.dayaedu.com/daya202409/UOFVK2A.pdf               // https://cdn.oss.dayaedu.com/daya202409/UODQffO.pdf            } else {               if (userStoreHook.roles === "GYM") {                  state.iframeSrc = getPreViewCloud(activeItem.value.id, state.partXmlIndex, state.selectedTrack)               } else {                  state.iframeSrc = `/osmd/index.html`               }            }         } catch (error) {            //         }      }      /** 音频控制 */      const handleChangeAudio = (type: "play" | "pause" | "pre" | "next") => {         if (type === "play") {            state.playState = "play"         } else if (type === "pause") {            state.playState = "pause"         } else if (type === "pre") {            if (state.list[state.listActive - 1]) {               handlePlay(state.list[state.listActive - 1])            }         } else if (type === "next") {            if (state.list[state.listActive + 1]) {               handlePlay(state.list[state.listActive + 1])            }         }      }      /** 播放曲目 */      const handlePlay = (item: any) => {         const index = state.list.findIndex((_item: any) => _item.id === item.id)         if (index > -1) {            if (state.listActive === index) {               state.playState = state.playState === "play" ? "pause" : "play"            } else {               state.playState = "play"            }            state.showPlayer = true            state.listActive = index         }      }      // // 多个文件下载      const downLoadMultiFile = (files: any, filesName: string) => {         const zip = new JSZip()         for (const i in files) {            zip.file(files[i].name, files[i].url, { binary: true })         }         zip.generateAsync({ type: "blob" }).then(res => {            saveAs(res, filesName ? filesName + ".zip" : `文件夹${Date.now()}.zip`)         })         downloadStatus.value = false      }      const showLoading = async (e: any) => {         if (e.data?.api === "musicStaffRender") {            const musicName =               activeItem.value.name +               (((activeItem.value.musicSheetType === "CONCERT" || state.details.musicSheetType === "CONCERT") && state.selectedPartName) ||               state.selectedTrack                  ? `(${state.selectedPartName || state.selectedTrack})`                  : "")            try {               const osmdImg = e.data.osmdImg               const imgs = []               for (let i = 0; i < osmdImg.length; i++) {                  const img = await svgtoblob(osmdImg[i].img, osmdImg[i].width, osmdImg[i].height, musicName)                  imgs.push({                     url: img,                     name: i + 1 + ".png"                  })               }               state.imgs = imgs            } catch (e) {               // console.log(e);            }            staffLoading.value = e.data.loading            loading.value = e.data.loading         }      }      const searchContent = async () => {         await toDetail()         if (activeItem.value?.id) {            if (state.musicPdfUrl) {               staffLoading.value = true               renderStaff()            } else {               // 为了处理,之前是使用pdf渲染,现在又用osmd,iframe没有重新加载               if (state.iframeSrc.indexOf("pdf/web") !== -1) {                  renderStaff()               } else {                  resetRender()               }            }         }      }      /** 下载图片 */      const onDownload = () => {         if (downloadStatus.value || staffLoading.value) return         const musicName =            activeItem.value.name +            ((activeItem.value.musicSheetType === "CONCERT" && state.selectedPartName) || state.selectedTrack               ? `(${state.selectedPartName || state.selectedTrack})`               : "")         downloadStatus.value = true         if (state.musicPdfUrl) {            // 发起Fetch请求            fetch(state.musicPdfUrl)               .then(response => response.blob())               .then(blob => {                  saveAs(blob, musicName)                  downloadStatus.value = false               })               .catch(() => {                  ElMessage.error("下载失败")                  downloadStatus.value = false               })         } else {            downLoadMultiFile(state.imgs, musicName)         }      }      // 根据当前选中的声部和曲目筛选出对应的声轨      function filterSoundCodes() {         // const { id } = state.list[state.listActive] || {}         // if (!id) {         //    return undefined         // }         const { instrumentIds } =            state.subjectList.find((item: any) => {               return item.value === state.subjectId            }) || {}         if (instrumentIds) {            //  GYM,GYT,KLX 区分   查询声部数据            let cbsDetails: any = []            if (userStoreHook.roles === "GYM") {               cbsDetails = state.details.musicalInstruments || []            } else if (userStoreHook.roles === "GYT") {               //            } else if (userStoreHook.roles === "KLX") {               //            }            const { code } =               cbsDetails.find((item: any) => {                  return instrumentIds == item.id               }) || {}            return code         }         return undefined      }      // 白板的批注打开时暂停播放      watch(         () => [whitePenShow.value, penShow.value],         () => {            if (whitePenShow.value || penShow.value) {               handleChangeAudio("pause")            }         }      )      onMounted(() => {         const obv = new IntersectionObserver(entries => {            if (entries[0].intersectionRatio > 0) {               handleResh()            }         })         obv.observe(spinRef.value)         window.addEventListener("message", showLoading)      })      return () => (         <NavContainer navs={navs}>            {/* <ElScrollbar class="elScrollbar"> */}            <div class={styles.cloudPractice}>               <div class={styles.leftContainer}>                  <div class={styles.details}>                     {storeData.value.length > 0 && (                        <ElScrollbar class={styles.leftSection}>                           {/* 基 础 云 练 */}                           {storeData.value.map((item: any) => (                              <div                                 class={[styles.leftSection_item, item.id === state.firstTreeId && styles.leftSection_item__active]}                                 onClick={async () => {                                    if (loading.value) return                                    state.firstTreeId = item.id                                    await setDefaultData("first")                                    await handleGetList()                                    await handleGetDetail()                                    searchContent()                                 }}                              >                                 {item.name}                              </div>                           ))}                        </ElScrollbar>                     )}                     <div class={[styles.musicList, "musicList-container"]}>                        <div class={styles.searchHeader}>                           {state.categoryList.length > 1 && (                              <div class={[styles.categorySection]}>                                 <NPopselect                                    placement="bottom-start"                                    disabled={loading.value}                                    options={state.categoryList}                                    v-model:value={state.categoryId}                                    onUpdate:value={async (val: any) => {                                       const item = state.categoryList.find((item: any) => item.value === val)                                       if (item) {                                          state.categoryName = item.label                                          state.categoryId = item.value                                          await setDefaultData("category")                                          await handleGetList()                                          await handleGetDetail()                                          searchContent()                                       }                                    }}                                    onUpdate:show={(value: any) => {                                       state.categoryShow = value                                    }}                                    trigger="click"                                    class={"PopSelect"}                                 >                                    <span class={[styles.iconTagName, state.categoryShow && styles.show]}>                                       <span>{state.categoryName}</span>                                    </span>                                 </NPopselect>                              </div>                           )}                           <div class={styles.searchMore}>                              <div class={styles.searchSection}>                                 <Dictionary                                    clearable={false}                                    popperClass="classTypePopper"                                    v-model={state.subjectId}                                    height={42}                                    // disabled={loading.value}                                    options={state.subjectList}                                    placeholder="全部声部"                                    onChange={async () => {                                       await handleGetList()                                       await handleGetDetail()                                       searchContent()                                    }}                                 />                                 {state.levelList.length ? (                                    <Dictionary                                       clearable={false}                                       popperClass="classTypePopper"                                       v-model={state.levelId}                                       height={42}                                       // disabled={loading.value}                                       options={state.levelList}                                       placeholder="级别"                                       onChange={async () => {                                          setDefaultData("level")                                          await handleGetList()                                          await handleGetDetail()                                          searchContent()                                       }}                                    />                                 ) : null}                                 {state.typeList.length > 0 ? (                                    <Dictionary                                       clearable={false}                                       popperClass="classTypePopper"                                       v-model={state.typeId}                                       height={42}                                       // disabled={loading.value}                                       options={state.typeList}                                       propsOpt={{                                          labelField: "name",                                          valueField: "id"                                       }}                                       placeholder="分类"                                       onChange={async () => {                                          await handleGetList()                                          await handleGetDetail()                                          searchContent()                                       }}                                    />                                 ) : null}                              </div>                              <div                                 class={[styles.btnSearch, state.searchStatus && styles.btnSearchActive]}                                 onClick={() => (state.searchStatus = !state.searchStatus)}                              ></div>                           </div>                           {state.searchStatus && (                              <MyInput                                 class="queryCp"                                 v-model={state.queryStr}                                 height={42}                                 placeholder="请输入曲目关键词"                                 onKeyup={async (e: any) => {                                    if (e.code === "Enter" || e.key === "Enter") {                                       await handleGetList()                                       await handleGetDetail()                                       searchContent()                                    }                                 }}                                 onHandleQuery={async () => {                                    await handleGetList()                                    await handleGetDetail()                                    searchContent()                                 }}                                 clearable                              />                           )}                        </div>                        <div class={[styles.wrapList, !state.list.length && !loading.value && styles.wrapListEmpty]}>                           {state.list.map((item: any, index: number) => (                              <div                                 class={[styles.item, index === state.listActive && styles.active]}                                 onClick={async () => {                                    if (index === state.listActive) {                                       return                                    }                                    state.listActive = index                                    state.selectedPartIndex = 0                                    state.partXmlIndex = 0                                    await handleGetDetail()                                    searchContent()                                 }}                              >                                 <div class={styles.itemInfo}>                                    <div class={styles.img}>                                       <NImage                                          lazy                                          objectFit="cover"                                          previewDisabled={true}                                          src={item.titleImg || icon_default}                                          onLoad={(e: any) => {                                             ;(e.target as any).dataset.loaded = "true"                                          }}                                       />                                       <PlayLoading                                          class={[state.listActive === index && state.playState === "play" ? "" : styles.showPlayLoading]}                                       />                                    </div>                                    <div class={styles.title}>                                       <div class={styles.titleName}>                                          <ellipsisScroll title={item.name} />                                       </div>                                    </div>                                 </div>                                 <div class={styles.btnSection}>                                    <div                                       class={styles.btn}                                       onClick={(e: any) => {                                          e.stopPropagation()                                          handlePlay(item)                                          if (state.listActive !== index) {                                             resetRender()                                          }                                       }}                                    >                                       {state.listActive === index && (                                          <>                                             {state.playState === "pause" ? "播放" : "暂停"}                                             <img src={state.playState === "pause" ? iconBtnPlay : (iconBtnPause as any)} />                                          </>                                       )}                                       {state.listActive !== index && (                                          <>                                             播放                                             <img src={iconBtnPlay as any} />                                          </>                                       )}                                    </div>                                 </div>                              </div>                           ))}                           {!state.list.length && !loading.value && (                              <ElEmpty class={styles.empty} image={require("@/img/layout/empty.png")} description="暂无内容" />                           )}                           <div ref={spinRef} class={[styles.loadingWrap, state.finshed && styles.showLoading]}>                              <NSpin show={true} stroke="#FF531C"></NSpin>                           </div>                        </div>                     </div>                  </div>               </div>               <div class={styles.rightContainer}>                  {/* <i class={styles.leftArrow}></i> */}                  <NSpin show={staffLoading.value} stroke="#FF531C">                     {activeItem.value?.id ? (                        state.musicPdfUrl ? (                           <div class={[styles.staffImgs]}>                              <iframe                                 style={{                                    // opacity: loading.value ? 0 : 1,                                    width: "100%",                                    height: "100%"                                 }}                                 src={state.iframeSrc}                                 onLoad={() => {                                    // 判断是用哪个渲染的                                    loading.value = false                                    staffLoading.value = false                                 }}                              ></iframe>                           </div>                        ) : (                           <>                              <div class={styles.musicName}>                                 {activeItem.value.name}                                 {activeItem.value.musicSheetType === "CONCERT" &&                                    (state.selectedPartName || state.selectedTrack ? `(${state.selectedPartName || state.selectedTrack})` : "")}                              </div>                              <div class={[styles.staffImgs]}>                                 <iframe                                    id="staffIframeRef"                                    style={{                                       // opacity: loading.value ? 0 : 1,                                       width: "100%",                                       height: "100%"                                    }}                                    src={state.iframeSrc}                                    onLoad={musicIframeLoad}                                 ></iframe>                              </div>                           </>                        )                     ) : (                        <div class={[styles.staffImgs, !loading.value && !activeItem.value?.id && styles.staffImgsEmpty]}>                           {!loading.value && !activeItem.value?.id && (                              <ElEmpty class={styles.empty} image={require("@/img/layout/empty.png")} description="暂无内容" />                           )}                        </div>                     )}                  </NSpin>                  <img                     style={{                        display: activeItem.value?.id ? "" : "none"                     }}                     class={[styles.goBtn]}                     src={btnSubmit as any}                     onClick={() => {                        handleChangeAudio("pause")                        goToCloud(activeItem.value.id, state.partXmlIndex)                     }}                  />                  <div class={styles.rightBtns} style={{ display: activeItem.value.id ? "" : "none" }}>                     <div style={{ display: state.musicPdfUrl || state.imgs.length > 0 ? "" : "none" }}>                        <NTooltip showArrow={false}>                           {{                              trigger: () => (                                 <img                                    onClick={onDownload}                                    class={[styles.transBtn, (downloadStatus.value || staffLoading.value) && styles.disableBtn]}                                    src={iconDownload as any}                                 />                              ),                              default: "下载曲谱"                           }}                        </NTooltip>                     </div>                     <div                        style={{ display: activeItem.value.musicSheetType === "CONCERT" || state.details.musicSheetType === "CONCERT" ? "" : "none" }}                     >                        <NPopselect                           options={partColumns.value}                           placement="bottom-end"                           trigger="click"                           v-model:value={state.selectedPartIndex}                           scrollable                           onUpdate:value={async (value: any) => {                              const item = partColumns.value.find((item: any) => item.value === value)                              state.selectedPartIndex = value                              state.selectedPartName = item.instrumentName                              state.selectedTrack = item.track                              state.partXmlIndex = item.xmlIndex                              nextTick(() => {                                 let tempPdf = ""                                 if (activeItem.value?.isScoreRender && value === 999) {                                    if (activeItem.value?.musicPdfUrl) {                                       tempPdf = activeItem.value?.musicPdfUrl                                    }                                 } else {                                    tempPdf = item.musicPdfUrl                                 }                                 if (tempPdf) {                                    state.musicPdfUrl = tempPdf                                    staffLoading.value = true                                    renderStaff()                                 } else {                                    state.musicPdfUrl = ""                                    loading.value = true                                    // 为了处理,之前是使用pdf渲染,现在又用osmd,iframe没有重新加载                                    if (state.iframeSrc.indexOf("pdf/web") !== -1) {                                       renderStaff()                                    } else {                                       resetRender()                                    }                                 }                              })                           }}                           class={["PopSelect", "PopSelectPart"]}                        >                           {{                              empty: () => "暂无数据",                              default: () => (                                 <NTooltip showArrow={false}>                                    {{                                       trigger: () => <img class={styles.transBtn} src={iconTransfer as any} />,                                       default: "切换声轨"                                    }}                                 </NTooltip>                              )                           }}                        </NPopselect>                     </div>                  </div>               </div>            </div>            {/* </ElScrollbar> */}            {state.list.length !== 0 && activeItem.value.audioFileUrl && (               <PlayItem                  show={state.showPlayer}                  playState={state.playState}                  songPrevNextStatus={songPrevNextStatus.value}                  item={activeItem.value}                  onChange={value => handleChangeAudio(value)}                  onShow={(status: boolean) => {                     state.showPlayer = status                  }}               />            )}            <PracticeForm v-model={isPracticeShow.value} practiceUrl={practiceUrl.value} onClose={handlePracticeClose} />         </NavContainer>      )   }})
 |