addCourseware.tsx 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. import {
  2. defineComponent,
  3. nextTick,
  4. onMounted,
  5. onUnmounted,
  6. reactive,
  7. watch
  8. } from 'vue';
  9. import styles from './addCourseware.module.less';
  10. import {
  11. NButton,
  12. NModal,
  13. NScrollbar,
  14. NSelect,
  15. NSpace,
  16. NSpin,
  17. useMessage,
  18. useDialog,
  19. NSwitch,
  20. NInput,
  21. NTooltip,
  22. NImage,
  23. NIcon
  24. } from 'naive-ui';
  25. import CardType from '/src/components/card-type';
  26. // import AttendClass from '/src/views/prepare-lessons/model/attend-class';
  27. import { usePrepareStore } from '/src/store/modules/prepareLessons';
  28. import { useCatchStore } from '/src/store/modules/catchData';
  29. // import TheEmpty from '/src/components/TheEmpty';
  30. import {
  31. api_teacherChapterLessonCoursewareAdd,
  32. api_teacherChapterLessonCoursewareUpdate,
  33. api_teacherChapterLessonCoursewareDetail,
  34. // courseScheduleStart,
  35. // queryCourseware,
  36. saveCourseware
  37. } from '../../../api';
  38. import Draggable from 'vuedraggable';
  39. import iconDelete from '../../../images/icon-delete-default.png';
  40. import iconAddMusic from '../../../images/icon-add-music.png';
  41. import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
  42. // import deepClone from '/src/helpers/deep-clone';
  43. import CardPreview from '/src/components/card-preview';
  44. import PreviewWindow from '/src/views/preview-window';
  45. // import { state } from '/src/state';
  46. import SubjectSync from '../../../model/subject-sync';
  47. import { eventGlobal } from '/src/utils';
  48. // import iconTips from '../../../images/icon-tips.png';
  49. import TheMessageDialog from '/src/components/TheMessageDialog';
  50. import AddItemModel from '../../../model/add-item-model';
  51. import AddOtherSource from '../../../model/add-other-source';
  52. import deepClone from '/src/helpers/deep-clone';
  53. export default defineComponent({
  54. name: 'courseware-modal',
  55. props: {
  56. groupItem: {
  57. type: Object,
  58. default: () => ({})
  59. }
  60. },
  61. emits: ['change'],
  62. setup(props, { emit }) {
  63. const catchStore = useCatchStore();
  64. const prepareStore = usePrepareStore();
  65. // const route = useRoute();
  66. const router = useRouter();
  67. // const dialog = useDialog();
  68. const message = useMessage();
  69. const forms = reactive({
  70. subjects: [] as any,
  71. openFlagEnable: true, // 是否支持修改公开状态
  72. name: '',
  73. openFlag: false,
  74. baseCoursewareList: [
  75. {
  76. name: '',
  77. id: null,
  78. list: [] as any
  79. }
  80. ] as any, // 基础数据
  81. coursewareList: [
  82. {
  83. name: '',
  84. id: null,
  85. list: [] as any
  86. }
  87. ] as any,
  88. loadingStatus: false,
  89. showAttendClass: false,
  90. attendClassType: 'change', //
  91. removeIds: [] as any, // 临时删除的编号
  92. editSubjectIds: '', // 声部编号
  93. addCoursewareVisiable: false,
  94. addCoursewareItem: {} as any,
  95. messageCallBack: null as any,
  96. messageOperation: {
  97. visiable: false,
  98. loading: false, // 是否显示加载
  99. type: 'delete' as 'delete' | 'addItem' | 'save' | 'pageLive',
  100. contentDirection: 'center' as 'left' | 'center' | 'right',
  101. title: '删除知识点',
  102. content: '请确认是否删除该知识点,删除知识点后将同步删除知识点下的资源',
  103. cancelButtonText: '取消',
  104. confirmButtonText: '确认',
  105. index: 0
  106. },
  107. subjectSyncVisiable: false, // 同步声部
  108. show: false,
  109. item: {} as any,
  110. previewModal: false,
  111. previewParams: {
  112. type: '',
  113. subjectId: '',
  114. detailId: ''
  115. } as any,
  116. addOtherSource: false,
  117. addOtherIndex: 0 // 添加其它的索引
  118. });
  119. // 获取列表
  120. const getList = async () => {
  121. forms.loadingStatus = true;
  122. try {
  123. if (!props.groupItem.id) return (forms.loadingStatus = false);
  124. const { data } = await api_teacherChapterLessonCoursewareDetail(
  125. props.groupItem.id
  126. );
  127. const tempRows = data.chapterKnowledgeList || [];
  128. forms.name = data.name;
  129. forms.subjects = data.subjectIds
  130. ? data.subjectIds.split(',').map((s: any) => {
  131. return Number(s);
  132. })
  133. : [];
  134. forms.openFlag = data.openFlag;
  135. forms.openFlagEnable = data.openFlagEnable;
  136. const temp: any = [];
  137. tempRows.forEach((row: any) => {
  138. const child: any = row.chapterKnowledgeMaterialList;
  139. const childList: any[] = [];
  140. if (Array.isArray(child) && child.length > 0) {
  141. child.forEach((sub: any) => {
  142. childList.push({
  143. id: sub.id,
  144. materialId: sub.bizId,
  145. coverImg: sub.bizInfo.coverImg,
  146. type: sub.type,
  147. title: sub.bizInfo.name,
  148. dataJson: sub.dataJson,
  149. // isCollect: !!sub.favoriteFlag,
  150. isSelected: sub.source === 'PLATFORM' ? true : false,
  151. content: sub.bizInfo.content,
  152. removeFlag: sub.removeFlag
  153. });
  154. });
  155. }
  156. temp.push({
  157. name: row.name,
  158. id: row.id,
  159. list: [...childList]
  160. });
  161. });
  162. forms.coursewareList = temp;
  163. forms.baseCoursewareList = deepClone(temp);
  164. } catch (e) {
  165. //
  166. console.log(e);
  167. }
  168. forms.loadingStatus = false;
  169. };
  170. // 删除
  171. const onDelete = (j: number, index: number) => {
  172. const coursewareItem = forms.coursewareList[index];
  173. if (!coursewareItem) return;
  174. coursewareItem.list.splice(j, 1);
  175. };
  176. // 完成编辑
  177. const onOverEdit = async () => {
  178. try {
  179. const temp: any = [];
  180. forms.coursewareList.forEach((item: any) => {
  181. temp.push({
  182. materialName: item.name,
  183. materialType: item.type,
  184. materialId: item.materialId,
  185. id: item.id
  186. });
  187. });
  188. // 保存课件
  189. // 判断是否编辑,如果编辑则取选择的声部
  190. await saveCourseware({
  191. coursewareDetailKnowledgeId: prepareStore.getSelectKey,
  192. lessonCoursewareId: prepareStore.getLessonCoursewareId,
  193. lessonCoursewareDetailId: prepareStore.getLessonCoursewareDetailId,
  194. // subjectId: forms.isEdit
  195. // ? forms.editSubjectIds
  196. // : prepareStore.getSubjectId,
  197. materialList: [...temp]
  198. });
  199. message.success('编辑成功');
  200. // forms.removeVisiable = false;
  201. prepareStore.setIsEditResource(false);
  202. // 重置临时删除编号
  203. forms.removeIds = [];
  204. await getList();
  205. } catch {
  206. //
  207. }
  208. };
  209. const isPointInsideElement = (element: any, x: number, y: number) => {
  210. const rect = element.getBoundingClientRect();
  211. return (
  212. x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom
  213. );
  214. };
  215. const isPointOnLeft = (element: any, x: number) => {
  216. const rect = element.getBoundingClientRect();
  217. const elementCenterX = rect.left + rect.width / 2;
  218. return x < elementCenterX;
  219. };
  220. // 操作
  221. const onChangePoint = (type: string, index: number, item?: any) => {
  222. if (type === 'up') {
  223. // 向上移动
  224. if (index === 0) return;
  225. const temp = forms.coursewareList[index - 1];
  226. forms.coursewareList[index - 1] = forms.coursewareList[index];
  227. forms.coursewareList[index] = temp;
  228. } else if (type === 'down') {
  229. // 向下移动
  230. if (index >= forms.coursewareList.length - 1) return;
  231. const temp = forms.coursewareList[index + 1];
  232. forms.coursewareList[index + 1] = forms.coursewareList[index];
  233. forms.coursewareList[index] = temp;
  234. } else if (type === 'remove') {
  235. forms.messageOperation = {
  236. visiable: true,
  237. type: 'delete',
  238. contentDirection: 'left',
  239. title: '删除知识点',
  240. loading: false,
  241. content: `请确认是否删除${
  242. item.name ? '【' + item.name + '】' : '该知识点'
  243. },删除知识点后将同步删除知识点下的资源`,
  244. cancelButtonText: '取消',
  245. confirmButtonText: '确认',
  246. index
  247. };
  248. }
  249. };
  250. //
  251. const onMessageConfirm = async () => {
  252. const type = forms.messageOperation.type;
  253. if (type === 'delete') {
  254. forms.coursewareList.splice(forms.messageOperation.index, 1);
  255. } else if (type === 'addItem') {
  256. forms.coursewareList.push({ name: '', list: [] });
  257. addCoursewareItem(forms.addCoursewareItem);
  258. } else if (type === 'save' || type === 'pageLive') {
  259. if (forms.messageOperation.loading) return;
  260. if (!forms.name) {
  261. message.error('请输入课件标题');
  262. forms.messageOperation.visiable = false;
  263. return;
  264. }
  265. if (forms.subjects.length <= 0) {
  266. message.error('请选择声部');
  267. forms.messageOperation.visiable = false;
  268. return;
  269. }
  270. if (forms.coursewareList.length <= 0) {
  271. message.error('未配置知识点');
  272. forms.messageOperation.visiable = false;
  273. return;
  274. }
  275. let isNotAdd = false;
  276. for (const item of forms.coursewareList) {
  277. if (!item.name) {
  278. message.error('请输入知识点名称');
  279. forms.messageOperation.visiable = false;
  280. return;
  281. }
  282. if (Array.isArray(item.list) && item.list.length <= 0) {
  283. isNotAdd = true;
  284. }
  285. }
  286. if (isNotAdd) {
  287. message.error('请至少添加一个资源');
  288. forms.messageOperation.visiable = false;
  289. return;
  290. }
  291. forms.messageOperation.loading = true;
  292. await onSaveCourseWare();
  293. forms.messageOperation.loading = false;
  294. if (
  295. type === 'pageLive' &&
  296. typeof forms.messageCallBack === 'function'
  297. ) {
  298. forms.messageCallBack();
  299. }
  300. emit('change', { status: false });
  301. eventGlobal.emit('teacher-slideshow', false);
  302. }
  303. forms.messageOperation.visiable = false;
  304. };
  305. const addCoursewareItem = (item: any, point?: any) => {
  306. nextTick(() => {
  307. if (point) {
  308. const rowGroupDom = document.querySelectorAll('.row-group');
  309. const dom = rowGroupDom[item.index].querySelectorAll('.row-nav');
  310. // const dom = document.querySelectorAll('.row-nav');
  311. let isAdd = false;
  312. dom.forEach((child: any, index: number) => {
  313. // console.log(child);
  314. const status = isPointInsideElement(child, point.x, point.y);
  315. if (status) {
  316. const array: any =
  317. forms.coursewareList[item.index || 0].list || [];
  318. const left = isPointOnLeft(child, point.x);
  319. if (!left) {
  320. array.splice(index + 1, 0, item);
  321. } else {
  322. array.splice(index, 0, item);
  323. }
  324. isAdd = true;
  325. forms.coursewareList[item.index || 0].list = array;
  326. }
  327. });
  328. if (!isAdd) {
  329. forms.coursewareList[item.index || 0].list.push(item);
  330. }
  331. } else {
  332. forms.coursewareList[item.index || 0].list.push(item);
  333. message.success('添加成功');
  334. }
  335. });
  336. };
  337. // 提交
  338. const onSubmit = async () => {
  339. try {
  340. if (!forms.name) {
  341. message.error('请输入课件标题');
  342. return;
  343. }
  344. if (forms.subjects.length <= 0) {
  345. message.error('请选择声部');
  346. return;
  347. }
  348. let isNotAdd = false;
  349. for (const item of forms.coursewareList) {
  350. if (!item.name) {
  351. message.error('请输入知识点名称');
  352. return;
  353. }
  354. if (Array.isArray(item.list) && item.list.length <= 0) {
  355. isNotAdd = true;
  356. }
  357. }
  358. if (isNotAdd) {
  359. message.error('请至少添加一个资源');
  360. return;
  361. }
  362. await onSaveCourseWare(true);
  363. } catch {
  364. //
  365. }
  366. };
  367. const onSaveCourseWare = async (hasBack = false) => {
  368. try {
  369. const params = {
  370. name: forms.name,
  371. subjectIds: forms.subjects.join(','),
  372. openFlag: forms.openFlag,
  373. coursewareDetailKnowledgeId: prepareStore.getSelectKey,
  374. chapterKnowledgeList: [] as any
  375. };
  376. console.log(forms.coursewareList, '121212');
  377. forms.coursewareList.forEach((item: any) => {
  378. let tempItem: any = [];
  379. if (Array.isArray(item.list) && item.list.length > 0) {
  380. tempItem = item.list.map((child: any) => {
  381. return {
  382. bizId: child.materialId,
  383. type: child.type,
  384. dataJson: !['IMG', 'VIDEO', 'SONG', 'MUSIC', 'PPT'].includes(
  385. child.type
  386. )
  387. ? JSON.stringify({
  388. setting: child.dataJson,
  389. coverImg: child.coverImg,
  390. bizId: child.bizId,
  391. content: child.content,
  392. name: child.title
  393. })
  394. : ''
  395. };
  396. });
  397. }
  398. params.chapterKnowledgeList.push({
  399. name: item.name,
  400. chapterKnowledgeMaterialList: tempItem
  401. });
  402. });
  403. if (props.groupItem?.id) {
  404. await api_teacherChapterLessonCoursewareUpdate({
  405. id: props.groupItem.id,
  406. ...params
  407. });
  408. } else {
  409. await api_teacherChapterLessonCoursewareAdd(params);
  410. }
  411. message.success('保存成功');
  412. if (hasBack) {
  413. emit('change', { status: false });
  414. eventGlobal.emit('teacher-slideshow', false);
  415. }
  416. } catch {
  417. //
  418. }
  419. };
  420. const addItem = (item: any, point?: any) => {
  421. if (forms.coursewareList.length <= 0) {
  422. // 添加到临时对象
  423. forms.addCoursewareItem = item;
  424. forms.messageOperation = {
  425. visiable: true,
  426. type: 'addItem',
  427. contentDirection: 'center',
  428. title: '添加到知识点',
  429. loading: false,
  430. content: '当前课件暂无知识点,请添加知识点后操作',
  431. cancelButtonText: '取消',
  432. confirmButtonText: '添加知识点',
  433. index: 0
  434. };
  435. } else if (forms.coursewareList.length > 1 && item.addType !== 'drag') {
  436. forms.addCoursewareVisiable = true;
  437. forms.addCoursewareItem = item;
  438. } else {
  439. addCoursewareItem(item, point);
  440. }
  441. };
  442. // 当页面离开时
  443. const onPageBeforeLeave = (event: any) => {
  444. const objA = JSON.stringify(forms.coursewareList);
  445. const objB = JSON.stringify(forms.baseCoursewareList);
  446. if (objA === objB) {
  447. if (typeof event === 'function') {
  448. event();
  449. emit('change', { status: false });
  450. eventGlobal.emit('teacher-slideshow', false);
  451. }
  452. } else {
  453. forms.messageCallBack = event;
  454. forms.messageOperation = {
  455. visiable: true,
  456. type: 'pageLive',
  457. loading: false,
  458. contentDirection: 'center',
  459. title: '保存课件',
  460. content: '当前课件暂未保存,是否保存?',
  461. cancelButtonText: '不保存',
  462. confirmButtonText: '保存',
  463. index: 0
  464. };
  465. }
  466. };
  467. onMounted(async () => {
  468. await getList();
  469. // 动态添加数据
  470. eventGlobal.on('onPrepareAddItem', addItem);
  471. eventGlobal.on('pageBeforeLeave', onPageBeforeLeave);
  472. });
  473. onUnmounted(() => {
  474. eventGlobal.off('onPrepareAddItem', addItem);
  475. eventGlobal.off('pageBeforeLeave', onPageBeforeLeave);
  476. });
  477. // 当列表数据更新时同步缓存数据
  478. watch(
  479. () => forms.coursewareList,
  480. () => {
  481. prepareStore.setCoursewareList = forms.coursewareList;
  482. },
  483. {
  484. deep: true
  485. }
  486. );
  487. // 全选
  488. const chioseAll = (list: any) => {
  489. forms.subjects = list.map((child: any) => {
  490. return child.id;
  491. }) as any;
  492. };
  493. return () => (
  494. <div class={styles.coursewareModal}>
  495. <div class={styles.btnGroup}>
  496. <NSpace>
  497. <div class={styles.btnItem}>
  498. <span class={styles.btnTitle}>
  499. <span>*</span>标题:
  500. </span>
  501. <NInput
  502. placeholder="请输入课件标题"
  503. v-model:value={forms.name}
  504. maxlength={20}
  505. clearable
  506. />
  507. </div>
  508. <div class={styles.btnItem}>
  509. <span class={styles.btnTitle}>
  510. <span>*</span>声部:
  511. </span>
  512. <NSelect
  513. placeholder="请选择声部(可多选)"
  514. class={styles.btnSubjectList}
  515. options={prepareStore.getSubjectList}
  516. labelField="name"
  517. valueField="id"
  518. multiple
  519. maxTagCount={1}
  520. size="small"
  521. v-model:value={forms.subjects}
  522. clearable
  523. v-slots={{
  524. action: () => (
  525. <>
  526. <NButton
  527. text
  528. style=" --n-width: 100% "
  529. size="small"
  530. onClick={() => chioseAll(prepareStore.getSubjectList)}>
  531. 全选
  532. </NButton>
  533. </>
  534. )
  535. }}
  536. />
  537. </div>
  538. <div class={styles.btnItem}>
  539. <span class={styles.btnTitle}>公开:</span>
  540. {!forms.openFlagEnable ? (
  541. <NTooltip style={{ maxWidth: '200px' }} showArrow={false}>
  542. {{
  543. trigger: () => (
  544. <NSwitch
  545. v-model:value={forms.openFlag}
  546. disabled={!forms.openFlagEnable}
  547. />
  548. ),
  549. default: () =>
  550. '为尊重课件原作者,在“相关课件”中添加的课件不支持公开'
  551. }}
  552. </NTooltip>
  553. ) : (
  554. <NSwitch
  555. v-model:value={forms.openFlag}
  556. disabled={!forms.openFlagEnable}
  557. />
  558. )}
  559. </div>
  560. </NSpace>
  561. {/* 编辑 */}
  562. <NSpace>
  563. <NButton
  564. type="error"
  565. onClick={() => {
  566. const objA = JSON.stringify(forms.coursewareList);
  567. const objB = JSON.stringify(forms.baseCoursewareList);
  568. if (objA === objB) {
  569. emit('change', { status: false });
  570. eventGlobal.emit('teacher-slideshow', false);
  571. } else {
  572. forms.messageOperation = {
  573. visiable: true,
  574. type: 'save',
  575. loading: false,
  576. contentDirection: 'center',
  577. title: '保存课件',
  578. content: '当前课件暂未保存,是否保存?',
  579. cancelButtonText: '不保存',
  580. confirmButtonText: '保存',
  581. index: 0
  582. };
  583. }
  584. }}>
  585. 取消
  586. </NButton>
  587. <NButton
  588. type="primary"
  589. onClick={onSubmit}
  590. disabled={forms.coursewareList.length <= 0}>
  591. 保存课件
  592. </NButton>
  593. {/* <NButton
  594. type="primary"
  595. onClick={() => {
  596. forms.coursewareList = [{ name: '', list: [] }];
  597. }}>
  598. 请空
  599. </NButton> */}
  600. </NSpace>
  601. </div>
  602. <NScrollbar class={[styles.listContainer]} {...{ id: 'lessons-2' }}>
  603. <NSpin show={forms.loadingStatus}>
  604. <div class={[styles.listSection]}>
  605. {forms.coursewareList.map((item: any, index: number) => (
  606. <div
  607. class={[styles.listItems, 'row-group']}
  608. onDragenter={(e: any) => {
  609. e.preventDefault();
  610. }}
  611. onDragover={(e: any) => {
  612. e.preventDefault();
  613. }}
  614. onDrop={(e: any) => {
  615. let dropItem = e.dataTransfer.getData('text');
  616. dropItem =
  617. dropItem && e.dataTransfer.effectAllowed === 'all'
  618. ? JSON.parse(dropItem)
  619. : {};
  620. // 判断是否有数据
  621. if (dropItem.id) {
  622. // 获取拖拽的目标元素
  623. eventGlobal.emit(
  624. 'onPrepareAddItem',
  625. {
  626. materialId: dropItem.id,
  627. coverImg: dropItem.coverImg,
  628. type: dropItem.type,
  629. title: dropItem.title,
  630. isCollect: dropItem.isCollect,
  631. isSelected: dropItem.isSelected,
  632. content: dropItem.content,
  633. removeFlag: false,
  634. index,
  635. addType: 'drag'
  636. },
  637. {
  638. x: e.clientX,
  639. y: e.clientY
  640. }
  641. );
  642. }
  643. }}>
  644. <div class={styles.knowledgePoint}>
  645. <div class={styles.btnItem}>
  646. <span class={styles.btnTitle}>
  647. <span>*</span>知识点名称:
  648. </span>
  649. <NInput
  650. placeholder="未命名知识点"
  651. v-model:value={item.name}
  652. maxlength={15}
  653. clearable
  654. />
  655. </div>
  656. </div>
  657. <NSpace class={styles.operationGroup}>
  658. {index > 0 && (
  659. <NTooltip showArrow={false}>
  660. {{
  661. trigger: () => (
  662. <i
  663. class={styles.iconCUp}
  664. onClick={() => onChangePoint('up', index)}></i>
  665. ),
  666. default: () => '上移知识点'
  667. }}
  668. </NTooltip>
  669. )}
  670. {index < forms.coursewareList.length - 1 && (
  671. <NTooltip showArrow={false}>
  672. {{
  673. trigger: () => (
  674. <i
  675. class={styles.iconCDown}
  676. onClick={() => onChangePoint('down', index)}></i>
  677. ),
  678. default: () => '下移知识点'
  679. }}
  680. </NTooltip>
  681. )}
  682. <NTooltip showArrow={false}>
  683. {{
  684. trigger: () => (
  685. <i
  686. class={styles.iconCRemove}
  687. onClick={() =>
  688. onChangePoint('remove', index, item)
  689. }></i>
  690. ),
  691. default: () => '删除知识点'
  692. }}
  693. </NTooltip>
  694. </NSpace>
  695. {item.list.length > 0 && (
  696. <Draggable
  697. v-model:modelValue={item.list}
  698. itemKey="id"
  699. componentData={{
  700. itemKey: 'id',
  701. tag: 'div',
  702. animation: 200,
  703. group: 'description',
  704. disabled: false
  705. }}
  706. class={styles.list}>
  707. {{
  708. item: (element: any) => {
  709. const item = element.element;
  710. return (
  711. <div
  712. data-id={item.id}
  713. class={[
  714. styles.itemWrap,
  715. styles.itemBlock,
  716. 'row-nav'
  717. ]}>
  718. <div class={styles.itemWrapBox}>
  719. <CardType
  720. class={[styles.itemContent]}
  721. isShowCollect={false}
  722. offShelf={item.removeFlag ? true : false}
  723. // onOffShelf={() => onRemove(item)}
  724. item={item}
  725. disabledMouseHover={false}
  726. onClick={() => {
  727. if (item.type === 'IMG') return;
  728. forms.show = true;
  729. forms.item = item;
  730. }}
  731. />
  732. <div class={styles.itemOperation}>
  733. <img
  734. src={iconDelete}
  735. class={styles.iconDelete}
  736. onClick={(e: MouseEvent) => {
  737. e.stopPropagation();
  738. onDelete(element.index, index);
  739. }}
  740. />
  741. </div>
  742. </div>
  743. </div>
  744. );
  745. },
  746. footer: () => (
  747. <div class={styles.itemWrap}>
  748. <div class={styles.itemWrapBox}>
  749. <div
  750. class={[
  751. styles.itemContent,
  752. styles.addMusicItem,
  753. 'handle'
  754. ]}
  755. onClick={() => {
  756. forms.addOtherSource = true;
  757. forms.addOtherIndex = index;
  758. }}>
  759. <img src={iconAddMusic} />
  760. <p class={styles.addMusicName}>添加功能</p>
  761. </div>
  762. </div>
  763. </div>
  764. )
  765. }}
  766. </Draggable>
  767. )}
  768. {item.list <= 0 && (
  769. <div class={styles.list}>
  770. <div class={styles.itemWrap}>
  771. <div class={styles.itemWrapBox}>
  772. <div
  773. class={[
  774. styles.itemContent,
  775. styles.addMusicItem,
  776. 'handle'
  777. ]}
  778. onClick={() => {
  779. forms.addOtherSource = true;
  780. forms.addOtherIndex = index;
  781. }}>
  782. <img src={iconAddMusic} />
  783. <p class={styles.addMusicName}>添加功能</p>
  784. </div>
  785. </div>
  786. </div>
  787. </div>
  788. )}
  789. </div>
  790. ))}
  791. <NButton
  792. block
  793. type="primary"
  794. secondary
  795. class={styles.addKnowledgePoint}
  796. onClick={() => {
  797. forms.coursewareList.push({
  798. name: '',
  799. list: []
  800. });
  801. }}>
  802. <i class={styles.iconCAdd}></i>
  803. 添加知识点
  804. </NButton>
  805. </div>
  806. </NSpin>
  807. </NScrollbar>
  808. {/* 弹窗查看 */}
  809. <CardPreview
  810. size={
  811. ['INSTRUMENT', 'THEORY', 'MUSIC_WIKI', 'MUSICIAN'].includes(
  812. forms.item.type
  813. )
  814. ? 'large'
  815. : ''
  816. }
  817. v-model:show={forms.show}
  818. item={forms.item}
  819. />
  820. <NModal
  821. v-model:show={forms.addCoursewareVisiable}
  822. preset="card"
  823. class={['modalTitle', styles.addCourseware]}
  824. title={'添加到知识点'}>
  825. <AddItemModel
  826. coursewareList={forms.coursewareList}
  827. onClose={() => (forms.addCoursewareVisiable = false)}
  828. onConfirm={(selects: number[]) => {
  829. if (Array.isArray(selects) && selects.length > 0) {
  830. selects.forEach(select => {
  831. addCoursewareItem({
  832. ...forms.addCoursewareItem,
  833. index: select
  834. });
  835. });
  836. forms.addCoursewareVisiable = false;
  837. } else {
  838. message.error('请选择需要添加的知识点');
  839. }
  840. }}
  841. />
  842. </NModal>
  843. <NModal
  844. v-model:show={forms.messageOperation.visiable}
  845. preset="card"
  846. class={['modalTitle', styles.removeVisiable1]}
  847. title={forms.messageOperation.title}>
  848. <TheMessageDialog
  849. content={forms.messageOperation.content}
  850. contentDirection={forms.messageOperation.contentDirection}
  851. cancelButtonText={forms.messageOperation.cancelButtonText}
  852. confirmButtonText={forms.messageOperation.confirmButtonText}
  853. loading={forms.messageOperation.loading}
  854. onClose={() => {
  855. forms.messageOperation.visiable = false;
  856. if (
  857. forms.messageOperation.type === 'save' ||
  858. forms.messageOperation.type === 'pageLive'
  859. ) {
  860. emit('change', { status: false });
  861. eventGlobal.emit('teacher-slideshow', false);
  862. if (
  863. forms.messageOperation.type === 'pageLive' &&
  864. typeof forms.messageCallBack === 'function'
  865. ) {
  866. forms.messageCallBack();
  867. }
  868. }
  869. }}
  870. onConfirm={() => onMessageConfirm()}
  871. />
  872. </NModal>
  873. <PreviewWindow
  874. v-model:show={forms.previewModal}
  875. type="attend"
  876. params={forms.previewParams}
  877. />
  878. {/* 完成编辑时,选择声部 */}
  879. <NModal
  880. v-model:show={forms.subjectSyncVisiable}
  881. preset="card"
  882. class={['modalTitle background', styles.subjectSyncModal]}
  883. title={'同步声部'}>
  884. <SubjectSync
  885. subjectId={prepareStore.getSubjectId as any}
  886. onClose={() => (forms.subjectSyncVisiable = false)}
  887. onConfirm={async (subjectIds: any) => {
  888. //
  889. try {
  890. forms.editSubjectIds = subjectIds.join(',');
  891. await onOverEdit();
  892. forms.subjectSyncVisiable = false;
  893. } catch {
  894. //
  895. }
  896. }}
  897. />
  898. </NModal>
  899. {/* 添加其它类型的资源 */}
  900. <NModal
  901. v-model:show={forms.addOtherSource}
  902. preset="card"
  903. class={['modalTitle background', styles.addOtherSource]}
  904. title={'添加功能'}>
  905. <AddOtherSource
  906. onClose={() => (forms.addOtherSource = false)}
  907. onComfirm={item => {
  908. if (Array.isArray(item)) {
  909. item.forEach((child: any) => {
  910. addCoursewareItem({ ...child, index: forms.addOtherIndex });
  911. });
  912. } else {
  913. addCoursewareItem({ ...item, index: forms.addOtherIndex });
  914. }
  915. }}
  916. />
  917. </NModal>
  918. </div>
  919. );
  920. }
  921. });