index.tsx 18 KB

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