courseConfiguration.tsx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. import {
  2. NAlert,
  3. NButton,
  4. NCard,
  5. NDialog,
  6. NDrawer,
  7. NDrawerContent,
  8. NDropdown,
  9. NEmpty,
  10. NForm,
  11. NFormItem,
  12. NGi,
  13. NGrid,
  14. NIcon,
  15. NInput,
  16. NModal,
  17. NSelect,
  18. NSpace,
  19. NSpin,
  20. NTooltip,
  21. NUpload,
  22. UploadCustomRequestOptions,
  23. useDialog,
  24. useMessage
  25. } from 'naive-ui'
  26. import { defineComponent, onMounted, reactive, ref } from 'vue'
  27. import { useRoute } from 'vue-router'
  28. import {
  29. lessonCoursewareDetailPage,
  30. lessonCoursewareDetailSave,
  31. lessonCoursewareDetailUpdate,
  32. lessonTrainingPage,
  33. lessonCoursewareDetailRemove,
  34. lessonCoursewareExaminationMapperQueryAll,
  35. lessonCoursewareDetailLock,
  36. api_openFileImportInfoSave,
  37. api_removeTraining,
  38. api_getUsedLevelDetail
  39. } from '../../api'
  40. import styles from '../index.module.less'
  41. import { EditFilled, DeleteFilled, LockFilled, UnlockFilled } from '@vicons/antd'
  42. import CourseKnowledgePoint from '../model/CourseKnowledgePoint'
  43. import SelectAfterClassTraining from '../model/selectAfterClassTraining'
  44. import AddUnitTest from '../model/AddUnitTest'
  45. import TheLink from '@/components/TheLink'
  46. import { api_uploadFile } from '@/plugins/uploadFile'
  47. const courseTypeIds: any = []
  48. for(let i = 1; i <= 20; i++) {
  49. courseTypeIds.push({
  50. label: i,
  51. value: i
  52. })
  53. }
  54. export default defineComponent({
  55. name: 'courseConfiguration',
  56. props: {
  57. course: {
  58. type: Object,
  59. default: () => {}
  60. }
  61. },
  62. setup(props, ctx) {
  63. const message = useMessage()
  64. const dialog = useDialog()
  65. const route = useRoute()
  66. const addFormRef = ref()
  67. const addForm = reactive({
  68. open: false,
  69. id: '',
  70. name: '', //课时名称
  71. lessonTargetDesc: '', //课时名称
  72. lessonTrainingId: '', //课后作业
  73. lockEnable: 'true',
  74. level: null,
  75. accessScope: 0
  76. })
  77. // 课件添加课程
  78. const addCourseware = () => {
  79. addFormRef.value.validate(async (err: any) => {
  80. if (!err) {
  81. const body = {
  82. lessonCoursewareId: route.query.id,
  83. name: addForm.name,
  84. level: addForm.level,
  85. lessonTargetDesc: addForm.lessonTargetDesc,
  86. lockEnable: addForm.lockEnable,
  87. accessScope: addForm.accessScope
  88. }
  89. let res: any
  90. if (addForm.id) {
  91. try {
  92. res = await lessonCoursewareDetailUpdate({
  93. ...body,
  94. id: addForm.id
  95. })
  96. } catch (error) {}
  97. } else {
  98. try {
  99. res = await lessonCoursewareDetailSave(body)
  100. } catch (error) {}
  101. }
  102. if (res?.code == 200) {
  103. message.success('保存成功')
  104. addForm.open = false
  105. getDetail()
  106. }
  107. }
  108. })
  109. }
  110. const state = reactive({
  111. dataList: [] as any,
  112. mapperList: [] as any
  113. })
  114. const getDetail = async () => {
  115. try {
  116. const { data } = await lessonCoursewareDetailPage({
  117. lessonCoursewareId: route.query.id,
  118. page: 1,
  119. rows: 1000
  120. })
  121. if (Array.isArray(data?.rows)) {
  122. state.dataList = data.rows
  123. }
  124. } catch (error) {}
  125. }
  126. /** 查询课件下的所有阶段自测 */
  127. const getMapperAll = async () => {
  128. try {
  129. const { data } = await lessonCoursewareExaminationMapperQueryAll(route.query.id)
  130. if (Array.isArray(data)) {
  131. state.mapperList = data
  132. }
  133. } catch (error) {}
  134. }
  135. /** 获取级别 */
  136. const getLevels = async (item?: any) => {
  137. const { data } = await api_getUsedLevelDetail({
  138. id: item?.id,
  139. lessonCoursewareId: route.query.id
  140. })
  141. if(Array.isArray(data)) {
  142. courseTypeIds.forEach((item: any) => {
  143. item.disabled = data.includes(item.value) ? true : false
  144. })
  145. }
  146. }
  147. onMounted(() => {
  148. getDetail()
  149. getMapperAll()
  150. })
  151. //删除课时
  152. const hanldeDelete = (item: any) => {
  153. const d = dialog.warning({
  154. title: '警告',
  155. content: '是否确认删除此课时?',
  156. positiveText: '确定',
  157. negativeText: '取消',
  158. onPositiveClick: async () => {
  159. d.loading = true
  160. try {
  161. const res: any = await lessonCoursewareDetailRemove(item.id)
  162. if (res?.code == 200) {
  163. message.success('删除成功')
  164. getDetail()
  165. }
  166. } catch (error) {}
  167. d.loading = false
  168. }
  169. })
  170. }
  171. //绑定课后作业
  172. const afterTrain = reactive({
  173. open: false,
  174. id: ''
  175. })
  176. const addAfterTrain = async (row: any) => {
  177. console.log('🚀 ~ row', row)
  178. const body = {
  179. id: addForm.id,
  180. lessonTrainingId: row.id,
  181. name: addForm.name,
  182. lessonTargetDesc: addForm.lessonTargetDesc
  183. }
  184. try {
  185. const res: any = await lessonCoursewareDetailUpdate(body)
  186. if (res?.code == 200) {
  187. message.success('保存成功')
  188. afterTrain.open = false
  189. getDetail()
  190. }
  191. } catch (error) {}
  192. }
  193. // 课程配置
  194. const courseData = reactive({
  195. open: false,
  196. title: '',
  197. item: null
  198. })
  199. //阶段自测
  200. const unitData = reactive({
  201. open: false,
  202. model: {}
  203. })
  204. /** 切换课件是否锁定 */
  205. const toggleLock = (item: any) => {
  206. const d = dialog.warning({
  207. title: '警告',
  208. content: `是否确认${item.lockFlag ? '解锁' : '锁定'}此课时?`,
  209. positiveText: '确定',
  210. negativeText: '取消',
  211. onPositiveClick: async () => {
  212. d.loading = true
  213. try {
  214. const res = await lessonCoursewareDetailLock({ id: item.id, lockFlag: !item.lockFlag })
  215. message.success('操作成功')
  216. getDetail()
  217. } catch (error) {}
  218. d.loading = false
  219. }
  220. })
  221. }
  222. /** 删除选择的作业 */
  223. const hanldeRemoveTraning = (item: any) => {
  224. const d = dialog.warning({
  225. title: '警告',
  226. content: `是否确认删除作业?`,
  227. positiveText: '确定',
  228. negativeText: '取消',
  229. onPositiveClick: async () => {
  230. d.loading = true
  231. try {
  232. const res = await api_removeTraining(item.id)
  233. message.success('删除成功')
  234. getDetail()
  235. } catch (error) {}
  236. d.loading = false
  237. }
  238. })
  239. }
  240. const customRequest_importData = reactive({
  241. loading: false,
  242. dataType: 'EXAMINATION',
  243. importRef: null as any
  244. })
  245. const customRequest_importFile = async (data: UploadCustomRequestOptions) => {
  246. console.log(data.file)
  247. const msg = message.loading('正在上传文件', { duration: 0 })
  248. customRequest_importData.loading = true
  249. try {
  250. const fileUrl = await api_uploadFile(data.file.file, () => {})
  251. const res = await api_openFileImportInfoSave({
  252. dataType: customRequest_importData.dataType,
  253. fileName: data.file.name,
  254. importUrl: fileUrl,
  255. lessonId: route.query.id
  256. })
  257. console.log('🚀 ~ res:', res)
  258. customRequest_importData.loading = false
  259. if (res.data) {
  260. msg.destroy()
  261. // 空表格
  262. if (res.data.insertRow === 0 && res.data.invalidRow === 0) {
  263. message.error('导入失败,表格为空')
  264. return
  265. }
  266. if (res.data.respUrl) {
  267. dialog.error({
  268. title: '信息',
  269. content: () => (
  270. <NSpace>
  271. <div>导入失败,点击下载错误信息</div>
  272. <a href={res.data.respUrl} download>
  273. 下载
  274. </a>
  275. </NSpace>
  276. )
  277. })
  278. return
  279. }
  280. getDetail()
  281. message.success('导入成功')
  282. } else {
  283. message.error('请下载模板后,填写数据再导入')
  284. }
  285. } catch {}
  286. customRequest_importData.loading = false
  287. msg.destroy()
  288. }
  289. return () => (
  290. <div class={styles.courseConfiguration}>
  291. <NSpin show={customRequest_importData.loading}>
  292. <NSpace justify="space-between">
  293. <NSpace>
  294. <NButton
  295. disabled={route.query.isLook ? true : false}
  296. type="primary"
  297. onClick={() => {
  298. addForm.name = ''
  299. addForm.lessonTargetDesc = ''
  300. addForm.lessonTrainingId = ''
  301. addForm.id = ''
  302. addForm.level = null
  303. addForm.lockEnable = ''
  304. addForm.accessScope = 0
  305. getLevels()
  306. addForm.open = true
  307. }}
  308. >
  309. 添加课程
  310. </NButton>
  311. <NButton
  312. type="primary"
  313. disabled={route.query.isLook ? true : false}
  314. onClick={() => {
  315. unitData.open = true
  316. unitData.model = {}
  317. }}
  318. >
  319. 添加阶段自测
  320. </NButton>
  321. </NSpace>
  322. <NSpace style={{ marginLeft: 'auto' }}>
  323. <NDropdown
  324. size="huge"
  325. trigger="hover"
  326. options={[
  327. {
  328. key: '3',
  329. type: 'render',
  330. render: () => (
  331. <NButton
  332. size="large"
  333. quaternary
  334. tag="a"
  335. //@ts-ignore
  336. href="https://oss.dayaedu.com/daya-docs/%E5%8D%95%E5%85%83%E6%B5%8B%E9%AA%8C%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
  337. download
  338. >
  339. 单元测验模板
  340. </NButton>
  341. )
  342. },
  343. {
  344. key: '1',
  345. type: 'render',
  346. render: () => (
  347. <NButton
  348. size="large"
  349. quaternary
  350. tag="a"
  351. //@ts-ignore
  352. href="https://oss.dayaedu.com/daya-docs/%E8%AF%BE%E5%90%8E%E8%AE%AD%E7%BB%83%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx"
  353. download
  354. >
  355. 课后训练模板
  356. </NButton>
  357. )
  358. }
  359. ]}
  360. >
  361. <NButton type="primary" v-auth="downloadUnitQuiz1702251742292344833">
  362. 下载模板
  363. </NButton>
  364. </NDropdown>
  365. <div>
  366. <NUpload
  367. multiple={false}
  368. ref={(el: any) => (customRequest_importData.importRef = el)}
  369. showFileList={false}
  370. accept=".xlsx"
  371. customRequest={customRequest_importFile}
  372. >
  373. <NDropdown
  374. size="huge"
  375. trigger="hover"
  376. options={[
  377. { label: '课件', key: 'COURSEWARE' },
  378. { label: '单元测验', key: 'EXAMINATION' },
  379. { label: '课后训练', key: 'HOMEWORK' },
  380. { label: '素材关联曲目', key: 'COURSEWARE_REF_MATERIAL' }
  381. ]}
  382. onSelect={(key: string) => {
  383. customRequest_importData.dataType = key
  384. console.log(customRequest_importData.importRef)
  385. customRequest_importData.importRef?.clear()
  386. customRequest_importData.importRef?.openOpenFileDialog()
  387. }}
  388. >
  389. <NButton type="primary" onClick={(e: Event) => e.stopPropagation()}>
  390. 导入数据
  391. </NButton>
  392. </NDropdown>
  393. </NUpload>
  394. </div>
  395. </NSpace>
  396. </NSpace>
  397. <NAlert class={styles.title} title="教学内容" />
  398. <NGrid xGap={12} yGap={8} cols={3}>
  399. {state.dataList.map((item: any) => {
  400. const mapper = state.mapperList.find(
  401. (n: any) => n.parentCoursewareDetailId == item.id
  402. )
  403. return (
  404. <>
  405. <NGi>
  406. <NCard
  407. // title={item.name}
  408. style={{
  409. '--n-padding-top': '5px',
  410. '--n-padding-bottom': '5px',
  411. height: '100%'
  412. }}
  413. >
  414. {{
  415. header: () => <div>{item.name}{item.level && <span style="color: red">({item.level})</span>}</div>,
  416. default: () => (
  417. <div>
  418. <div style={{ paddingBottom: '12px' }}>{item.lessonTargetDesc}</div>
  419. <table style={{ width: '100%' }}>
  420. <tr>
  421. <td>建议学习时长</td>
  422. <td style={{ 'text-align': 'right' }}>
  423. {item.lessonDurationSecond || '0'}s
  424. </td>
  425. </tr>
  426. <tr>
  427. <td>知识点</td>
  428. <td style={{ 'text-align': 'right' }}>
  429. {item.knowledgePointIds?.split(',').filter(Boolean).length || 0}个
  430. </td>
  431. </tr>
  432. <tr>
  433. <td>课后作业</td>
  434. <td style={{ 'text-align': 'right' }}>
  435. {item.lessonTrainingId ? (
  436. <>
  437. <TheLink
  438. // to={`/#/afterClassTrainingDetail?id=${item.lessonTrainingId}&name=${item.lessonTrainingName}&courseTypeCode=TRUMPET_SINGLE`}
  439. authLink="afterClassTrainingManage1599968711187746818"
  440. to={{
  441. path: '/afterClassTrainingManage',
  442. query: { id: item.lessonTrainingId }
  443. }}
  444. >
  445. {item.lessonTrainingName}
  446. </TheLink>
  447. <NTooltip>
  448. {{
  449. default: () => '删除',
  450. trigger: () => (
  451. <NButton
  452. v-auth="lessonCoursewareDetail/removeTraining1793827126242213890"
  453. quaternary
  454. size="small"
  455. circle
  456. onClick={() => hanldeRemoveTraning(item)}
  457. >
  458. <NIcon component={<DeleteFilled />} />
  459. </NButton>
  460. )
  461. }}
  462. </NTooltip>
  463. </>
  464. ) : (
  465. '无'
  466. )}
  467. </td>
  468. </tr>
  469. </table>
  470. </div>
  471. ),
  472. 'header-extra': () => (
  473. <>
  474. <NTooltip>
  475. {{
  476. default: () => (item.lockFlag ? '解锁' : '锁定'),
  477. trigger: () => (
  478. <NButton
  479. disabled={route.query.isLook ? true : false}
  480. quaternary
  481. circle
  482. onClick={() => toggleLock(item)}
  483. >
  484. <NIcon
  485. component={item.lockFlag ? <LockFilled /> : <UnlockFilled />}
  486. />
  487. </NButton>
  488. )
  489. }}
  490. </NTooltip>
  491. <NTooltip>
  492. {{
  493. default: () => '编辑',
  494. trigger: () => (
  495. <NButton
  496. disabled={route.query.isLook ? true : false}
  497. quaternary
  498. circle
  499. onClick={() => {
  500. addForm.name = item.name
  501. addForm.lessonTargetDesc = item.lessonTargetDesc
  502. addForm.id = item.id
  503. addForm.lockEnable = item.lockEnable + ''
  504. addForm.accessScope = item.accessScope ?? 0
  505. addForm.level = item.level
  506. getLevels(item)
  507. addForm.open = true
  508. }}
  509. >
  510. <NIcon component={<EditFilled />} />
  511. </NButton>
  512. )
  513. }}
  514. </NTooltip>
  515. <NTooltip>
  516. {{
  517. default: () => '删除',
  518. trigger: () => (
  519. <NButton
  520. disabled={route.query.isLook ? true : false}
  521. quaternary
  522. circle
  523. onClick={() => hanldeDelete(item)}
  524. >
  525. <NIcon component={<DeleteFilled />} />
  526. </NButton>
  527. )
  528. }}
  529. </NTooltip>
  530. </>
  531. ),
  532. action: () => (
  533. <NSpace justify="space-around">
  534. <NButton
  535. text
  536. disabled={route.query.isLook ? true : false}
  537. onClick={() => {
  538. courseData.title = item.name
  539. courseData.open = true
  540. courseData.item = item
  541. }}
  542. >
  543. 选择知识点
  544. </NButton>
  545. <NButton
  546. text
  547. disabled={route.query.isLook ? true : false}
  548. onClick={() => {
  549. addForm.id = item.id
  550. addForm.lessonTargetDesc = item.lessonTargetDesc
  551. addForm.name = item.name
  552. afterTrain.open = true
  553. }}
  554. >
  555. 选择课后作业
  556. </NButton>
  557. </NSpace>
  558. )
  559. }}
  560. </NCard>
  561. </NGi>
  562. {mapper && (
  563. <NGi>
  564. <NCard
  565. title={mapper.name}
  566. style={{
  567. '--n-padding-top': '5px',
  568. '--n-padding-bottom': '5px',
  569. '--n-color': 'rgba(238,243,254,1)',
  570. '--n-action-color': 'rgba(238,243,254,1)',
  571. height: '100%'
  572. }}
  573. >
  574. {{
  575. default: () => (
  576. <div>
  577. <div style={{ paddingBottom: '12px' }}>{mapper.desc}</div>
  578. <table style={{ width: '100%' }}>
  579. <tr>
  580. <td>单团学生</td>
  581. <td style={{ 'text-align': 'right' }}>
  582. {mapper?.details?.[0]?.unitExaminationName || '无'}
  583. </td>
  584. </tr>
  585. <tr>
  586. <td>双团学生</td>
  587. <td style={{ 'text-align': 'right' }}>
  588. {mapper?.details?.[1]?.unitExaminationName || '无'}
  589. </td>
  590. </tr>
  591. <tr>
  592. <td>多团学生</td>
  593. <td style={{ 'text-align': 'right' }}>
  594. {mapper?.details?.[2]?.unitExaminationName || '无'}
  595. </td>
  596. </tr>
  597. </table>
  598. </div>
  599. ),
  600. action: () => (
  601. <NSpace justify="space-around">
  602. <NButton
  603. text
  604. disabled={route.query.isLook ? true : false}
  605. onClick={() => {
  606. unitData.open = true
  607. unitData.model = mapper
  608. }}
  609. >
  610. 编辑阶段自测
  611. </NButton>
  612. </NSpace>
  613. )
  614. }}
  615. </NCard>
  616. </NGi>
  617. )}
  618. </>
  619. )
  620. })}
  621. </NGrid>
  622. </NSpin>
  623. {state.dataList.length ? null : <NEmpty />}
  624. {/* 课程编辑 */}
  625. <NModal
  626. preset="dialog"
  627. v-model:show={addForm.open}
  628. title={addForm.id ? '编辑课程' : '添加课程'}
  629. showIcon={false}
  630. >
  631. <NForm ref={addFormRef} model={addForm}>
  632. <NFormItem
  633. label="课程名称"
  634. required
  635. path="name"
  636. rule={[{ required: true, message: '请填写课程名称', trigger: ['blur', 'change'] }]}
  637. >
  638. <NInput v-model:value={addForm.name} />
  639. </NFormItem>
  640. <NFormItem label="课程编号" path="level">
  641. <NSelect
  642. filterable
  643. placeholder="请选择课程编号"
  644. clearable
  645. v-model:value={addForm.level}
  646. options={courseTypeIds}
  647. />
  648. </NFormItem>
  649. <NFormItem
  650. label="是否需要解锁"
  651. required
  652. path="lockEnable"
  653. rule={[{ required: true, message: '请选择是否解锁', trigger: ['blur', 'change'] }]}
  654. >
  655. <NSelect
  656. v-model:value={addForm.lockEnable}
  657. options={
  658. [
  659. {
  660. label: '是',
  661. value: 'true'
  662. },
  663. {
  664. label: '否',
  665. value: 'false'
  666. }
  667. ] as any
  668. }
  669. clearable
  670. ></NSelect>
  671. </NFormItem>
  672. <NFormItem
  673. label="是否免费"
  674. required
  675. path="accessScope"
  676. rule={[
  677. {
  678. type: 'number',
  679. required: true,
  680. message: '设置是否免费',
  681. trigger: ['blur', 'change']
  682. }
  683. ]}
  684. >
  685. <NSelect
  686. v-model:value={addForm.accessScope}
  687. options={
  688. [
  689. {
  690. label: '是',
  691. value: 0
  692. },
  693. {
  694. label: '否',
  695. value: 1
  696. }
  697. ] as any
  698. }
  699. clearable
  700. ></NSelect>
  701. </NFormItem>
  702. <NFormItem
  703. label="阶段目标"
  704. required
  705. path="lessonTargetDesc"
  706. // rule={[{ required: true, message: '请填写教学目标', trigger: ['blur', 'change'] }]}
  707. >
  708. <NInput
  709. type="textarea"
  710. rows={3}
  711. v-model:value={addForm.lessonTargetDesc}
  712. maxlength={1500}
  713. showCount={true}
  714. />
  715. </NFormItem>
  716. <NSpace justify="end">
  717. <NButton onClick={() => (addForm.open = false)}>取消</NButton>
  718. <NButton type="primary" onClick={() => addCourseware()}>
  719. 确认
  720. </NButton>
  721. </NSpace>
  722. </NForm>
  723. </NModal>
  724. {/* 课后作业 */}
  725. <NModal
  726. preset="dialog"
  727. v-model:show={afterTrain.open}
  728. title="选择课后作业"
  729. showIcon={false}
  730. style={{ width: '80vw' }}
  731. >
  732. <SelectAfterClassTraining
  733. courseTypeCode={props.course?.courseTypeCode}
  734. onHandleSuccess={addAfterTrain}
  735. />
  736. </NModal>
  737. {/* 课程详情编辑 */}
  738. <NDrawer v-model:show={courseData.open} width="80vw">
  739. <NDrawerContent title={courseData.title} closable>
  740. {{
  741. default: () => (
  742. <CourseKnowledgePoint
  743. courseTypeCode={props.course?.courseTypeCode}
  744. item={courseData.item as any}
  745. onHandleSuccess={() => {
  746. getDetail()
  747. }}
  748. />
  749. ),
  750. footer: () => (
  751. <NSpace>
  752. <NButton onClick={() => (courseData.open = false)}>取消</NButton>
  753. <NButton type="primary" onClick={() => (courseData.open = false)}>
  754. 确认
  755. </NButton>
  756. </NSpace>
  757. )
  758. }}
  759. </NDrawerContent>
  760. </NDrawer>
  761. {/* 阶段自测 */}
  762. <NModal
  763. preset="dialog"
  764. v-model:show={unitData.open}
  765. title={(unitData.model as any)?.id ? '编辑阶段自测' : '新增阶段自测'}
  766. showIcon={false}
  767. style={{ width: '500px' }}
  768. >
  769. <AddUnitTest
  770. courseTypeCode={props.course?.courseTypeCode}
  771. list={state.dataList}
  772. item={unitData.model}
  773. onClose={(result) => {
  774. if (result) {
  775. getDetail()
  776. getMapperAll()
  777. }
  778. unitData.open = false
  779. }}
  780. />
  781. </NModal>
  782. </div>
  783. )
  784. }
  785. })