index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. import {
  2. PropType,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref,
  8. toRef
  9. } from 'vue';
  10. import styles from './index.module.less';
  11. import { NTabs, NTabPane, NModal } from 'naive-ui';
  12. import SelectMusicModal from '../../model/select-music';
  13. import { usePrepareStore } from '/src/store/modules/prepareLessons';
  14. import SelectResources from '../../model/select-resources';
  15. import SelectMusic, { typeFormat } from './components/select-music';
  16. import ResourceItem from './components/resource-item';
  17. import TrainUpdate from '/src/views/attend-class/model/train-update';
  18. import requestOrigin from 'umi-request';
  19. import { eventGlobal } from '/src/utils';
  20. import useDrag from '@/hooks/useDrag';
  21. import Dragbom from '@/hooks/useDrag/dragbom';
  22. import { useUserStore } from '@/store/modules/users';
  23. import { useCatchStore } from '/src/store/modules/catchData';
  24. import { modalClickMask } from '/src/state';
  25. export default defineComponent({
  26. name: 'resource-main',
  27. props: {
  28. /** 类型 */
  29. cardType: {
  30. type: String as PropType<'' | 'homerowk-record' | 'prepare'>,
  31. default: ''
  32. },
  33. from: {
  34. // 来自哪里
  35. type: String,
  36. default: ''
  37. }
  38. },
  39. setup(props, { expose }) {
  40. const prepareStore = usePrepareStore();
  41. const catchStore = useCatchStore();
  42. const forms = reactive({
  43. tabType: 'relateResources',
  44. tabWorkType: 'myMusic',
  45. selectMusicStatus: false,
  46. selectResourceStatus: false,
  47. editStatus: false,
  48. editItem: {} as any,
  49. searchGroup: {} as any
  50. });
  51. const relateResourcesRef = ref();
  52. const shareResourcesRef = ref();
  53. const myResourcesRef = ref();
  54. const myCollectRef = ref();
  55. const tabRef = ref();
  56. const workRef = ref();
  57. const onAdd = async (item: any) => {
  58. let xmlStatus = 'init';
  59. // 第一个声部小节
  60. let firstMeasures: any = null;
  61. try {
  62. // 获取文件
  63. const res = await requestOrigin.get(item.xmlFileUrl, {
  64. mode: 'cors'
  65. });
  66. const xmlParse = new DOMParser().parseFromString(res, 'text/xml');
  67. /**
  68. * 妙极客的曲子,systems中含有part标签,需过滤掉systems标签,xmlParse.querySelectorAll('systems')
  69. */
  70. const systems = Array.from(xmlParse?.querySelectorAll('systems')) || [];
  71. systems.forEach((system: any) => {
  72. const childs = Array.from(system?.querySelectorAll('system')) || [];
  73. childs.forEach((child: any) => {
  74. system?.removeChild(child);
  75. })
  76. });
  77. const parts = xmlParse.getElementsByTagName('part');
  78. firstMeasures = parts[0]?.getElementsByTagName('measure');
  79. xmlStatus = 'success';
  80. } catch (error) {
  81. xmlStatus = 'error';
  82. }
  83. // 判断读取小节数
  84. if (xmlStatus == 'success') {
  85. // 标记xml是否是从0小节开始
  86. item.firstMeasureIsZero = firstMeasures?.[0]?.getAttribute('number') === '0';
  87. item.practiceChapterMax = item.firstMeasureIsZero ? firstMeasures.length - 1 : firstMeasures.length;
  88. } else {
  89. item.practiceChapterMax = 0;
  90. }
  91. item.coursewareKnowledgeDetailId = prepareStore.getSelectKey;
  92. item.subjectId = prepareStore.getSubjectId;
  93. forms.editItem = item;
  94. forms.editStatus = true;
  95. };
  96. const resetTabPosition = () => {
  97. nextTick(() => {
  98. tabRef.value?.syncBarPosition();
  99. workRef.value?.syncBarPosition();
  100. });
  101. };
  102. onMounted(async () => {
  103. resetTabPosition();
  104. // 获取教材分类列表
  105. await catchStore.getMusicSheetCategory(true);
  106. });
  107. // 弹窗拖动
  108. // 曲目资源
  109. let selectResourceStatusAddBoxDragData: any;
  110. let selectResourceStatusAddBoxClass: string;
  111. if (props.from === 'class') {
  112. const users = useUserStore();
  113. selectResourceStatusAddBoxClass = 'selectResourceStatusAddBoxClass_drag';
  114. selectResourceStatusAddBoxDragData = useDrag(
  115. [
  116. `${selectResourceStatusAddBoxClass} .select-resource>.n-tabs>.n-tabs-nav--top.n-tabs-nav`,
  117. `${selectResourceStatusAddBoxClass} .bom_drag`
  118. ],
  119. selectResourceStatusAddBoxClass,
  120. toRef(forms, 'selectMusicStatus'),
  121. users.info.id
  122. );
  123. }
  124. // 曲目资源 作业设置
  125. let workSetingBoxDragData: any;
  126. let workSetingBoxClass: string;
  127. if (props.from === 'class') {
  128. const users = useUserStore();
  129. workSetingBoxClass = 'workSetingBoxClass_drag';
  130. workSetingBoxDragData = useDrag(
  131. [
  132. `${workSetingBoxClass}>.n-card-header`,
  133. `${workSetingBoxClass} .bom_drag`
  134. ],
  135. workSetingBoxClass,
  136. toRef(forms, 'editStatus'),
  137. users.info.id
  138. );
  139. }
  140. //
  141. expose({
  142. resetTabPosition
  143. });
  144. return () => (
  145. <div
  146. class={[
  147. styles['resource-main'],
  148. forms.selectMusicStatus || forms.selectResourceStatus
  149. ? styles.resourceClose
  150. : ''
  151. ]}>
  152. {prepareStore.getTabType === 'courseware' &&
  153. !['homerowk-record', 'prepare'].includes(props.cardType) ? (
  154. <NTabs
  155. id="lessonsIn-0"
  156. ref={tabRef}
  157. animated
  158. class={styles.homerowkTabs}
  159. value={forms.tabType}
  160. paneClass={styles.paneTitle}
  161. paneWrapperClass={styles.paneWrapperContainer}
  162. onUpdate:value={(val: string) => {
  163. forms.tabType = val;
  164. }}>
  165. {{
  166. suffix: () => (
  167. <div
  168. class={styles.iconScreen}
  169. onClick={() => {
  170. let searchGroup: any = {};
  171. if (forms.tabType === 'relateResources') {
  172. searchGroup = relateResourcesRef.value?.getParams();
  173. } else if (forms.tabType === 'shareResources') {
  174. searchGroup = shareResourcesRef.value?.getParams();
  175. } else if (forms.tabType === 'myResources') {
  176. searchGroup = myResourcesRef.value?.getParams();
  177. } else if (forms.tabType === 'myCollect') {
  178. searchGroup = myCollectRef.value?.getParams();
  179. }
  180. forms.searchGroup = searchGroup;
  181. forms.selectResourceStatus = true;
  182. prepareStore.setSelectResourceStatus(true);
  183. }}>
  184. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  185. <g fill="none">
  186. <path
  187. d="M5 6a1 1 0 0 1 1-1h2a1 1 0 0 0 0-2H6a3 3 0 0 0-3 3v2a1 1 0 0 0 2 0V6zm0 12a1 1 0 0 0 1 1h2a1 1 0 1 1 0 2H6a3 3 0 0 1-3-3v-2a1 1 0 1 1 2 0v2zM18 5a1 1 0 0 1 1 1v2a1 1 0 1 0 2 0V6a3 3 0 0 0-3-3h-2a1 1 0 1 0 0 2h2zm1 13a1 1 0 0 1-1 1h-2a1 1 0 1 0 0 2h2a3 3 0 0 0 3-3v-2a1 1 0 1 0-2 0v2z"
  188. fill="#198CFE"></path>
  189. </g>
  190. </svg>
  191. </div>
  192. ),
  193. default: () => (
  194. <>
  195. <NTabPane name="relateResources" tab="相关资源">
  196. <ResourceItem
  197. type="relateResources"
  198. ref={relateResourcesRef}
  199. />
  200. </NTabPane>
  201. <NTabPane
  202. name="shareResources"
  203. tab="共享资源"
  204. // displayDirective="show:lazy"
  205. >
  206. <ResourceItem
  207. type="shareResources"
  208. ref={shareResourcesRef}
  209. />
  210. </NTabPane>
  211. <NTabPane
  212. name="myResources"
  213. tab="我的资源"
  214. // displayDirective="show:lazy"
  215. >
  216. <ResourceItem type="myResources" ref={myResourcesRef} />
  217. </NTabPane>
  218. <NTabPane
  219. name="myCollect"
  220. tab="我的收藏"
  221. // displayDirective="show:lazy"
  222. >
  223. <ResourceItem type="myCollect" ref={myCollectRef} />
  224. </NTabPane>
  225. </>
  226. )
  227. }}
  228. </NTabs>
  229. ) : (
  230. <NTabs
  231. ref={workRef}
  232. animated
  233. value={forms.tabWorkType}
  234. paneClass={styles.paneTitle}
  235. paneWrapperClass={styles.paneWrapperContainer}
  236. onUpdate:value={(val: string) => {
  237. forms.tabWorkType = val;
  238. }}>
  239. {{
  240. suffix: () => (
  241. <div
  242. class={styles.iconScreen}
  243. onClick={() => {
  244. forms.selectMusicStatus = true;
  245. prepareStore.setSelectMusicStatus(true);
  246. }}>
  247. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  248. <g fill="none">
  249. <path
  250. d="M5 6a1 1 0 0 1 1-1h2a1 1 0 0 0 0-2H6a3 3 0 0 0-3 3v2a1 1 0 0 0 2 0V6zm0 12a1 1 0 0 0 1 1h2a1 1 0 1 1 0 2H6a3 3 0 0 1-3-3v-2a1 1 0 1 1 2 0v2zM18 5a1 1 0 0 1 1 1v2a1 1 0 1 0 2 0V6a3 3 0 0 0-3-3h-2a1 1 0 1 0 0 2h2zm1 13a1 1 0 0 1-1 1h-2a1 1 0 1 0 0 2h2a3 3 0 0 0 3-3v-2a1 1 0 1 0-2 0v2z"
  251. fill="#198CFE"></path>
  252. </g>
  253. </svg>
  254. </div>
  255. ),
  256. default: () => (
  257. <>
  258. <NTabPane name="myMusic" tab="我的曲目">
  259. <SelectMusic
  260. from={props.from}
  261. cardType={props.cardType}
  262. type="myMusic"
  263. />
  264. </NTabPane>
  265. <NTabPane name="sahreMusic" tab="共享曲目">
  266. <SelectMusic
  267. from={props.from}
  268. cardType={props.cardType}
  269. type="sahreMusic"
  270. />
  271. </NTabPane>
  272. <NTabPane name="collectMusic" tab="收藏曲目">
  273. <SelectMusic
  274. from={props.from}
  275. cardType={props.cardType}
  276. type="collectMusic"
  277. />
  278. </NTabPane>
  279. </>
  280. )
  281. }}
  282. </NTabs>
  283. )}
  284. <NModal
  285. maskClosable={modalClickMask}
  286. v-model:show={forms.selectResourceStatus}
  287. onUpdate:show={(val: any) => {
  288. if (!val) {
  289. prepareStore.setSelectResourceStatus(val);
  290. }
  291. }}
  292. class={['modalTitle', styles.selectMusicModal]}
  293. preset="card"
  294. title={'选择资源'}>
  295. <SelectResources
  296. type={forms.tabType}
  297. searchGroup={forms.searchGroup}
  298. />
  299. </NModal>
  300. <NModal
  301. maskClosable={modalClickMask}
  302. style={
  303. props.from === 'class'
  304. ? selectResourceStatusAddBoxDragData.styleDrag.value
  305. : {}
  306. }
  307. v-model:show={forms.selectMusicStatus}
  308. onUpdate:show={(val: any) => {
  309. if (!val) {
  310. prepareStore.setSelectMusicStatus(val);
  311. }
  312. }}
  313. class={[
  314. 'modalTitle',
  315. styles.selectMusicModal,
  316. selectResourceStatusAddBoxClass
  317. ]}
  318. preset="card"
  319. title={'选择曲目'}>
  320. <SelectMusicModal
  321. from={props.from}
  322. cardType={props.cardType}
  323. onAdd={(item: any) => onAdd(item)}
  324. />
  325. {props.from === 'class' && <Dragbom></Dragbom>}
  326. </NModal>
  327. <NModal
  328. maskClosable={modalClickMask}
  329. style={
  330. props.from === 'class' ? workSetingBoxDragData.styleDrag.value : {}
  331. }
  332. v-model:show={forms.editStatus}
  333. class={[
  334. 'modalTitle background',
  335. styles.trainEditModal,
  336. workSetingBoxClass
  337. ]}
  338. preset="card"
  339. title="作业设置">
  340. <TrainUpdate
  341. item={forms.editItem}
  342. onClose={() => (forms.editStatus = false)}
  343. onConfirm={(item: any) => {
  344. const tList = typeFormat(
  345. item.trainingType,
  346. item.trainingConfigJson
  347. );
  348. const train = {
  349. ...item,
  350. id: null,
  351. musicName: forms.editItem.title,
  352. typeList: tList
  353. };
  354. eventGlobal.emit('onTrainAddItem', train);
  355. }}
  356. />
  357. {props.from === 'class' && <Dragbom></Dragbom>}
  358. </NModal>
  359. </div>
  360. );
  361. }
  362. });