index.tsx 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. import {
  2. computed,
  3. defineComponent,
  4. onMounted,
  5. reactive,
  6. ref,
  7. watch,
  8. nextTick
  9. } from 'vue'
  10. import {
  11. Image,
  12. Tabs,
  13. Tab,
  14. List,
  15. Button,
  16. Popup,
  17. Dialog,
  18. Sticky,
  19. Swipe,
  20. SwipeItem,
  21. Picker
  22. } from 'vant'
  23. import styles from './index.module.less'
  24. import TheSticky from '@/components/the-sticky'
  25. import ColHeader from '@/components/col-header'
  26. import { useWindowScroll, useEventListener } from '@vueuse/core'
  27. import request from '@/helpers/request'
  28. import iconMenu from './images/icon-menu.png'
  29. import iconRightTop from './images/icon-right-top.png'
  30. import iconAlbumCover from '../../images/icon-album-cover.png'
  31. import iconTimer from './images/icon-timer.png'
  32. import iconArrow from './images/icon-arrow.png'
  33. import { state as baseState, setLogout } from '@/state'
  34. import Song from '../component/song'
  35. import { useRoute, useRouter } from 'vue-router'
  36. import ColResult from '@/components/col-result'
  37. import { moneyFormat } from '@/helpers/utils'
  38. import { orderStatus } from '@/views/order-detail/orderStatus'
  39. import { postMessage } from '@/helpers/native-message'
  40. import { browser } from '@/helpers/utils'
  41. // Import Swiper Vue.js components
  42. // import Swiper core and required modules
  43. import { Pagination } from 'swiper/modules'
  44. import { Swiper, SwiperSlide } from 'swiper/vue'
  45. // Import Swiper styles
  46. import 'swiper/css'
  47. import 'swiper/css/pagination'
  48. import CourseItem from '../lessonCourseware/component/CourseItem'
  49. export default defineComponent({
  50. name: 'train-tool',
  51. setup() {
  52. const sessionStorageToolSubject =
  53. sessionStorage.getItem('tool-subject-type')
  54. const toolSubject =
  55. sessionStorageToolSubject && JSON.parse(sessionStorageToolSubject)
  56. sessionStorage.removeItem('tool-subject-type')
  57. const route = useRoute()
  58. const router = useRouter()
  59. const background = ref<string>('rgba(55, 205, 177, 0)')
  60. const color = ref<string>('#fff')
  61. const state = reactive({
  62. details: {} as any,
  63. buy: route.query.buy as any,
  64. albumId: route.query.albumId || null,
  65. activeTab:
  66. toolSubject?.activeTab || route.query.subjectType || 'COURSEWARE', // 有缓存 默认用缓存,之后用请求头,最后默认
  67. loadingAlbum: false,
  68. loading: false,
  69. finished: false,
  70. isError: false,
  71. list: [] as any,
  72. popupStatus: false,
  73. selectMember: {} as any, // 购买的月份
  74. ensembleCounts: false,
  75. musicCounts: false,
  76. subjectCounts: false,
  77. coursewareCounts: false,
  78. tenantAlbumStatus: 0 as any,
  79. ablumStatus: false,
  80. heightV: 0,
  81. hasBuyStatus: true, // 是否能继续购买
  82. albumList: [] as any, // 专辑列表
  83. initialSlide: 0,
  84. subjectStatus: false,
  85. openStatus: false,
  86. teacherSubjectId: null as any,
  87. teacherSubjectName: null as any,
  88. teacherSubjectIndex: 0,
  89. subjectList: [] // 声部列表
  90. })
  91. const params = reactive({
  92. page: 1,
  93. rows: 20
  94. })
  95. const apiSuffix = ref(
  96. baseState.platformType === 'STUDENT' ? '/api-student' : '/api-teacher'
  97. )
  98. const isSingleAlbum = computed(() => {
  99. const query = route.query
  100. if (query.taId || (query.albumId && state.buy === '1')) {
  101. return true
  102. } else {
  103. return false
  104. }
  105. })
  106. const getDetails = async () => {
  107. state.loadingAlbum = true
  108. try {
  109. // tenantGroupAlbum/buyAlbumInfo
  110. // 当我的曲目过来的时候才走单个查询
  111. if (state.albumId && state.buy === '1') {
  112. let url = apiSuffix.value + '/userTenantAlbumRecord/detail'
  113. if (state.albumId) {
  114. url = url + '?albumId=' + state.albumId
  115. }
  116. const { data } = await request.post(url)
  117. state.albumList = [data || {}]
  118. state.details = data || {}
  119. } else {
  120. const url =
  121. apiSuffix.value +
  122. `/tenantGroupAlbum/buyAlbumInfo?tenantGroupAlbumId=${
  123. route.query.taId || ''
  124. }`
  125. //&tenantAlbumId=${state.albumId || ''}
  126. // if (state.albumId) {
  127. // url = url + '?albumId=' + state.albumId
  128. // }
  129. const { data } = await request.get(url)
  130. state.albumList = data || []
  131. if (state.albumList.length > 0) {
  132. let index = 0
  133. // 以缓存为优先 其次 请求头 state.albumId
  134. if (toolSubject?.tenantGroupAlbumId || state.albumId) {
  135. index = state.albumList.findIndex(item => {
  136. return toolSubject?.tenantGroupAlbumId
  137. ? (baseState.platformType === 'STUDENT'
  138. ? item.tenantGroupAlbumId
  139. : item.id) === toolSubject?.tenantGroupAlbumId
  140. : item.id == state.albumId // 这里不全等 因为state.albumId为字符串 id为number
  141. })
  142. index < 0 && (index = 0)
  143. }
  144. state.initialSlide = index //默认展示第几个
  145. state.details = state.albumList[index] // 有缓存 就用缓存里面的数据
  146. } else {
  147. // state.albumList
  148. if (!browser().isApp) {
  149. Dialog.alert({
  150. title: '提示',
  151. message: '该教程不可购买',
  152. confirmButtonText: '确定',
  153. confirmButtonColor: '#2dc7aa'
  154. }).then(() => {
  155. if (browser().isApp) {
  156. postMessage({ api: 'back' })
  157. } else {
  158. setLogout()
  159. router.replace({
  160. path: '/login' as any,
  161. query: {
  162. returnUrl: '/train-tool',
  163. ...route.query
  164. }
  165. })
  166. }
  167. })
  168. }
  169. }
  170. }
  171. } catch {
  172. //
  173. }
  174. state.loadingAlbum = false
  175. }
  176. watch(
  177. () => state.details,
  178. () => {
  179. state.ensembleCounts = state.details?.ensembleCounts ? true : false
  180. state.subjectCounts = state.details?.subjectCounts ? true : false
  181. state.musicCounts = state.details?.musicCounts ? true : false
  182. state.coursewareCounts = state.details?.coursewareCounts ? true : false
  183. if (state.details.buyTimesFlag) {
  184. if (state.details.buyedTimes >= state.details.buyTimes) {
  185. state.hasBuyStatus = false
  186. } else {
  187. state.hasBuyStatus = true
  188. }
  189. } else {
  190. state.hasBuyStatus = true
  191. }
  192. }
  193. )
  194. let listController
  195. const FetchList = async (hideLoading = false) => {
  196. if (!state.details.id) {
  197. return
  198. }
  199. if (listController) {
  200. listController.abort()
  201. }
  202. state.loading = true
  203. state.isError = false
  204. const tempParams = {
  205. albumId: state.details.id || null,
  206. subjectType: state.activeTab,
  207. ...params
  208. } as any
  209. // 老师端默认查询声部
  210. if (baseState.platformType === 'TEACHER') {
  211. // const users = baseState.user.data
  212. tempParams.subjectId = state.teacherSubjectId || null
  213. }
  214. try {
  215. listController = new AbortController()
  216. const { signal } = listController
  217. const { data } = await request.post(
  218. `${apiSuffix.value}/tenantAlbumMusic/page`,
  219. {
  220. hideLoading,
  221. data: tempParams,
  222. signal
  223. }
  224. )
  225. if (state.list.length > 0 && data.pageNo === 1) {
  226. return
  227. }
  228. state.list = state.list.concat(data.rows || [])
  229. params.page = data.pageNo + 1
  230. // showContact.value = state.list.length > 0
  231. state.loading = false
  232. state.finished = data.pageNo >= data.totalPage
  233. params.page = data.pageNo + 1
  234. } catch (error) {
  235. state.isError = true
  236. }
  237. state.loading = false
  238. }
  239. const getSubjectList = async () => {
  240. try {
  241. const res = await request.get('/api-tenant/open/subject/queryPage', {
  242. data: { page: 1, rows: 9999 }
  243. })
  244. const result = res.data.rows || []
  245. result.forEach((item: any) => {
  246. item.text = item.name
  247. })
  248. state.subjectList = result || []
  249. const index = state.subjectList.findIndex(
  250. (item: any) => item.id == state.teacherSubjectId
  251. )
  252. state.teacherSubjectIndex = index === -1 ? 0 : index
  253. } catch (e) {
  254. console.log(e)
  255. }
  256. }
  257. /** 设置声部 */
  258. const operatoinCatchSubjectInfo = (
  259. type: 'set' | 'get',
  260. params?: { defaultSubject: string; defaultSubjectName: string }
  261. ) => {
  262. if (type === 'set') {
  263. localStorage.setItem(
  264. 'trainTool-teacherSubjectInfo',
  265. JSON.stringify(params)
  266. )
  267. } else if (type === 'get') {
  268. const result = localStorage.getItem('trainTool-teacherSubjectInfo')
  269. return result ? JSON.parse(result) : null
  270. }
  271. }
  272. onMounted(async () => {
  273. // useEventListener(document, 'scroll', evt => {
  274. // const { y } = useWindowScroll()
  275. // if (y.value > 20) {
  276. // background.value = `rgba(255, 255, 255)`
  277. // } else {
  278. // background.value = 'transparent'
  279. // }
  280. // })
  281. // 老师端默认查询声部
  282. if (baseState.platformType === 'TEACHER') {
  283. const users = baseState.user.data
  284. const catchSubject = operatoinCatchSubjectInfo('get')
  285. if (catchSubject) {
  286. state.teacherSubjectId = catchSubject.defaultSubject || null
  287. state.teacherSubjectName = catchSubject.defaultSubjectName || null
  288. } else {
  289. state.teacherSubjectId = users.defaultSubject || null
  290. state.teacherSubjectName = users.defaultSubjectName || null
  291. }
  292. operatoinCatchSubjectInfo('set', {
  293. defaultSubject: state.teacherSubjectId,
  294. defaultSubjectName: state.teacherSubjectName
  295. })
  296. }
  297. state.loading = true
  298. state.loadingAlbum = true
  299. await getDetails()
  300. await FetchList()
  301. getSubjectList()
  302. state.loadingAlbum = false
  303. state.loading = false
  304. // 为了处理 swiper 会不显示的问题
  305. document.body.scrollIntoView()
  306. window.scrollTo(1, 0)
  307. })
  308. function handleChangeActiveTab() {
  309. state.activeTab = state.details?.coursewareCounts
  310. ? 'COURSEWARE'
  311. : state.details?.subjectCounts
  312. ? 'SUBJECT'
  313. : state.details?.musicCounts
  314. ? 'MUSIC'
  315. : 'ENSEMBLE'
  316. }
  317. const onSubmit = async () => {
  318. const album = state.details
  319. const details = state.details
  320. orderStatus.orderObject.orderType = 'TENANT_ALBUM'
  321. orderStatus.orderObject.orderName = details.name
  322. orderStatus.orderObject.orderDesc = details.name
  323. orderStatus.orderObject.actualPrice = album.actualPrice
  324. // orderStatus.orderObject.recomUserId = route.query.recomUserId || 0
  325. // orderStatus.orderObject.activityId = route.query.activityId || 0
  326. orderStatus.orderObject.orderNo = ''
  327. orderStatus.orderObject.orderList = [
  328. {
  329. orderType: 'TENANT_ALBUM',
  330. goodsName: details.name,
  331. actualPrice: album.actualPrice,
  332. price: album.actualPrice,
  333. ...details,
  334. ...album
  335. }
  336. ]
  337. const res = await request.post('/api-student/userOrder/getPendingOrder', {
  338. data: {
  339. goodType: 'TENANT_ALBUM',
  340. bizId: details.id
  341. }
  342. })
  343. const result = res.data
  344. if (result) {
  345. state.popupStatus = false
  346. Dialog.confirm({
  347. title: '提示',
  348. message: '您有一个未支付的订单,是否继续支付?',
  349. theme: 'round-button',
  350. className: 'confirm-button-group',
  351. cancelButtonText: '取消订单',
  352. confirmButtonText: '继续支付'
  353. })
  354. .then(async () => {
  355. orderStatus.orderObject.orderNo = result.orderNo
  356. orderStatus.orderObject.actualPrice = result.actualPrice
  357. orderStatus.orderObject.discountPrice = result.discountPrice
  358. orderStatus.orderObject.paymentConfig = {
  359. ...result.paymentConfig,
  360. paymentVendor: result.paymentVendor,
  361. paymentVersion: result.paymentVersion
  362. }
  363. routerTo()
  364. })
  365. .catch(() => {
  366. Dialog.close()
  367. // 只用取消订单,不用做其它处理
  368. cancelPayment(result.orderNo)
  369. })
  370. } else {
  371. routerTo()
  372. }
  373. }
  374. const routerTo = () => {
  375. const album = state.details
  376. sessionStorage.setItem(
  377. 'tool-subject-type',
  378. JSON.stringify({
  379. activeTab: state.activeTab,
  380. tenantGroupAlbumId:
  381. baseState.platformType === 'STUDENT'
  382. ? state.details.tenantGroupAlbumId
  383. : state.details.id // 老师用专辑id当唯一值
  384. })
  385. )
  386. router.push({
  387. path: '/orderDetail',
  388. query: {
  389. orderType: 'ALBUM',
  390. album: album.id
  391. }
  392. })
  393. }
  394. const cancelPayment = async (orderNo: string) => {
  395. try {
  396. await request.post('/api-student/userOrder/orderCancel/v2', {
  397. data: {
  398. orderNo
  399. }
  400. })
  401. } catch {
  402. //
  403. }
  404. }
  405. return () => (
  406. <div class={styles.trainTool}>
  407. {!state.loading && !state.details.id && state.buy != '1' ? (
  408. <>
  409. <TheSticky
  410. class={styles.theSticky}
  411. position="top"
  412. onBarHeight={(height: any) => {
  413. console.log(height, 'height', height)
  414. state.heightV = height
  415. }}
  416. >
  417. <ColHeader border={false} isFixed={false} />
  418. </TheSticky>
  419. {!state.loading && (
  420. <div
  421. class={styles.colResultBox}
  422. style={{
  423. height: 'calc(100vh - var(--header-height))',
  424. display: 'flex',
  425. alignItems: 'center'
  426. }}
  427. >
  428. <ColResult
  429. tips="暂无教程"
  430. classImgSize="SMALL"
  431. btnStatus={false}
  432. />
  433. </div>
  434. )}
  435. </>
  436. ) : (
  437. !state.loadingAlbum && (
  438. <>
  439. <TheSticky
  440. class={styles.theSticky}
  441. position="top"
  442. onBarHeight={(height: any) => {
  443. state.heightV = height
  444. }}
  445. >
  446. <ColHeader
  447. background={background.value}
  448. border={false}
  449. isFixed={false}
  450. hideHeader={route.query.taId ? true : false}
  451. // color={color.value}
  452. // backIconColor="white"
  453. >
  454. {{
  455. right: () =>
  456. baseState.platformType === 'TEACHER' && (
  457. <div
  458. class={styles.changeSubjectSection}
  459. onClick={() => {
  460. state.subjectStatus = true
  461. }}
  462. >
  463. <span class={styles.subjectName}>
  464. {state.teacherSubjectName}
  465. </span>
  466. <img
  467. class={state.subjectStatus && styles.active}
  468. src={iconArrow}
  469. />
  470. </div>
  471. )
  472. }}
  473. </ColHeader>
  474. </TheSticky>
  475. {/* <img class={styles.bgImg} src={state.details?.coverImg} /> */}
  476. <div class={styles.musicContent}></div>
  477. <div class={styles.bg}>
  478. <div class={styles.alumWrap}>
  479. {isSingleAlbum.value ? (
  480. <div class={styles.singleAlbum}>
  481. <div class={styles.img}>
  482. {state.details?.buyTimesFlag && (
  483. <span class={styles.quota}>
  484. 限购:{state.details?.buyedTimes}/
  485. {state.details?.buyTimes}次
  486. </span>
  487. )}
  488. <Image
  489. class={styles.image}
  490. width="100%"
  491. height="100%"
  492. fit="cover"
  493. src={state.details?.coverImg || iconAlbumCover}
  494. errorIcon={iconAlbumCover}
  495. />
  496. <div class={styles.iconPian}></div>
  497. </div>
  498. </div>
  499. ) : (
  500. state.albumList &&
  501. state.albumList.length > 0 && (
  502. <Swiper
  503. initialSlide={state.initialSlide}
  504. watchSlidesProgress={true}
  505. slidesPerView={'auto'}
  506. centeredSlides={true}
  507. modules={[Pagination]}
  508. pagination={{ clickable: true }}
  509. // onTransitionEnd={(swiper: any) => {}} onSlideChange
  510. onSlideChange={(swiper: any) => {
  511. state.details = state.albumList[swiper.activeIndex]
  512. // 等tab渲染完了之后再切换 不然tab会自动重新赋值
  513. nextTick(() => {
  514. // 当有初始值的时候不刷新
  515. if (state.initialSlide) {
  516. state.initialSlide = 0
  517. return
  518. }
  519. handleChangeActiveTab()
  520. params.page = 1
  521. state.list = []
  522. FetchList(true)
  523. })
  524. }}
  525. >
  526. {state.albumList.map((album: any) => (
  527. <SwiperSlide>
  528. <div class={styles.img}>
  529. {album.buyTimesFlag && (
  530. <span class={styles.quota}>
  531. 限购{album.buyedTimes}/{album.buyTimes}次
  532. </span>
  533. )}
  534. <Image
  535. class={styles.image}
  536. width="100%"
  537. height="100%"
  538. fit="cover"
  539. src={album?.coverImg || iconAlbumCover}
  540. errorIcon={iconAlbumCover}
  541. />
  542. <div class={styles.iconPian}></div>
  543. </div>
  544. </SwiperSlide>
  545. ))}
  546. </Swiper>
  547. )
  548. )}
  549. <div class={styles.alumDes}>
  550. <div class={[styles.alumTitle, 'van-ellipsis']}>
  551. {state.details?.name}
  552. </div>
  553. <div
  554. class={[styles.des, 'van-multi-ellipsis--l2']}
  555. style={{
  556. height: '32px',
  557. lineHeight: '16px'
  558. }}
  559. >
  560. {state.details?.describe}
  561. </div>
  562. </div>
  563. {state.buy != '1' && baseState.platformType === 'STUDENT' && (
  564. <div class={styles.albumPriceGroup}>
  565. <div class={styles.albumTimer}>
  566. <img src={iconTimer} class={styles.iconTimer} />
  567. <span>有效期:{state.details?.purchaseNum || 0}天</span>
  568. </div>
  569. <div class={styles.albumPriceList}>
  570. {(state.details?.originalPrice || 0) >
  571. (state.details?.actualPrice || 0) && (
  572. <del class={styles.originPrice}>
  573. 原价:¥
  574. {moneyFormat(state.details?.originalPrice || 0)}
  575. </del>
  576. )}
  577. <span class={styles.currentPrice}>
  578. <span>
  579. ¥{moneyFormat(state.details?.actualPrice || 0)}
  580. </span>
  581. </span>
  582. </div>
  583. </div>
  584. )}
  585. </div>
  586. </div>
  587. <div class={styles.musicList}>
  588. <Sticky position="top" offsetTop={state.heightV}>
  589. <Tabs
  590. color="var(--van-primary)"
  591. background="transparent"
  592. lineWidth={20}
  593. shrink
  594. v-model:active={state.activeTab}
  595. onClick-tab={val => {
  596. state.activeTab = val.name
  597. params.page = 1
  598. state.list = []
  599. FetchList()
  600. }}
  601. >
  602. {state.coursewareCounts && (
  603. <Tab title="云课堂" name="COURSEWARE"></Tab>
  604. )}
  605. {state.subjectCounts && (
  606. <Tab title="声部云练" name="SUBJECT"></Tab>
  607. )}
  608. {state.musicCounts && (
  609. <Tab title="独奏云练" name="MUSIC"></Tab>
  610. )}
  611. {state.ensembleCounts && (
  612. <Tab title="合奏云练" name="ENSEMBLE"></Tab>
  613. )}
  614. </Tabs>
  615. </Sticky>
  616. <div
  617. class={[
  618. styles.alumnList,
  619. state.activeTab === 'COURSEWARE'
  620. ? styles.alumnListCourseware
  621. : ''
  622. ]}
  623. >
  624. <List
  625. loading={state.loading}
  626. finished={state.finished}
  627. finished-text={' '}
  628. onLoad={FetchList}
  629. immediateCheck={false}
  630. error={state.isError}
  631. >
  632. {state.list && state.list.length ? (
  633. state.activeTab === 'COURSEWARE' ? (
  634. <CourseItem
  635. list={state.list.map(item => {
  636. return {
  637. name: item.musicSheetName,
  638. coverImg: item.titleImg,
  639. id: item.id
  640. }
  641. })}
  642. onItemClick={row => {
  643. sessionStorage.setItem(
  644. 'tool-subject-type',
  645. JSON.stringify({
  646. activeTab: state.activeTab,
  647. tenantGroupAlbumId:
  648. baseState.platformType === 'STUDENT'
  649. ? state.details.tenantGroupAlbumId
  650. : state.details.id // 老师用专辑id当唯一值
  651. })
  652. )
  653. router.push({
  654. path: '/courseList',
  655. query: {
  656. id: row.id,
  657. albumId: state.details.id,
  658. taId: state.details.tenantGroupAlbumId, // 当通过我的曲目进来的时候 这个值为空
  659. buyStatus: state.hasBuyStatus ? '0' : '1' //默认能购买
  660. }
  661. })
  662. }}
  663. />
  664. ) : (
  665. <Song
  666. showNumber
  667. list={state.list}
  668. onDetail={(item: any) => {
  669. sessionStorage.setItem(
  670. 'tool-subject-type',
  671. JSON.stringify({
  672. activeTab: state.activeTab,
  673. tenantGroupAlbumId:
  674. baseState.platformType === 'STUDENT'
  675. ? state.details.tenantGroupAlbumId
  676. : state.details.id // 老师用专辑id当唯一值
  677. })
  678. )
  679. router.push({
  680. path: '/music-detail',
  681. query: {
  682. id: item.id,
  683. tenantAlbumId: item.tenantAlbumId,
  684. taId: state.details.tenantGroupAlbumId, // 当通过我的曲目进来的时候 这个值为空
  685. buyStatus: state.hasBuyStatus ? '0' : '1' //默认能购买
  686. }
  687. })
  688. }}
  689. />
  690. )
  691. ) : (
  692. !state.loading && (
  693. <ColResult
  694. tips={
  695. state.activeTab === 'COURSEWARE'
  696. ? '暂无教材'
  697. : '暂无曲目'
  698. }
  699. classImgSize="SMALL"
  700. btnStatus={false}
  701. />
  702. )
  703. )}
  704. </List>
  705. </div>
  706. </div>
  707. {baseState.platformType === 'STUDENT' && state.buy != '1' && (
  708. <TheSticky position="bottom">
  709. <div class={styles.btnGroup}>
  710. <Button
  711. round
  712. block
  713. disabled={!state.hasBuyStatus}
  714. color="linear-gradient(270deg, #FF204B 0%, #FE5B71 100%)"
  715. onClick={onSubmit}
  716. >
  717. 开通训练教程
  718. </Button>
  719. </div>
  720. </TheSticky>
  721. )}
  722. </>
  723. )
  724. )}
  725. {/* 选择声部 */}
  726. <Popup
  727. show={state.subjectStatus}
  728. position="bottom"
  729. round
  730. safe-area-inset-bottom
  731. onClose={() => (state.subjectStatus = false)}
  732. onClosed={() => (state.openStatus = false)}
  733. >
  734. <Picker
  735. defaultIndex={state.teacherSubjectIndex}
  736. columns={state.subjectList}
  737. onCancel={() => {
  738. state.subjectStatus = false
  739. }}
  740. onConfirm={(val: any) => {
  741. state.teacherSubjectId = val.id
  742. state.teacherSubjectName = val.name
  743. params.page = 1
  744. state.finished = false
  745. state.list = []
  746. FetchList()
  747. state.subjectStatus = false
  748. operatoinCatchSubjectInfo('set', {
  749. defaultSubject: state.teacherSubjectId,
  750. defaultSubjectName: state.teacherSubjectName
  751. })
  752. }}
  753. ></Picker>
  754. </Popup>
  755. </div>
  756. )
  757. }
  758. })