123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857 |
- import {
- computed,
- defineComponent,
- nextTick,
- onMounted,
- onUnmounted,
- reactive,
- ref,
- Teleport,
- toRefs,
- watch
- } from 'vue';
- import styles from './index.module.less';
- import { browser, vaildMusicScoreUrl } from '@/helpers/utils';
- import MSticky from '@/components/m-sticky';
- import MHeader from '@/components/m-header';
- import { useRoute, useRouter } from 'vue-router';
- import MSearch from '@/components/m-search';
- import { Cell, Icon, Image, List, Popup, Tab, Tabs } from 'vant';
- import iconPlayer from './images/icon-player.png';
- import iconFire from './images/icon-fire.png';
- import iconTitleArrow from './images/icon-title-arrow.png';
- import { api_musicSheetPage } from '../co-ai/api';
- import { state as baseState } from '@/state';
- import request from '@/helpers/request';
- import MEmpty from '@/components/m-empty';
- import { listenerMessage, postMessage } from '@/helpers/native-message';
- import { audioPlayType } from '@/helpers/constant';
- import MusicDetail from './music-detail';
- import TheVip from '@/components/the-vip';
- import { useEventListener } from '@vueuse/core';
- const ChildNodeSearch = defineComponent({
- name: 'ChildNodeSearch',
- props: {
- activeRow: {
- type: Object,
- default: () => ({})
- },
- list: {
- type: Array,
- default: () => []
- }
- },
- emits: ['selectChildTag'],
- setup(props, { emit }) {
- const { activeRow } = toRefs(props);
- const selectItem = ref({});
- watch(
- () => props.activeRow,
- () => {
- activeRow.value = props.activeRow;
- selectItem.value = {};
- }
- );
- return () => (
- <>
- {activeRow.value?.id && (
- <>
- <div class={styles.title}>{activeRow.value.columnName}</div>
- <div class={[styles.subjectContainer]}>
- {activeRow.value?.children.map((subject: any) => (
- <div
- class={[
- styles.subjectItem,
- styles.subjectItem4,
- (activeRow.value.activeIndex || '') == subject.id &&
- styles.active
- ]}
- onClick={() => {
- activeRow.value.activeIndex = subject.id;
- let children: any;
- let columnName = '';
- if (subject.children) {
- children = [
- {
- columnName: subject.children[0].columnName,
- name: '全部',
- id: ''
- },
- ...subject.children
- ];
- columnName = subject.children[0].columnName;
- selectItem.value = {
- ...subject,
- columnName,
- activeIndex: '',
- children
- };
- } else {
- selectItem.value = {};
- }
- emit('selectChildTag', activeRow.value.activeIndex);
- }}>
- {subject.name}
- </div>
- ))}
- </div>
- <ChildNodeSearch
- activeRow={selectItem.value}
- onSelectChildTag={(item: any) => {
- emit('selectChildTag', item || activeRow.value.activeIndex);
- }}
- />
- </>
- )}
- </>
- );
- }
- });
- export default defineComponent({
- name: 'hot-music-more',
- setup() {
- const router = useRouter();
- const route = useRoute();
- const state = reactive({
- background: 'transparent',
- loading: false,
- finished: false,
- isAllStatus: true, // 当前是否已经为全部了
- searchPopup: false,
- musicDetailPopup: false,
- showVip: false,
- vipMember: baseState.user.data.vipMember,
- tabActive: '' as any,
- instrumentCodes: {} as any, // 所有的乐器code 对应的名称
- newTags: [] as any,
- isTagExpand: false,
- musics: [] as any,
- types: [] as any,
- subjectList: [] as any,
- audioPlayTypeList: [] as any, // 场景
- sNt: '' as any, // 标签
- sAPT: '', // 场景
- item: {} as any,
- allSearch: {
- name: '',
- musicTagIds: '' as any,
- audioPlayTypes: [] as any,
- bookVersionId: null as any,
- musicalInstrumentId: ''
- },
- hotSearch: {
- name: ''
- },
- newSearch: {
- name: ''
- },
- recommendSearch: {
- name: ''
- }
- });
- const tabsRef = ref();
- const musicForms = reactive({
- page: 1,
- rows: 20,
- status: 1,
- sortType: 2, // 默认热度排序
- keyword: '' // 关键词
- });
- const data = reactive({
- selectParents: {}, // 选中的数据
- tags: [] as any[],
- tagActiveId: '' as any,
- tagActive: {} as any,
- childSelectId: null as any
- });
- const contentRef = ref();
- const searchValue = computed(() => {
- if (state.tabActive === 'RECOMMEND') {
- return state.recommendSearch.name;
- } else if (state.tabActive === 'HOT') {
- return state.hotSearch.name;
- } else if (state.tabActive === 'NEW') {
- return state.newSearch.name;
- } else {
- return state.allSearch.name;
- }
- });
- let isClick = false;
- const getMusicList = async () => {
- if (isClick) return;
- isClick = true;
- state.loading = true;
- try {
- const { ...result } = musicForms;
- let params = {
- ...result,
- searchType: state.tabActive
- } as any;
- if (state.tabActive === 'RECOMMEND') {
- params = Object.assign(params, state.recommendSearch);
- params.page = 1;
- params.rows = 60;
- } else if (state.tabActive === 'HOT') {
- params = Object.assign(params, state.hotSearch);
- params.page = 1;
- params.rows = 60;
- } else if (state.tabActive === 'NEW') {
- params = Object.assign(params, state.newSearch);
- params.page = 1;
- params.rows = 60;
- } else {
- params.name = state.allSearch.name;
- params = Object.assign(params, state.allSearch);
- }
- const res = await api_musicSheetPage(params);
- if (res.code === 200 && Array.isArray(res?.data?.rows)) {
- const result = res.data.rows || [];
- result.forEach((item: any) => {
- item.audioPlayTypeArray = item.audioPlayTypes
- ? item.audioPlayTypes.split(',')
- : [];
- });
- state.musics = [...state.musics, ...res.data.rows];
- state.finished = !res.data.next;
- musicForms.page = res.data.current + 1;
- // state.listState.dataShow = state.list.length > 0;
- } else {
- state.finished = true;
- }
- } catch (error) {
- // console.log('🚀 ~ error:', error);
- state.finished = true;
- }
- state.loading = false;
- isClick = false;
- };
- const getTags = async () => {
- try {
- const res = await request.get('/edu-app/musicSheetTag/queryList');
- const result = res.data || [];
- state.newTags = [
- {
- name: '全部',
- id: ''
- },
- ...result.map((item: any) => {
- return {
- name: item.name,
- id: item.id
- };
- })
- ];
- } catch {
- //
- }
- };
- const formatParentId = (id: any, list: any, ids = [] as any) => {
- for (const item of list) {
- if (item.children && item.children.length > 0) {
- const cIds: any = formatParentId(id, item.children, [
- ...ids,
- item.id
- ]);
- if (cIds.includes(id)) {
- return cIds;
- }
- }
- if (item.id === id) {
- return [...ids, id];
- }
- }
- return ids;
- };
- const onSearch = () => {
- musicForms.page = 1;
- state.musics = [];
- state.finished = false;
- getMusicList();
- };
- const onReset = () => {
- state.sNt = '';
- state.sAPT = '';
- data.tagActiveId = '';
- data.childSelectId = null;
- data.selectParents = {};
- // state.allSearch.bookVersionId = data.childSelectId || data.tagActiveId;
- // state.allSearch.audioPlayTypes = state.sAPT
- // ? state.sAPT === 'PLAY_SING'
- // ? ['SING', 'PLAY']
- // : [state.sAPT]
- // : [];
- // state.allSearch.musicTagIds = state.sNt;
- // state.searchPopup = false;
- // onSearch();
- };
- const onDetail = (item: any) => {
- state.item = item;
- state.musicDetailPopup = true;
- };
- const getMusicTagTree = async () => {
- try {
- const res = await request.get('/edu-app/musicTag/tree');
- const result = res.data || [];
- // 去掉上下册
- result.forEach((item: any) => {
- if (item.children && item.children.length > 0) {
- const child = item.children;
- child?.forEach((c: any) => {
- c.children = null;
- });
- }
- });
- data.tags = [
- {
- columnName: result[0].columnName,
- name: '全部',
- id: ''
- },
- ...result
- ];
- data.tagActiveId = data.tags[0].id;
- } catch {
- //
- }
- };
- const changeTag = (item: any, activeIndex?: any) => {
- data.tagActiveId = item.id;
- data.childSelectId = activeIndex;
- let children: any;
- let columnName = '';
- if (item.children) {
- children = [
- {
- columnName: item.children[0].columnName,
- name: '全部',
- id: ''
- },
- ...item.children
- ];
- columnName = item.children[0].columnName;
- data.selectParents = {
- ...item,
- columnName,
- activeIndex: activeIndex || '',
- children
- };
- } else {
- data.selectParents = {};
- }
- };
- const formatUsedNum = (num: number) => {
- if (num < 10000) {
- return num;
- } else {
- const n = num / 10000;
- return Number(n.toFixed(1)) + '万';
- }
- };
- // 判断是否有数据
- // const isSearch = computed(() => {
- // return data.tags.length > 0 ? true : false;
- // });
- const handleGoto = (
- item: any,
- showMusicImg: string,
- selectMusicInstrumentIndex: number
- ) => {
- if (!state.vipMember && item?.paymentType === 'VIP') {
- state.showVip = true;
- return;
- }
- // 默认进页面显示对应的曲谱
- let lineType = 'staff';
- if (showMusicImg === 'first') {
- lineType = 'firstTone';
- } else if (showMusicImg === 'fixed') {
- lineType = 'fixedTone';
- } else if (showMusicImg === 'staff') {
- lineType = 'staff';
- }
- let src = `${vaildMusicScoreUrl()}/instrument/?id=${
- item?.id
- }&musicRenderType=${lineType}&showGuide=true&part-index=${selectMusicInstrumentIndex}`;
- postMessage({
- api: 'openAccompanyWebView',
- content: {
- url: src,
- orientation: 0,
- isHideTitle: true,
- statusBarTextColor: false,
- isOpenLight: true,
- c_orientation: 0 // 0 横屏 1 竖屏
- }
- });
- };
- const getUserInfo = async () => {
- const res = await request.get('/edu-app/user/getUserInfo', {
- initRequest: true, // 初始化接口
- requestType: 'form',
- hideLoading: true
- });
- if (res?.code === 200) {
- state.vipMember = res.data.vipMember;
- }
- };
- /**
- * 获取所有曲目code
- */
- const getInstrumentCode = async () => {
- try {
- const { data } = await request.get('/edu-app/musicSheet/instrumentCode');
- const result = data || [];
- const tempCodes: any = {}
- result.forEach((item: any) => {
- const codes = item.code?.split(',');
- codes.forEach((code: any) => {
- tempCodes[code] = item.name;
- });
- });
- state.instrumentCodes = tempCodes;
- } catch {
- //
- }
- }
- const tabResize = () => {
- tabsRef.value?.resize();
- };
- onMounted(async () => {
- getInstrumentCode()
- if (route.query.type) {
- state.tabActive = route.query.type;
- state.isAllStatus = false;
- }
- // tabsRef
- // 场景
- const tempAudio = Object.keys(audioPlayType).map(key => {
- return {
- id: key,
- name: audioPlayType[key]
- };
- });
- state.audioPlayTypeList = [{ name: '全部', id: '' }, ...tempAudio];
- state.loading = true;
- getUserInfo();
- await getTags();
- await getMusicTagTree();
- getMusicList();
- window.addEventListener('resize', tabResize);
- listenerMessage('webViewOnResume', () => {
- tabResize();
- });
- });
- onUnmounted(() => {
- window.removeEventListener('resize', tabResize);
- });
- return () => (
- <div
- class={[
- styles.hotMusicMore,
- browser().isTablet ? styles.hotMusicMoreTablet : ''
- ]}>
- <MSticky position="top">
- <MHeader border={false} background={'transparent'}>
- {{
- content: () => (
- <div class={styles.woringHeader}>
- <i
- onClick={() => {
- if (browser().isApp) {
- postMessage({
- api: 'back'
- });
- } else {
- router.back();
- }
- }}
- class={[
- 'van-badge__wrapper van-icon van-icon-arrow-left van-nav-bar__arrow',
- styles.leftArrow
- ]}></i>
- <Tabs
- ref={tabsRef}
- class={styles.tabSection}
- v-model:active={state.tabActive}
- shrink
- onClickTab={(val) => {
- if (state.tabActive === '') {
- if (state.isAllStatus) {
- state.searchPopup = !state.searchPopup;
- if (state.searchPopup) {
- const allSearch = state.allSearch;
- if (allSearch.audioPlayTypes.length > 0) {
- if (allSearch.audioPlayTypes.length == 1) {
- state.sAPT = allSearch.audioPlayTypes.join(',');
- } else {
- state.sAPT = 'PLAY_SING';
- }
- } else {
- state.sAPT = '';
- }
- state.sNt = allSearch.musicTagIds;
- if (allSearch.bookVersionId) {
- let ids: any = [];
- data.tags.forEach((item: any) => {
- if (item.id === allSearch.bookVersionId) {
- ids.push(item.id);
- }
- });
- if (ids.length <= 0) {
- ids = formatParentId(
- allSearch.bookVersionId,
- data.tags
- );
- }
- // console.log(ids, 'ids', allSearch.bookVersionId)
- data.tagActiveId = ids[0];
- if (data.tagActiveId) {
- const item = data.tags.find(
- item => item.id === ids[0]
- );
- if (item) changeTag(item, ids[1]);
- }
- } else {
- data.tagActiveId = '';
- data.childSelectId = null;
- data.selectParents = {};
- }
- }
- } else {
- state.isAllStatus = true;
- onSearch();
- }
- } else {
- state.searchPopup = false;
- state.isAllStatus = false;
- onSearch();
- }
- }}>
- <Tab name="">
- {{
- title: () => (
- <div class={styles.moreIcon}>
- <span>全部</span>
- <img
- src={iconTitleArrow}
- class={[
- styles.iconArrow,
- state.searchPopup && styles.iconArrowActive
- ]}
- />
- </div>
- )
- }}
- </Tab>
- {/* 推荐 - 由于Android 在华为平台审核的原因 */}
- <Tab name="RECOMMEND" title="精选"></Tab>
- <Tab name="HOT" title="热门"></Tab>
- <Tab name="NEW" title="最新"></Tab>
- </Tabs>
- </div>
- )
- }}
- </MHeader>
- <MSearch
- v-model:modelValue={searchValue.value}
- background={'transparent'}
- inputBackground="transparent"
- class={styles.mSearch11}
- onFocus={() => {
- state.searchPopup = false;
- }}
- onSearch={(val: any) => {
- if (state.tabActive === 'RECOMMEND') {
- state.recommendSearch.name = val;
- } else if (state.tabActive === 'HOT') {
- state.hotSearch.name = val;
- } else if (state.tabActive === 'NEW') {
- state.newSearch.name = val;
- } else {
- state.allSearch.name = val;
- }
- state.searchPopup = false;
- onSearch();
- }}></MSearch>
- </MSticky>
- <div style="height: calc(100vh - var(--header-height)); overflow-x: hidden; overflow-y: auto;">
- <List
- loading={state.loading}
- finished={state.finished}
- finishedText=" "
- onLoad={() => {
- if (!state.tabActive) {
- getMusicList();
- }
- }}
- immediateCheck={false}>
- {state.musics.length > 0 && (
- <div class={styles.musicListSection}>
- <div class={styles.musicList}>
- {state.musics.map((item: any) => (
- <Cell
- class={styles.musicItem}
- border={false}
- center
- onClick={() => onDetail(item)}>
- {{
- icon: () => (
- <div class={styles.musicImg}>
- <i
- class={[
- styles.iconType,
- styles[item.paymentType]
- ]}></i>
- <Image
- class={styles.musicImg}
- src={item.titleImg}
- />
- </div>
- ),
- title: () => (
- <div class={styles.musicContnet}>
- <h2>{item.musicSheetName}</h2>
- <div class={styles.allStatus}>
- <span class={styles.hotNum}>
- <img src={iconFire} class={styles.iconFire} />
- {formatUsedNum(item.usedNum)}
- </span>
- {item.audioPlayTypes?.includes('SING') && (
- <span
- class={[
- styles.iconPlayType,
- styles.iconSing
- ]}>
- 演唱
- </span>
- )}
- {item.audioPlayTypes?.includes('PLAY') && (
- <span
- class={[
- styles.iconPlayType,
- styles.iconPlay
- ]}>
- 演奏
- </span>
- )}
- {item.composer && <p>{item.composer}</p>}
- </div>
- </div>
- ),
- 'right-icon': () => (
- <Image
- class={styles.musicPlayIcon}
- src={iconPlayer}
- />
- )
- }}
- </Cell>
- ))}
- </div>
- </div>
- )}
- {!state.loading && state.musics.length === 0 && (
- <div class={styles.emptyGroup}>
- <MEmpty description="暂无曲谱" />
- </div>
- )}
- </List>
- </div>
- <Teleport to={'body'}>
- <div class={[styles.searchBodySection]}>
- <Popup position="top" round v-model:show={state.searchPopup}>
- <div class={styles.searchContainer}>
- <div class={styles.changeSubjectContainer}>
- {state.newTags.length > 1 && (
- <>
- <div class={styles.title}>标签</div>
- <div class={styles.subjectContainer}>
- {state.newTags.map((subject: any) => (
- <div
- class={[
- styles.subjectItem,
- subject.id === state.sNt && styles.active
- ]}
- onClick={() => {
- state.sNt = subject.id;
- }}>
- {subject.name}
- </div>
- ))}
- </div>
- </>
- )}
- {state.audioPlayTypeList.length > 0 && (
- <>
- <div class={styles.title}>场景</div>
- <div class={styles.subjectContainer}>
- {state.audioPlayTypeList.map((subject: any) => (
- <div
- class={[
- styles.subjectItem,
- styles.subjectItem4,
- subject.id === state.sAPT && styles.active
- ]}
- onClick={() => {
- state.sAPT = subject.id;
- }}>
- {subject.name}
- </div>
- ))}
- </div>
- </>
- )}
- {data.tags.length > 0 && (
- <>
- <div class={styles.title} ref={contentRef}>
- {data.tags[0]?.columnName}
- {state.isTagExpand && (
- <span onClick={() => (state.isTagExpand = false)}>
- 收起
- <Icon name="arrow-up" />
- </span>
- )}
- </div>
- <div
- class={[
- styles.subjectContainer,
- styles.subjectContainerTwo
- ]}>
- {data.tags.map(
- (subject: any, index: number) =>
- ((!state.isTagExpand && index <= 4) ||
- state.isTagExpand) && (
- <div
- class={[
- styles.subjectItem,
- (subject.id || '') ===
- (data.tagActiveId || '') && styles.active
- ]}
- onClick={() => {
- changeTag(subject);
- }}>
- {subject.name}
- </div>
- )
- )}
- {!state.isTagExpand && data.tags.length > 5 && (
- <div
- class={[styles.subjectItem]}
- onClick={() => {
- state.isTagExpand = true;
- nextTick(() => {
- contentRef.value?.scrollIntoView({
- behavior: 'smooth',
- block: 'start'
- });
- });
- }}>
- 更多 <Icon name="arrow-down" />
- </div>
- )}
- </div>
- <ChildNodeSearch
- activeRow={data.selectParents}
- onSelectChildTag={(val: any) => {
- data.childSelectId = val;
- // onSearch();
- }}
- />
- </>
- )}
- </div>
- <div class={styles.searchHead}>
- <span class={styles.cancel} onClick={() => onReset()}>
- 重置
- </span>
- {/* <span>筛选</span> */}
- <span
- class={styles.confirm}
- onClick={() => {
- state.allSearch.bookVersionId =
- data.childSelectId || data.tagActiveId;
- state.allSearch.audioPlayTypes = state.sAPT
- ? state.sAPT === 'PLAY_SING'
- ? ['SING', 'PLAY']
- : [state.sAPT]
- : [];
- state.allSearch.musicTagIds = state.sNt;
- state.searchPopup = false;
- onSearch();
- }}>
- 确定
- </span>
- </div>
- </div>
- </Popup>
- </div>
- </Teleport>
- <Popup
- position="bottom"
- class={styles.popupMusicDetail}
- closeable
- round
- v-model:show={state.musicDetailPopup}>
- <MusicDetail item={state.item} instrumentCodes={state.instrumentCodes} onHandleGoto={handleGoto} />
- </Popup>
- <Popup
- class="popup-custom van-scale"
- transition="van-scale"
- closeOnClickOverlay={false}
- v-model:show={state.showVip}>
- <TheVip
- onClose={val => {
- if (val) {
- router.push('/member-center');
- }
- state.showVip = false;
- }}
- />
- </Popup>
- </div>
- );
- }
- });
|