index.tsx 18 KB

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