index.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. import {
  2. computed,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref,
  8. watch
  9. } from 'vue'
  10. import { Sticky, List, Popup, Icon, Switch, Tabs, Tab } from 'vant'
  11. import Search from '@/components/col-search'
  12. import request from '@/helpers/request'
  13. // import Item from './item'
  14. import SelectTag from '../search/select-tag'
  15. import { useRoute, useRouter } from 'vue-router'
  16. import ColResult from '@/components/col-result'
  17. import styles from './index.module.less'
  18. import { getRandomKey } from '../music'
  19. import { openDefaultWebView, state as baseState } from '@/state'
  20. import SelectSubject from '../search/select-subject'
  21. import { SubjectEnum, useSubjectId } from '@/helpers/hooks'
  22. import Song from '../component/song'
  23. import ColHeader from '@/components/col-header'
  24. import { useRect } from '@vant/use'
  25. import { useAsyncState } from '@vueuse/core'
  26. import bgImg from './icons/bgImg.png'
  27. import iconSearch from './icons/icon_search.png'
  28. import { browser } from '@/helpers/utils'
  29. import TheSticky from '@/components/the-sticky'
  30. const noop = () => {
  31. //
  32. }
  33. export default defineComponent({
  34. name: 'MusicList',
  35. props: {
  36. hideSearch: {
  37. type: Boolean,
  38. default: false
  39. },
  40. onlySearch: {
  41. type: Boolean,
  42. default: false
  43. },
  44. height: {
  45. type: Number,
  46. default: 0
  47. },
  48. defauleParams: {
  49. type: Object,
  50. default: () => ({})
  51. },
  52. onItemClick: {
  53. type: Function,
  54. default: noop
  55. },
  56. teacherId: {
  57. type: String || Number,
  58. default: ''
  59. },
  60. myself: {
  61. type: Boolean,
  62. default: false
  63. }
  64. },
  65. setup(
  66. {
  67. hideSearch,
  68. onlySearch,
  69. height,
  70. defauleParams,
  71. onItemClick,
  72. teacherId,
  73. myself
  74. },
  75. { expose }
  76. ) {
  77. const { isLoading, state } = useAsyncState(
  78. request(baseState.platformApi + '/MusicTag/tree', {
  79. params: {
  80. type: 'MUSIC'
  81. }
  82. }),
  83. null
  84. )
  85. const stickyHeight = ref(height || 0)
  86. const updateStickyHeight = (height: number) => {
  87. stickyHeight.value = height
  88. }
  89. const teacherDetaultSubject = ref({
  90. id: '',
  91. name: ''
  92. })
  93. if (baseState.platformType === 'TEACHER') {
  94. // defaultSubject
  95. const users = baseState.user.data
  96. teacherDetaultSubject.value = {
  97. name: users.defaultSubjectName || '全部声部',
  98. id: users.defaultSubject || ''
  99. }
  100. } else {
  101. // const subjects: any = useSubjectId(SubjectEnum.SEARCH)
  102. // 判断是否已有数据
  103. // if (!subjects.id) {
  104. const users = baseState.user.data
  105. // const subjectId = users.subjectId
  106. // ? Number(users.subjectId.split(',')[0])
  107. // : ''
  108. // const subjectName = users.subjectName
  109. // ? users.subjectName.split(',')[0]
  110. // : ''
  111. // 存储instrumentId
  112. const userInstrumentId = users.instrumentId
  113. localStorage.setItem('userInstrumentId', userInstrumentId)
  114. // if (subjectId) {
  115. // useSubjectId(
  116. // SubjectEnum.SEARCH,
  117. // JSON.stringify({
  118. // id: subjectId,
  119. // name: subjectName
  120. // }),
  121. // 'set'
  122. // )
  123. // }
  124. // }
  125. }
  126. localStorage.setItem('behaviorId', getRandomKey())
  127. const route = useRoute()
  128. const router = useRouter()
  129. const tempParams: any = {}
  130. if (baseState.version) {
  131. tempParams.version = baseState.version || '' // 处理ios审核版本
  132. tempParams.platform =
  133. baseState.platformType === 'STUDENT' ? 'ios-student' : 'ios-teacher'
  134. }
  135. const exquisiteFlag = ref(false)
  136. // 判断是否在搜索页面用过
  137. if (!hideSearch) {
  138. if (baseState.platformType === 'TEACHER') {
  139. tempParams.subjectIds = teacherDetaultSubject.value.id
  140. } else {
  141. // const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
  142. const users = baseState.user.data
  143. const subjectId = users.subjectId
  144. ? Number(users.subjectId.split(',')[0])
  145. : ''
  146. tempParams.subjectIds = subjectId
  147. }
  148. const getMusic: any = useSubjectId(SubjectEnum.MUSIC_FREE)
  149. exquisiteFlag.value = getMusic.chargeType
  150. }
  151. // if(onlySearch) {
  152. // const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
  153. // tempParams.subjectIds = getSubject.id
  154. // }
  155. //
  156. const params = reactive({
  157. search: (route.query.search as string) || '',
  158. musicSortType: (route.query.type as string) || "",
  159. // exquisiteFlag: 1,
  160. musicTagIds: route.query.tagids || '',
  161. page: 1,
  162. ...defauleParams,
  163. ...tempParams
  164. })
  165. const data = ref<any>(null)
  166. const loading = ref(false)
  167. const finished = ref(false)
  168. const isError = ref(false)
  169. const tagVisibility = ref(false)
  170. const isAudit = ref(true)
  171. const apiSuffix = ref(
  172. baseState.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
  173. )
  174. const onSearch = (value: string) => {
  175. params.page = 1
  176. params.search = value
  177. data.value = null
  178. FetchList()
  179. }
  180. const FetchList = async () => {
  181. if (loading.value) {
  182. return
  183. }
  184. loading.value = true
  185. isError.value = false
  186. const tempParams = {
  187. ...params,
  188. auditStatus: 'PASS',
  189. idAndName: params.search,
  190. createBy: teacherId
  191. }
  192. if (exquisiteFlag.value) {
  193. tempParams.chargeType = 'FREE'
  194. }
  195. if (myself) {
  196. tempParams.myself = true
  197. } else {
  198. tempParams.myself = false
  199. }
  200. try {
  201. const res = await request.post(`${apiSuffix.value}/music/sheet/list`, {
  202. data: tempParams
  203. })
  204. if (data.value) {
  205. const result = (data.value?.rows || []).concat(res.data.rows || [])
  206. data.value.rows = result
  207. }
  208. data.value = data.value || res.data
  209. params.page = res.data.pageNo + 1
  210. finished.value = res.data.pageNo >= res.data.totalPage
  211. } catch (error) {
  212. isError.value = true
  213. }
  214. loading.value = false
  215. }
  216. // 设置默认声部
  217. const setDefaultSubject = async (subjectId: any) => {
  218. try {
  219. await request.post('/api-teacher/teacher/defaultSubject', {
  220. params: {
  221. subjectId
  222. }
  223. })
  224. } catch {
  225. //
  226. }
  227. }
  228. const onComfirm = tags => {
  229. const tempTags: any = {}
  230. // 单独处理乐谱类型
  231. for (const tag in tags) {
  232. if (Number(tag) === -1) {
  233. exquisiteFlag.value = tags[tag][0] ? true : false
  234. } else {
  235. tempTags[tag] = tags[tag]
  236. }
  237. }
  238. const d = Object.values(tempTags).flat().filter(Boolean).join(',')
  239. params.musicTagIds = d
  240. params.page = 1
  241. data.value = null
  242. FetchList()
  243. tagVisibility.value = false
  244. }
  245. const onComfirmSubject = item => {
  246. // params.page = 1
  247. // params.subjectIds = item.id
  248. // data.value = null
  249. // subject.instrumentId = item.instrumentId
  250. // localStorage.setItem('userInstrumentId', item.instrumentId || "")
  251. // if (baseState.platformType === 'TEACHER') {
  252. // teacherDetaultSubject.value = {
  253. // name: item.name,
  254. // id: item.id
  255. // }
  256. // setDefaultSubject(item.id)
  257. // } else {
  258. // subject.id = item.id
  259. // subject.name = item.name
  260. // useSubjectId(
  261. // SubjectEnum.SEARCH,
  262. // JSON.stringify({
  263. // id: item.id,
  264. // name: item.name
  265. // }),
  266. // 'set'
  267. // )
  268. // }
  269. // FetchList()
  270. // subject.show = false
  271. }
  272. // const getSubject: any = useSubjectId(SubjectEnum.SEARCH)
  273. // // 处理存值的问题 - 重置数量
  274. // let tempInstrumentId = localStorage.getItem('userInstrumentId') || ''
  275. // if(tempInstrumentId === 'undefined') {
  276. // useSubjectId(SubjectEnum.SEARCH, "", "remove")
  277. // tempInstrumentId = ""
  278. // }
  279. // const subject = reactive({
  280. // show: false,
  281. // name: getSubject.id ? getSubject.name : '全部声部',
  282. // id: getSubject.id || '',
  283. // instrumentId: tempInstrumentId,
  284. // })
  285. onMounted(async () => {
  286. try {
  287. if (!browser().iPhone) {
  288. isAudit.value = false
  289. return
  290. }
  291. const { data } = await request.get(
  292. '/api-admin/appVersionInfo/queryByPlatform',
  293. {
  294. params: {
  295. platform:
  296. baseState.platformType === 'TEACHER'
  297. ? 'ios-teacher'
  298. : 'ios-student'
  299. }
  300. }
  301. )
  302. if (baseState.version > data.version) {
  303. isAudit.value = true
  304. } else {
  305. isAudit.value = false
  306. }
  307. } catch {
  308. //
  309. }
  310. })
  311. expose({
  312. onSearch,
  313. onComfirm,
  314. updateStickyHeight,
  315. onComfirmSubject
  316. })
  317. return () => {
  318. // const tagList = ((state.value && state.value.data) as any) || []
  319. return (
  320. <>
  321. {!hideSearch && (
  322. <>
  323. <TheSticky class={styles.sticky}>
  324. <ColHeader
  325. background="transparent"
  326. isFixed={false}
  327. v-slots={{
  328. content: () => (
  329. <div class={styles.woringHeader}>
  330. <i
  331. onClick={() => {
  332. if (browser().isApp) {
  333. postMessage({
  334. api: 'back'
  335. })
  336. } else {
  337. router.back()
  338. }
  339. }}
  340. class={[
  341. 'van-badge__wrapper van-icon van-icon-arrow-left van-nav-bar__arrow',
  342. styles.leftArrow
  343. ]}
  344. ></i>
  345. <Tabs
  346. class={styles.tabSection}
  347. v-model:active={params.musicSortType}
  348. shrink
  349. onClick-tab={(val) => {
  350. params.musicSortType = val.name
  351. onSearch(params.search)
  352. }}
  353. >
  354. <Tab name="" title="全部"></Tab>
  355. <Tab name="TOP" title="推荐"></Tab>
  356. <Tab name="HOT" title="热门"></Tab>
  357. <Tab name="NEW" title="最新"></Tab>
  358. </Tabs>
  359. </div>
  360. )
  361. // right: () =>
  362. // !isAudit.value && (
  363. // <span
  364. // class={styles.fleg}
  365. // onClick={() => {
  366. // // 不要看这个字段的意思
  367. // exquisiteFlag.value != exquisiteFlag.value
  368. // useSubjectId(
  369. // SubjectEnum.MUSIC_FREE,
  370. // JSON.stringify({
  371. // chargeType: exquisiteFlag.value
  372. // }),
  373. // 'set'
  374. // )
  375. // data.value = null
  376. // params.page = 1
  377. // FetchList()
  378. // }}
  379. // >
  380. // <Switch v-model={exquisiteFlag.value} size="20px" />
  381. // <span>免费</span>
  382. // </span>
  383. // )
  384. }}
  385. />
  386. <Search
  387. onSearch={onSearch}
  388. background="transparent"
  389. inputBackground="transparent"
  390. leftIcon={iconSearch}
  391. // v-slots={{
  392. // left: () => (
  393. // <div
  394. // class={styles.label}
  395. // onClick={() => (subject.show = true)}
  396. // >
  397. // {baseState.platformType === 'TEACHER'
  398. // ? teacherDetaultSubject.value.name
  399. // : subject.name}
  400. // <Icon
  401. // classPrefix="iconfont"
  402. // name="down"
  403. // size={12}
  404. // color="#fff"
  405. // />
  406. // </div>
  407. // )
  408. // }}
  409. />
  410. {/* <Tabs
  411. shrink
  412. class={styles.tagTabs}
  413. lineHeight={0}
  414. onClick-tab={(obj: any) => {
  415. params.musicTagIds = obj.name
  416. data.value = null
  417. params.page = 1
  418. FetchList()
  419. }}
  420. >
  421. <Tab title="全部" name=""></Tab>
  422. {tagList.map((tag: any) => (
  423. <Tab title={tag.name} name={tag.id}></Tab>
  424. ))}
  425. </Tabs> */}
  426. </TheSticky>
  427. <img class={styles.bgImg} src={bgImg} />
  428. </>
  429. )}
  430. {onlySearch ? (
  431. <Sticky position="top" offsetTop={stickyHeight.value as any}>
  432. <Search
  433. onSearch={onSearch}
  434. background="transparent"
  435. inputBackground="white"
  436. // leftIcon={iconSearch}
  437. class={styles.searchGroup}
  438. // v-slots={{
  439. // left: () => (
  440. // <div
  441. // class={[styles.label, styles.searchs]}
  442. // onClick={() => (subject.show = true)}
  443. // >
  444. // {baseState.platformType === 'TEACHER'
  445. // ? teacherDetaultSubject.value.name
  446. // : subject.name}
  447. // <Icon
  448. // classPrefix="iconfont"
  449. // name="down"
  450. // size={12}
  451. // color="#949597"
  452. // />
  453. // </div>
  454. // )
  455. // }}
  456. />
  457. </Sticky>
  458. ) : (
  459. ''
  460. )}
  461. <div class={[styles.alumnList, onlySearch && styles.alumnListOnly]}>
  462. <List
  463. loading={loading.value}
  464. finished={finished.value}
  465. finished-text={data.value && data.value.rows.length ? '' : ''}
  466. onLoad={FetchList}
  467. error={isError.value}
  468. >
  469. {data.value && data.value.rows.length ? (
  470. <Song
  471. list={data.value.rows}
  472. onDetail={(item: any) => {
  473. if (onItemClick === noop) {
  474. const url =
  475. location.origin +
  476. location.pathname +
  477. '#/music-detail?id=' +
  478. item.id
  479. // + '&instrumentId=' + subject.instrumentId
  480. openDefaultWebView(url, () => {
  481. router.push({
  482. path: '/music-detail',
  483. query: {
  484. id: item.id
  485. // instrumentId: subject.instrumentId
  486. }
  487. })
  488. })
  489. } else {
  490. onItemClick?.(item)
  491. }
  492. }}
  493. />
  494. ) : (
  495. !loading.value && (
  496. <ColResult
  497. tips="暂无曲目"
  498. classImgSize="SMALL"
  499. btnStatus={false}
  500. />
  501. )
  502. )}
  503. </List>
  504. </div>
  505. <Popup
  506. show={tagVisibility.value}
  507. round
  508. closeable
  509. position="bottom"
  510. style={{ height: '60%' }}
  511. teleport="body"
  512. onUpdate:show={val => (tagVisibility.value = val)}
  513. >
  514. <SelectTag
  515. exquisiteFlag
  516. onConfirm={onComfirm}
  517. onCancel={() => {
  518. //
  519. }}
  520. defaultValue={route.query.tagids as string}
  521. />
  522. </Popup>
  523. {/* 声部弹框 */}
  524. {/* <Popup
  525. show={subject.show}
  526. position="bottom"
  527. round
  528. closeable
  529. safe-area-inset-bottom
  530. onClose={() => (subject.show = false)}
  531. onClosed={() => (subject.show = false)}
  532. >
  533. <SelectSubject
  534. type="MUSIC"
  535. searchParams={
  536. baseState.platformType === 'TEACHER'
  537. ? teacherDetaultSubject.value
  538. : subject
  539. }
  540. onComfirm={onComfirmSubject}
  541. />
  542. </Popup> */}
  543. </>
  544. )
  545. }
  546. }
  547. })