index.tsx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. import {
  2. defineComponent,
  3. onMounted,
  4. reactive,
  5. watch,
  6. ref,
  7. PropType,
  8. onUnmounted,
  9. toRef
  10. } from 'vue';
  11. import styles from './index.module.less';
  12. import {
  13. NButton,
  14. NInput,
  15. NModal,
  16. NScrollbar,
  17. NSelect,
  18. NSpace,
  19. NSpin,
  20. useDialog,
  21. useMessage
  22. } from 'naive-ui';
  23. import { usePrepareStore } from '/src/store/modules/prepareLessons';
  24. import { useCatchStore } from '/src/store/modules/catchData';
  25. import TrainType from '/src/views/attend-class/model/train-type';
  26. import TheEmpty from '/src/components/TheEmpty';
  27. import Draggable from 'vuedraggable';
  28. import {
  29. lessonPreTrainingBatchSave,
  30. lessonPreTrainingPage,
  31. lessonPreTrainingDelete,
  32. lessonPreTrainingV2Detail,
  33. lessonPreTrainingV2Save
  34. } from '../../../api';
  35. import { evaluateDifficult } from '/src/utils/contants';
  36. import TrainUpdate from '/src/views/attend-class/model/train-update';
  37. import AssignHomework from './assign-homework';
  38. import Trainguide from '@/custom-plugins/guide-page/train-guide';
  39. import { eventGlobal } from '/src/utils';
  40. import iconTips from '../../../images/icon-tips.png';
  41. import { typeFormat } from '../../resource-main/components/select-music';
  42. import TheMessageDialog from '/src/components/TheMessageDialog';
  43. import { useResizeObserver } from '@vueuse/core';
  44. import useDrag from '@/hooks/useDrag';
  45. import Dragbom from '@/hooks/useDrag/dragbom';
  46. import { useUserStore } from '@/store/modules/users';
  47. import request from '/src/utils/request';
  48. export default defineComponent({
  49. name: 'courseware-modal',
  50. props: {
  51. lessonPreTraining: {
  52. type: Object,
  53. default: () => ({})
  54. },
  55. cardType: {
  56. type: String as PropType<'' | 'homeworkRecord' | 'prepare'>,
  57. default: ''
  58. },
  59. /** 编辑编号 - 目前从上传传 */
  60. classGroupId: {
  61. type: String,
  62. default: ''
  63. },
  64. /** 编辑编号 - 目前从上传传 */
  65. coursewareKnowledgeDetailId: {
  66. type: String,
  67. default: ''
  68. },
  69. /** 编辑编号 - 目前从上传传 */
  70. courseScheduleId: {
  71. type: String,
  72. default: ''
  73. },
  74. from: {
  75. // 来自哪里
  76. type: String,
  77. default: ''
  78. }
  79. },
  80. emits: ['change'],
  81. setup(props, { emit }) {
  82. console.log(props.courseScheduleId, 'courseScheduleId');
  83. const catchStore = useCatchStore();
  84. const prepareStore = usePrepareStore();
  85. const dialog = useDialog();
  86. const message = useMessage();
  87. const forms = reactive({
  88. title: props.lessonPreTraining?.title,
  89. preBtnLoading: false,
  90. showAttendClass: false,
  91. list: [] as any,
  92. drag: true,
  93. loadingStatus: false,
  94. trainList: [] as any,
  95. assignHomeworkStatus: false,
  96. editStatus: false,
  97. editItem: {} as any,
  98. removeIds: [] as any, // 临时删除的编号
  99. removeVisiable1: false,
  100. preSaveVisiable: false
  101. });
  102. // const showGuide = ref(false);
  103. // 获取列表
  104. const getList = async () => {
  105. forms.loadingStatus = true;
  106. try {
  107. // 判断是否有选择对应的课件
  108. // console.log(props.lessonPreTraining, 'props.lessonPreTraining');
  109. if (!props.lessonPreTraining?.id) return (forms.loadingStatus = false);
  110. const { data } = await lessonPreTrainingV2Detail({
  111. id: props.lessonPreTraining?.id
  112. });
  113. const tempRows = data.lessonPreTrainingDetails || [];
  114. const temp: any = [];
  115. forms.title = data.title;
  116. tempRows.forEach((row: any) => {
  117. let tList: string[] = [];
  118. const configJson = row.trainingConfigJson;
  119. if (row.trainingType === 'EVALUATION') {
  120. tList = [
  121. `${evaluateDifficult[configJson.evaluateDifficult]}`,
  122. configJson.practiceChapterBegin || configJson.practiceChapterEnd
  123. ? `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`
  124. : '全部小节',
  125. // `速度${configJson.evaluateSpeed}`,
  126. `${configJson.trainingTimes}分合格`
  127. ];
  128. } else {
  129. tList = [
  130. `${configJson.practiceChapterBegin}-${configJson.practiceChapterEnd}小节`,
  131. `速度${configJson.practiceSpeed}`,
  132. `${configJson.trainingTimes}分钟`
  133. ];
  134. }
  135. temp.push({
  136. typeList: tList || [],
  137. ...row
  138. });
  139. });
  140. prepareStore.setTrainList(temp || []);
  141. const tempCourse: any = [];
  142. temp.forEach((item: any) => {
  143. if (!forms.removeIds.includes(item.id)) {
  144. tempCourse.push(item);
  145. }
  146. });
  147. forms.trainList = tempCourse || [];
  148. } catch {
  149. //
  150. }
  151. forms.loadingStatus = false;
  152. };
  153. // 监听选择的key 左侧选择了其它的课
  154. watch(
  155. () => prepareStore.getSelectKey,
  156. () => {
  157. eventGlobal.emit('teacher-slideshow', false);
  158. emit('change', { status: false });
  159. forms.trainList = [];
  160. getList();
  161. }
  162. );
  163. // 删除
  164. const onDelete = (item: any) => {
  165. forms.removeIds.push(item.id);
  166. const index = forms.trainList.findIndex((c: any) => c.id === item.id);
  167. forms.trainList.splice(index, 1);
  168. };
  169. // 单个删除
  170. const onRemove = async (item: any) => {
  171. try {
  172. dialog.warning({
  173. title: '提示',
  174. content: '该训练已下架,是否删除?',
  175. positiveText: '确定',
  176. negativeText: '取消',
  177. onPositiveClick: async () => {
  178. forms.removeIds.push(item.id);
  179. await lessonPreTrainingDelete({ ids: item.id });
  180. message.success('删除成功');
  181. getList();
  182. }
  183. });
  184. } catch {
  185. //
  186. }
  187. };
  188. /** 保存预设 */
  189. const onPreSave = async () => {
  190. forms.preBtnLoading = true;
  191. try {
  192. const lessonPreTrainingDetails: any = [];
  193. forms.trainList.forEach((item: any) => {
  194. lessonPreTrainingDetails.push({
  195. trainingType: item.trainingType,
  196. musicId: item.musicId,
  197. trainingConfigJson: item.trainingConfigJson,
  198. musicName: item.musicName
  199. });
  200. });
  201. const { data } = await lessonPreTrainingV2Save({
  202. title: forms.title,
  203. id: props.lessonPreTraining?.id,
  204. coursewareKnowledgeDetailId:
  205. props.coursewareKnowledgeDetailId || prepareStore.getSelectKey,
  206. lessonPreTrainingDetails,
  207. courseScheduleId: props.courseScheduleId,
  208. chapterLessonCoursewareId: props.lessonPreTraining?.chapterId
  209. });
  210. message.success('保存成功');
  211. prepareStore.setIsEditTrain(false);
  212. forms.removeIds = [];
  213. // getList();
  214. emit('change', {
  215. status: false,
  216. saveWork: true,
  217. lessonPreTrainingId: data.id
  218. });
  219. } catch {
  220. //
  221. }
  222. forms.preBtnLoading = false;
  223. };
  224. const getModalHeight = () => {
  225. const dom: any = document.querySelector('#model-homework-height');
  226. if (dom) {
  227. useResizeObserver(dom as HTMLElement, (entries: any) => {
  228. const entry = entries[0];
  229. const { height } = entry.contentRect;
  230. dom.style.setProperty('--window-page-lesson-height', height + 'px');
  231. });
  232. }
  233. };
  234. onMounted(async () => {
  235. getModalHeight();
  236. await getList();
  237. // 动态添加数据
  238. eventGlobal.on('onTrainAddItem', (item: any) => {
  239. forms.drag = true;
  240. // 临时储存编号
  241. item.id = item.id || new Date().getTime() + '__tmp';
  242. forms.trainList.push(item);
  243. prepareStore.setTrainList(forms.trainList);
  244. });
  245. });
  246. onUnmounted(() => {
  247. forms.trainList = [];
  248. prepareStore.setTrainList([]);
  249. });
  250. // 弹窗拖动
  251. // 作业设置
  252. let workSetingBoxDragData: any;
  253. let workSetingBoxClass: string;
  254. if (props.from === 'class') {
  255. const users = useUserStore();
  256. workSetingBoxClass = 'workSetingBoxClass_drag';
  257. workSetingBoxDragData = useDrag(
  258. [
  259. `${workSetingBoxClass}>.n-card-header`,
  260. `${workSetingBoxClass} .bom_drag`
  261. ],
  262. workSetingBoxClass,
  263. toRef(forms, 'editStatus'),
  264. users.info.id
  265. );
  266. }
  267. // 清空
  268. let workClearBoxDragData: any;
  269. let workClearBoxClass: string;
  270. if (props.from === 'class') {
  271. const users = useUserStore();
  272. workClearBoxClass = 'workClearBoxClass_drag';
  273. workClearBoxDragData = useDrag(
  274. [
  275. `${workClearBoxClass}>.n-card-header`,
  276. `${workClearBoxClass} .bom_drag`
  277. ],
  278. workClearBoxClass,
  279. toRef(forms, 'removeVisiable1'),
  280. users.info.id
  281. );
  282. }
  283. // 清空
  284. let workSaveBoxDragData: any;
  285. let workSaveBoxClass: string;
  286. if (props.from === 'class') {
  287. const users = useUserStore();
  288. workSaveBoxClass = 'workSaveBoxClass_drag';
  289. workSaveBoxDragData = useDrag(
  290. [`${workSaveBoxClass}>.n-card-header`, `${workSaveBoxClass} .bom_drag`],
  291. workSaveBoxClass,
  292. toRef(forms, 'preSaveVisiable'),
  293. users.info.id
  294. );
  295. }
  296. // 立即布置
  297. let workArrangeImmediatelyBoxDragData: any;
  298. let workArrangeImmediatelyBoxClass: string;
  299. if (props.from === 'class') {
  300. const users = useUserStore();
  301. workArrangeImmediatelyBoxClass = 'workArrangeImmediatelyBoxClass_drag';
  302. workArrangeImmediatelyBoxDragData = useDrag(
  303. [
  304. `${workArrangeImmediatelyBoxClass}>.n-card-header`,
  305. `${workArrangeImmediatelyBoxClass} .bom_drag`
  306. ],
  307. workArrangeImmediatelyBoxClass,
  308. toRef(forms, 'assignHomeworkStatus'),
  309. users.info.id
  310. );
  311. }
  312. return () => (
  313. <div class={styles.coursewareModal}>
  314. <div class={styles.btnGroup}>
  315. <NSpace>
  316. <div class={styles.btnItem}>
  317. <span class={styles.btnTitle}>
  318. <i style={{ color: '#ea4132', fontStyle: 'normal' }}>*</i>标题:
  319. </span>
  320. <NInput
  321. placeholder={'请输入标题'}
  322. v-model:value={forms.title}
  323. maxlength={100}
  324. />
  325. </div>
  326. </NSpace>
  327. <div class={styles.spaceBtnGroup}>
  328. <NButton
  329. bordered={false}
  330. type="error"
  331. disabled={forms.trainList.length <= 0}
  332. onClick={() => {
  333. forms.removeVisiable1 = true;
  334. }}>
  335. 清空
  336. </NButton>
  337. <NButton
  338. bordered={false}
  339. type="error"
  340. onClick={() => {
  341. // forms.drag = false;
  342. prepareStore.setIsEditTrain(false);
  343. forms.removeIds = [];
  344. // prepareStore.setTrainList([]);
  345. // getList();
  346. emit('change', { status: false });
  347. }}>
  348. 取消
  349. </NButton>
  350. {(props.cardType !== 'homeworkRecord' ||
  351. props.courseScheduleId) && (
  352. <NButton
  353. bordered={false}
  354. type="default"
  355. disabled={forms.trainList.length <= 0}
  356. onClick={() => {
  357. if (!forms.title) {
  358. message.error('请输入标题');
  359. return;
  360. }
  361. let count = 0;
  362. forms.trainList.forEach((item: any) => {
  363. if (!item.removeFlag) {
  364. count++;
  365. }
  366. });
  367. if (count <= 0) {
  368. message.error('作业内容不能为空');
  369. return;
  370. }
  371. forms.preSaveVisiable = true;
  372. }}
  373. // loading={forms.preBtnLoading}
  374. >
  375. 保存
  376. </NButton>
  377. )}
  378. {(props.cardType === 'homeworkRecord' ||
  379. props.courseScheduleId) && (
  380. <NButton
  381. type="primary"
  382. disabled={forms.trainList.length <= 0}
  383. onClick={() => {
  384. if (!forms.title) {
  385. message.error('请输入标题');
  386. return;
  387. }
  388. let count = 0;
  389. forms.trainList.forEach((item: any) => {
  390. if (!item.removeFlag) {
  391. count++;
  392. }
  393. });
  394. if (count <= 0) {
  395. message.error('作业内容不能为空');
  396. return;
  397. }
  398. forms.assignHomeworkStatus = true;
  399. }}>
  400. 立即布置
  401. </NButton>
  402. )}
  403. </div>
  404. </div>
  405. <NScrollbar
  406. class={[
  407. styles.listContainer,
  408. 'train-container'
  409. // forms.drag ? styles.listContainerDrag : ''
  410. ]}>
  411. <NSpin show={forms.loadingStatus}>
  412. <div
  413. class={[
  414. styles.listSection,
  415. 'train-listSection',
  416. !forms.loadingStatus && prepareStore.getTrainList.length <= 0
  417. ? styles.emptySection
  418. : ''
  419. ]}
  420. onDragenter={(e: any) => {
  421. e.preventDefault();
  422. }}
  423. onDragover={(e: any) => {
  424. e.preventDefault();
  425. }}
  426. onDrop={(e: any) => {
  427. let dropItem = e.dataTransfer.getData('text');
  428. console.log(dropItem, 'dropItem', dropItem);
  429. dropItem = dropItem ? JSON.parse(dropItem) : {};
  430. // 判断是否有数据
  431. if (dropItem.id) {
  432. eventGlobal.emit('onTrainDragItem', dropItem);
  433. }
  434. }}>
  435. {forms.trainList.length > 0 && (
  436. <>
  437. {/* {forms.drag ? ( */}
  438. <Draggable
  439. v-model:modelValue={forms.trainList}
  440. itemKey="id"
  441. componentData={{
  442. itemKey: 'id',
  443. tag: 'div',
  444. animation: 200,
  445. group: 'description',
  446. disabled: false
  447. }}
  448. class={styles.list}>
  449. {{
  450. item: (element: any) => {
  451. const item = element.element;
  452. return (
  453. <div data-id={item.musicId} class={styles.itemBlock}>
  454. <TrainType
  455. from={props.from}
  456. item={item}
  457. isDelete
  458. type="prepare"
  459. onDelete={(child: any) => onDelete(child)}
  460. offShelf={item.removeFlag ? true : false}
  461. onOffShelf={() => onRemove(item)}
  462. onEdit={(child: any) => {
  463. // console.log(forms.trainList);
  464. const {
  465. trainingConfigJson,
  466. id,
  467. musicId,
  468. ...res
  469. } = child;
  470. forms.editItem = {
  471. ...res,
  472. id: musicId,
  473. trainId: id,
  474. ...trainingConfigJson
  475. };
  476. forms.editStatus = true;
  477. }}
  478. />
  479. </div>
  480. );
  481. }
  482. }}
  483. </Draggable>
  484. {/* ) : (
  485. <div class={styles.list}>
  486. {forms.trainList.map((item: any) => (
  487. <TrainType
  488. item={item}
  489. type="prepare"
  490. offShelf={item.removeFlag ? true : false}
  491. onOffShelf={() => onRemove(item)}
  492. onEdit={(child: any) => {
  493. // console.log('edit', child);
  494. const { trainingConfigJson, id, musicId, ...res } =
  495. child;
  496. forms.editItem = {
  497. ...res,
  498. id: musicId,
  499. trainId: id,
  500. ...trainingConfigJson
  501. };
  502. forms.editStatus = true;
  503. }}
  504. />
  505. ))}
  506. </div>
  507. )} */}
  508. </>
  509. )}
  510. {!forms.loadingStatus &&
  511. prepareStore.getTrainList.length <= 0 && (
  512. <TheEmpty description="暂无作业" />
  513. )}
  514. </div>
  515. </NSpin>
  516. </NScrollbar>
  517. {/* 编辑 */}
  518. <NModal
  519. style={
  520. props.from === 'class' ? workSetingBoxDragData.styleDrag.value : {}
  521. }
  522. v-model:show={forms.editStatus}
  523. class={[
  524. 'modalTitle background',
  525. styles.trainEditModal,
  526. workSetingBoxClass
  527. ]}
  528. preset="card"
  529. title="作业设置">
  530. <TrainUpdate
  531. item={forms.editItem}
  532. onClose={() => (forms.editStatus = false)}
  533. onConfirm={(item: any) => {
  534. forms.editItem = {};
  535. // prepareStore.setIsAddTrain(true);
  536. const tList = typeFormat(
  537. item.trainingType,
  538. item.trainingConfigJson
  539. );
  540. //
  541. const train = {
  542. ...item,
  543. typeList: tList
  544. };
  545. forms.trainList.forEach((item: any) => {
  546. if (item.id === train.id) {
  547. // item = train;
  548. item.trainingConfigJson = train.trainingConfigJson;
  549. item.trainingType = train.trainingType;
  550. item.typeList = train.typeList;
  551. }
  552. });
  553. prepareStore.setTrainList(forms.trainList);
  554. }}
  555. />
  556. {props.from === 'class' && <Dragbom></Dragbom>}
  557. </NModal>
  558. {/* 添加自定义教材 */}
  559. <NModal
  560. style={
  561. props.from === 'class'
  562. ? workArrangeImmediatelyBoxDragData.styleDrag.value
  563. : {}
  564. }
  565. v-model:show={forms.assignHomeworkStatus}
  566. preset="card"
  567. showIcon={false}
  568. class={[
  569. 'modalTitle background',
  570. styles.assignHomework,
  571. workArrangeImmediatelyBoxClass
  572. ]}
  573. title={'布置作业'}
  574. blockScroll={false}>
  575. <AssignHomework
  576. from={props.from}
  577. classGroupId={props.classGroupId}
  578. courseScheduleId={props.courseScheduleId}
  579. chapterLessonCoursewareId={props.lessonPreTraining.chapterId}
  580. homeworkType={props.courseScheduleId ? 'HOMEWORK' : 'CLASSWORK'}
  581. item={{
  582. title: forms.title,
  583. lessonPreTrainingDetails: forms.trainList
  584. }}
  585. // trainList={forms.trainList}
  586. onClose={() => (forms.assignHomeworkStatus = false)}
  587. onConfirm={() => {
  588. if (props.cardType === 'homeworkRecord') {
  589. forms.trainList = [];
  590. prepareStore.setTrainList([]);
  591. emit('change', { state: false });
  592. }
  593. }}
  594. />
  595. {props.from === 'class' && <Dragbom></Dragbom>}
  596. </NModal>
  597. {/* {showGuide.value ? <Trainguide></Trainguide> : null} */}
  598. <NModal
  599. style={
  600. props.from === 'class' ? workClearBoxDragData.styleDrag.value : {}
  601. }
  602. v-model:show={forms.removeVisiable1}
  603. preset="card"
  604. class={['modalTitle', styles.removeVisiable1, workClearBoxClass]}
  605. title={'清空资源'}>
  606. <div class={styles.studentRemove}>
  607. <p>
  608. 请确认是否要清空作业?
  609. {/* <span>点击确认后所有的作业内容 将被清空掉。</span> */}
  610. </p>
  611. <NSpace class={styles.btnGroupModal} justify="center">
  612. <NButton
  613. round
  614. type="primary"
  615. onClick={() => {
  616. forms.trainList.forEach((item: any) => {
  617. forms.removeIds.push(item.id);
  618. });
  619. forms.trainList = [];
  620. prepareStore.setTrainList([]);
  621. forms.removeVisiable1 = false;
  622. }}>
  623. 确定
  624. </NButton>
  625. <NButton round onClick={() => (forms.removeVisiable1 = false)}>
  626. 取消
  627. </NButton>
  628. </NSpace>
  629. </div>
  630. {props.from === 'class' && <Dragbom></Dragbom>}
  631. </NModal>
  632. <NModal
  633. style={
  634. props.from === 'class' ? workSaveBoxDragData.styleDrag.value : {}
  635. }
  636. v-model:show={forms.preSaveVisiable}
  637. preset="card"
  638. class={['modalTitle', styles.removeVisiable1, workSaveBoxClass]}
  639. title={'保存'}>
  640. <TheMessageDialog
  641. content="是否保存当前页面编辑内容?"
  642. cancelButtonText="取消"
  643. confirmButtonText="保存"
  644. onClose={() => (forms.preSaveVisiable = false)}
  645. onConfirm={() => onPreSave()}
  646. />
  647. {props.from === 'class' && <Dragbom></Dragbom>}
  648. </NModal>
  649. </div>
  650. );
  651. }
  652. });