|
@@ -0,0 +1,584 @@
|
|
|
+import { defineComponent } from 'vue';
|
|
|
+import {
|
|
|
+ Sticky,
|
|
|
+ Search,
|
|
|
+ List,
|
|
|
+ Empty,
|
|
|
+ CellGroup,
|
|
|
+ Cell,
|
|
|
+ Icon,
|
|
|
+ NoticeBar,
|
|
|
+ DropdownMenu,
|
|
|
+ DropdownItem,
|
|
|
+ Popup,
|
|
|
+ showLoadingToast,
|
|
|
+ closeToast,
|
|
|
+ showToast
|
|
|
+} from 'vant';
|
|
|
+import qs from 'query-string';
|
|
|
+import { find } from 'lodash';
|
|
|
+import requestOrigin from 'umi-request';
|
|
|
+import { postMessage } from '@/helpers/native-message';
|
|
|
+import request from '@/helpers/request';
|
|
|
+import { state as baseState } from '@/state';
|
|
|
+import state, { getInitState, appState } from '../pageState';
|
|
|
+import ChoosePartName from './modals/choosePartName';
|
|
|
+import VipIcon from './icons/vip.png';
|
|
|
+import iconSearch from './icons/icon_search.png';
|
|
|
+import styles from './index.module.less';
|
|
|
+import MusicIcon from './icons/music.png';
|
|
|
+import { browser } from '@/helpers/utils';
|
|
|
+import OHeader from '@/components/o-header';
|
|
|
+import OSticky from '@/components/o-sticky';
|
|
|
+
|
|
|
+const searchParse = qs.parse(location.search);
|
|
|
+// const isTestTeacher = false;
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'music-list',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ pageInfo: {
|
|
|
+ page: 1,
|
|
|
+ rows: 20
|
|
|
+ },
|
|
|
+ // loading: false,
|
|
|
+ firstLoading: true,
|
|
|
+ show: true,
|
|
|
+ isFirstLoad: false,
|
|
|
+ userinfo: null,
|
|
|
+ isApp: browser().isApp,
|
|
|
+ tempLevelId: 0,
|
|
|
+ chooseShow: false,
|
|
|
+ partNames: [] as string[],
|
|
|
+ selectedPartName: '',
|
|
|
+ selectedPartIndex: 0,
|
|
|
+ activeRow: null as any,
|
|
|
+ liveConfig: false,
|
|
|
+ musicScoreList: []
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ const searchParse = qs.parse(location.search);
|
|
|
+ this.liveConfig = !!searchParse.liveConfig;
|
|
|
+ // console.log(this.liveConfig, " this.liveConfig");
|
|
|
+ // console.log(searchParse, "parseSearch");
|
|
|
+ },
|
|
|
+ async mounted() {
|
|
|
+ await this.initList();
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async initList() {
|
|
|
+ const initState = getInitState();
|
|
|
+ for (const key in initState) {
|
|
|
+ if (Object.prototype.hasOwnProperty.call(initState, key)) {
|
|
|
+ state[key] = initState[key];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.firstLoading = true;
|
|
|
+ try {
|
|
|
+ state.parentId = this.$route.params.id || 1;
|
|
|
+ state.list = [];
|
|
|
+ await this.FetchListTree();
|
|
|
+ await this.FetchLevel();
|
|
|
+ await this.FetchList();
|
|
|
+ } catch {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ this.firstLoading = false;
|
|
|
+
|
|
|
+ window.scrollTo(1, 0);
|
|
|
+ },
|
|
|
+ async FetchListTree() {
|
|
|
+ try {
|
|
|
+ const musicScoreList = sessionStorage.getItem('musicScoreList');
|
|
|
+ const musicList = musicScoreList ? JSON.parse(musicScoreList) : [];
|
|
|
+ let childClass = [];
|
|
|
+ for (const music of musicList) {
|
|
|
+ if (music.id == state.parentId) {
|
|
|
+ childClass = music.sysMusicScoreCategoriesList || [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (childClass.length > 0) {
|
|
|
+ this.musicScoreList = childClass || [];
|
|
|
+ } else {
|
|
|
+ const { data } = await request.get(
|
|
|
+ baseState.platformApi + '/sysMusicScoreCategories/queryTree1',
|
|
|
+ {
|
|
|
+ requestType: 'form',
|
|
|
+ params: {
|
|
|
+ parentId: this.$route.params.id
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ this.musicScoreList = data || [];
|
|
|
+ }
|
|
|
+ // console.log(1);
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async FetchLevel() {
|
|
|
+ try {
|
|
|
+ const childClass = this.musicScoreList || [];
|
|
|
+ // console.log(childClass);
|
|
|
+ state.levelOptions = [
|
|
|
+ ...childClass.map((item: any) => ({
|
|
|
+ value: item.id,
|
|
|
+ text: item.name,
|
|
|
+ childs: item.sysMusicScoreCategoriesList
|
|
|
+ }))
|
|
|
+ ];
|
|
|
+ if (state.levelOptions.length && !state.levelId) {
|
|
|
+ state.levelId = state.levelOptions[0].value;
|
|
|
+ const active = find(state.levelOptions, { value: state.levelId });
|
|
|
+ if (active) {
|
|
|
+ if (active.childs) {
|
|
|
+ // console.log(active, "showInfo");
|
|
|
+ state.typeOptions = [
|
|
|
+ { value: 0, text: '全部' },
|
|
|
+ ...active.childs.map((item: any) => ({
|
|
|
+ value: item.id,
|
|
|
+ text: item.name
|
|
|
+ }))
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ state.typeOptions = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // console.log(2);
|
|
|
+ } catch (error) {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async FetchCats() {
|
|
|
+ try {
|
|
|
+ const res = await request.get(
|
|
|
+ baseState.platformApi + '/sysMusicScoreAccompaniment/querySubjectIds',
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ categoriesId: this.$route.params.id || 1
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ appState.subjectOptions = [
|
|
|
+ { value: 0, text: '全部声部' },
|
|
|
+ ...res.data
|
|
|
+ .filter((item: any) => !!item)
|
|
|
+ .map((item: any) => ({
|
|
|
+ value: item.id,
|
|
|
+ text: item.name
|
|
|
+ }))
|
|
|
+ ];
|
|
|
+ } catch (error) {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async FetchList() {
|
|
|
+ state.error = false;
|
|
|
+ if (state.loading) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ state.loading = true;
|
|
|
+ // console.log(appState.subjectOptions);
|
|
|
+ // if (getRequestHostname() !== '/api-student') {
|
|
|
+ await this.FetchCats();
|
|
|
+ // }
|
|
|
+
|
|
|
+ // if (getRequestHostname() === '/api-student') {
|
|
|
+ // // 因为学生端加了一个扩展声部
|
|
|
+ // appState.subjectOptions = [
|
|
|
+ // ...appState.extSubjectIds
|
|
|
+ // .filter((item: any) => !!item)
|
|
|
+ // .map((item: any) => ({
|
|
|
+ // value: item.id,
|
|
|
+ // text: item.name
|
|
|
+ // }))
|
|
|
+ // ];
|
|
|
+ // }
|
|
|
+ // if (getRequestHostname() != '/api-student') {
|
|
|
+ // 每次请求前设置,确保列表中有值。不在声部列表中清空掉,此处不会影响详情
|
|
|
+ const ids: number[] = appState.subjectOptions
|
|
|
+ .map((item: any) => item.value)
|
|
|
+ .filter((item: number) => item > 0);
|
|
|
+ // console.log(ids, appState.subjectId);
|
|
|
+ if (ids.includes(5)) {
|
|
|
+ ids.push(6);
|
|
|
+ }
|
|
|
+ if (!ids.includes(appState.subjectId)) {
|
|
|
+ appState.subjectId = 0;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ state.subjectId = appState.subjectId;
|
|
|
+ const params = state.params;
|
|
|
+ const parentId = this.$route.params.id;
|
|
|
+ // 如果根级分类没有,则取父级分类
|
|
|
+ // let categoriesId = 181
|
|
|
+ // console.log(3);
|
|
|
+ // console.log(state.levelId, state.typeId, parentId);
|
|
|
+ const categoriesId =
|
|
|
+ (state.levelId || state.typeId) === 0
|
|
|
+ ? undefined
|
|
|
+ : state.typeId || state.levelId;
|
|
|
+ // 如果是合奏则不显示声部,且搜索条件也去掉
|
|
|
+ const subjectId =
|
|
|
+ appState.subjectId === 0 || this.$route.params.id == '43'
|
|
|
+ ? undefined
|
|
|
+ : appState.subjectId;
|
|
|
+
|
|
|
+ const res = await request.get(
|
|
|
+ baseState.platformApi + '/sysMusicScore/queryPage2',
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ ...params,
|
|
|
+ rows: 20,
|
|
|
+ // ...this.pageInfo,
|
|
|
+ clientType: 'SMART_PRACTICE',
|
|
|
+ subjectId,
|
|
|
+ categoriesId,
|
|
|
+ search: state.search
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const { data } = res;
|
|
|
+ // 处理接口重复请求,过滤数据
|
|
|
+ if (state.list.length > 0 && data.pageNo == 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ state.list = [...state.list, ...data.rows];
|
|
|
+ if (params.page >= Math.ceil(data.total / 20)) {
|
|
|
+ state.finished = true;
|
|
|
+ // Toast('列表加载完成')
|
|
|
+ }
|
|
|
+ state.params.page = data.nextPage;
|
|
|
+ // this.pageInfo.page = this.pageInfo.page + 1
|
|
|
+ if (state.list.length <= 0) {
|
|
|
+ this.show = false;
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ state.error = true;
|
|
|
+ }
|
|
|
+ state.loading = false;
|
|
|
+ },
|
|
|
+ async getPartNames(xmlUrl: string) {
|
|
|
+ const partNames: string[] = [];
|
|
|
+ showLoadingToast({
|
|
|
+ type: 'loading',
|
|
|
+ overlay: true
|
|
|
+ });
|
|
|
+ try {
|
|
|
+ const res = await requestOrigin.get(xmlUrl, { mode: 'cors' });
|
|
|
+ const xml: any = new DOMParser().parseFromString(res, 'text/xml');
|
|
|
+
|
|
|
+ for (const item of xml.getElementsByTagName('part-name')) {
|
|
|
+ if (item.textContent) {
|
|
|
+ partNames.push(item.textContent);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ closeToast();
|
|
|
+ } catch (error) {
|
|
|
+ closeToast();
|
|
|
+ showToast('读取分谱信息失败,请重试');
|
|
|
+ }
|
|
|
+ return partNames;
|
|
|
+ },
|
|
|
+ async openDetail() {
|
|
|
+ const row = this.activeRow;
|
|
|
+ const _id = row.id + '';
|
|
|
+
|
|
|
+ // if (searchParse.mode === 'select') {
|
|
|
+ const res = await requestOrigin.get(row.xmlUrl, {
|
|
|
+ mode: 'cors'
|
|
|
+ });
|
|
|
+ const xmlParse = new DOMParser().parseFromString(res, 'text/xml');
|
|
|
+ const parts = xmlParse.getElementsByTagName('part');
|
|
|
+ const firstMeasures = parts[0]?.getElementsByTagName('measure');
|
|
|
+ const body = {
|
|
|
+ api: 'onAccompanySelectResult',
|
|
|
+ content: {
|
|
|
+ id: _id,
|
|
|
+ name: row.name,
|
|
|
+ noteLength: firstMeasures.length,
|
|
|
+ partIndex: this.selectedPartIndex + ''
|
|
|
+ }
|
|
|
+ };
|
|
|
+ postMessage(body);
|
|
|
+ return;
|
|
|
+ // }
|
|
|
+ // try {
|
|
|
+ // const needIds = row.rankIds?.split(",")?.filter(Boolean) || [];
|
|
|
+ // const sid = String(appState.user?.student?.memberRankSettingId);
|
|
|
+ // if (Array.isArray(needIds) && needIds.length && appState.user && !needIds.includes(sid) && getRequestHostname() === "/api-student") {
|
|
|
+ // detailState.vipShow = true;
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ // } catch (error) {}
|
|
|
+
|
|
|
+ // if (browser().isApp) {
|
|
|
+ // const url = `${location.origin}${
|
|
|
+ // location.pathname
|
|
|
+ // }?campId=${sessionStorage.getItem('campId')}#/musicDetail?musicId=${
|
|
|
+ // row.id
|
|
|
+ // }`;
|
|
|
+ // postMessage({
|
|
|
+ // api: 'openWebView',
|
|
|
+ // content: {
|
|
|
+ // url,
|
|
|
+ // orientation: 1,
|
|
|
+ // isHideTitle: true,
|
|
|
+ // statusBarTextColor: false,
|
|
|
+ // isOpenLight: false
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ // } else {
|
|
|
+ // (this as any).$router.push({
|
|
|
+ // path: '/musicDetail',
|
|
|
+ // query: {
|
|
|
+ // musicId: row.id
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ async toDetail(row: any) {
|
|
|
+ this.activeRow = { ...row };
|
|
|
+
|
|
|
+ this.selectedPartName = '';
|
|
|
+ this.selectedPartIndex = 0;
|
|
|
+ const partNames = await this.getPartNames(row.xmlUrl);
|
|
|
+ this.partNames = partNames;
|
|
|
+ let multitrack = false;
|
|
|
+ try {
|
|
|
+ const _multitrack = JSON.parse(row.extConfigJson).multitrack;
|
|
|
+ multitrack = _multitrack > 1 ? true : false;
|
|
|
+ } catch (error) {
|
|
|
+ //
|
|
|
+ }
|
|
|
+ // 多声轨, 不是单声部多声轨, 不是老师布置作业选择曲谱
|
|
|
+
|
|
|
+ this.selectedPartName = partNames[0];
|
|
|
+
|
|
|
+ // this.openDetail();
|
|
|
+ },
|
|
|
+ onSelectedPartName(part: number) {
|
|
|
+ this.selectedPartIndex = part;
|
|
|
+ // this.selectedPartName = partNames[part]
|
|
|
+ this.chooseShow = false;
|
|
|
+ this.openDetail();
|
|
|
+ },
|
|
|
+ onPayVideo(evt: MouseEvent, data: any) {
|
|
|
+ evt.stopPropagation();
|
|
|
+ postMessage({
|
|
|
+ api: 'recordHomeworkVideo',
|
|
|
+ content: {
|
|
|
+ ...data,
|
|
|
+ partIndex: this.selectedPartIndex
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ openRecordingWebview(evt: MouseEvent, row: any) {
|
|
|
+ evt.stopPropagation();
|
|
|
+ postMessage({
|
|
|
+ api: 'recordHomeworkVideo',
|
|
|
+ content: {
|
|
|
+ id: row.id,
|
|
|
+ partIndex: this.selectedPartIndex
|
|
|
+ // url: location.origin + '/accompany/#/detail/' + row.examSongId + '?mode=homework',
|
|
|
+ // orientation: 0,
|
|
|
+ // isHideTitle: true,
|
|
|
+ // statusBarTextColor: false,
|
|
|
+ // isOpenLight: true,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onSearch() {
|
|
|
+ state.params.page = 1;
|
|
|
+ state.list = [];
|
|
|
+ this.show = true;
|
|
|
+ state.finished = false;
|
|
|
+ state.loading = false;
|
|
|
+ this.FetchList();
|
|
|
+ },
|
|
|
+ subjectChange(val: number) {
|
|
|
+ appState.subjectId = val;
|
|
|
+ this.onSearch();
|
|
|
+ },
|
|
|
+ onClickLeft() {
|
|
|
+ (this as any).$router.replace('/');
|
|
|
+ },
|
|
|
+ goBack() {
|
|
|
+ // (this as any).$router.push({
|
|
|
+ // path:'/',
|
|
|
+ // query: {
|
|
|
+ // ...this.$route.query,
|
|
|
+ // },
|
|
|
+ // })
|
|
|
+ (this as any).$router.go(-1);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ render() {
|
|
|
+ return (
|
|
|
+ <div class={styles.accompany}>
|
|
|
+ <Popup
|
|
|
+ show={this.chooseShow}
|
|
|
+ teleport="body"
|
|
|
+ closeable
|
|
|
+ style={{
|
|
|
+ borderRadius: '8px'
|
|
|
+ }}
|
|
|
+ onClickOverlay={() => (this.chooseShow = false)}
|
|
|
+ onClickCloseIcon={() => (this.chooseShow = false)}>
|
|
|
+ <ChoosePartName
|
|
|
+ partNames={this.partNames}
|
|
|
+ onSelectedPartName={this.onSelectedPartName}
|
|
|
+ />
|
|
|
+ </Popup>
|
|
|
+
|
|
|
+ <OSticky position="top">
|
|
|
+ <OHeader
|
|
|
+ isBack={true}
|
|
|
+ border={false}
|
|
|
+ isFixed={false}
|
|
|
+ backIconColor="white"></OHeader>
|
|
|
+ {state.typeOptions ||
|
|
|
+ (state.levelOptions && state.levelOptions.length > 0) ? (
|
|
|
+ <DropdownMenu activeColor="#01C1B5">
|
|
|
+ {state.levelOptions && state.levelOptions.length > 0 ? (
|
|
|
+ <DropdownItem
|
|
|
+ modelValue={state.levelId}
|
|
|
+ options={state.levelOptions}
|
|
|
+ onChange={(val: number) => {
|
|
|
+ state.levelId = val;
|
|
|
+ state.typeId = 0;
|
|
|
+ const active = find(state.levelOptions, { value: val });
|
|
|
+ if (active) {
|
|
|
+ if (active.childs) {
|
|
|
+ state.typeOptions = [
|
|
|
+ { value: 0, text: '全部' },
|
|
|
+ ...active.childs.map((item: any) => ({
|
|
|
+ value: item.id,
|
|
|
+ text: item.name
|
|
|
+ }))
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ state.typeOptions = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.onSearch();
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : null}
|
|
|
+ {state.typeOptions ? (
|
|
|
+ <DropdownItem
|
|
|
+ class={styles.searchSelect}
|
|
|
+ get-container="#app"
|
|
|
+ modelValue={state.typeId}
|
|
|
+ options={state.typeOptions}
|
|
|
+ onChange={(val: any) => {
|
|
|
+ state.typeId = val;
|
|
|
+ this.onSearch();
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : null}
|
|
|
+ </DropdownMenu>
|
|
|
+ ) : null}
|
|
|
+ <Search
|
|
|
+ class={[styles.search]}
|
|
|
+ placeholder="请输入搜索关键词"
|
|
|
+ modelValue={state.search}
|
|
|
+ background="#F8F9FC"
|
|
|
+ onUpdate:model-value={(text: string) => (state.search = text)}
|
|
|
+ showAction
|
|
|
+ onSearch={this.onSearch}
|
|
|
+ vSlots={{
|
|
|
+ 'left-icon': () => (
|
|
|
+ <img class={styles.iconSearch} src={iconSearch} />
|
|
|
+ ),
|
|
|
+ label: () => {
|
|
|
+ return (
|
|
|
+ <DropdownMenu
|
|
|
+ activeColor="#01C1B5"
|
|
|
+ onClick={(evt: MouseEvent) => {
|
|
|
+ evt.preventDefault();
|
|
|
+ }}>
|
|
|
+ <DropdownItem
|
|
|
+ class={styles.searchSelect}
|
|
|
+ get-container="#app"
|
|
|
+ modelValue={appState.subjectId}
|
|
|
+ options={appState.subjectOptions}
|
|
|
+ onChange={(val: any) => {
|
|
|
+ appState.subjectId = val;
|
|
|
+ this.onSearch();
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </DropdownMenu>
|
|
|
+ );
|
|
|
+ },
|
|
|
+ action: () => (
|
|
|
+ <span class={styles.search_btn} onClick={this.onSearch}>
|
|
|
+ 搜索
|
|
|
+ </span>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </OSticky>
|
|
|
+
|
|
|
+ <div class={[styles.accompanyList, styles.song]}>
|
|
|
+ {this.show ? (
|
|
|
+ <List
|
|
|
+ loading={state.loading}
|
|
|
+ finishedText="加载完毕"
|
|
|
+ error={state.error}
|
|
|
+ offset={100}
|
|
|
+ finished={state.finished}
|
|
|
+ immediateCheck={false}
|
|
|
+ onLoad={() => {
|
|
|
+ if (!this.firstLoading) this.FetchList();
|
|
|
+ }}
|
|
|
+ vSlots={{
|
|
|
+ error: () => (
|
|
|
+ <span onClick={this.FetchList}>加载失败,请点击重试</span>
|
|
|
+ )
|
|
|
+ }}>
|
|
|
+ <CellGroup>
|
|
|
+ {state.list.map((item: any) => (
|
|
|
+ <Cell
|
|
|
+ style={{ display: item.id ? '' : 'none' }}
|
|
|
+ size="large"
|
|
|
+ onClick={() => this.toDetail(item)}
|
|
|
+ vSlots={{
|
|
|
+ icon: () => (
|
|
|
+ <div class={styles['icon-status']}>
|
|
|
+ <Icon class={styles.iconMusic} name={MusicIcon} />
|
|
|
+ {item.rankIds ? (
|
|
|
+ <div class={styles.icon}>
|
|
|
+ <img src={VipIcon} />
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ title: () => (
|
|
|
+ <NoticeBar
|
|
|
+ background="none"
|
|
|
+ color="#444"
|
|
|
+ style={{
|
|
|
+ paddingLeft:
|
|
|
+ (item.rankIds ? '4PX' : '15PX') + '!important'
|
|
|
+ }}
|
|
|
+ text={item.name}
|
|
|
+ key="notactive"
|
|
|
+ />
|
|
|
+ )
|
|
|
+ }}></Cell>
|
|
|
+ ))}
|
|
|
+ </CellGroup>
|
|
|
+ </List>
|
|
|
+ ) : (
|
|
|
+ <Empty description="暂无数据" />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+});
|