courseConfiguration.tsx 28 KB

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