123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799 |
- import {
- NAlert,
- NButton,
- NCard,
- NDialog,
- NDrawer,
- NDrawerContent,
- NDropdown,
- NEmpty,
- NForm,
- NFormItem,
- NGi,
- NGrid,
- NIcon,
- NInput,
- NModal,
- NSelect,
- NSpace,
- NSpin,
- NTooltip,
- NUpload,
- UploadCustomRequestOptions,
- useDialog,
- useMessage
- } from 'naive-ui'
- import { defineComponent, onMounted, reactive, ref } from 'vue'
- import { useRoute } from 'vue-router'
- import {
- lessonCoursewareDetailPage,
- lessonCoursewareDetailSave,
- lessonCoursewareDetailUpdate,
- lessonTrainingPage,
- lessonCoursewareDetailRemove,
- lessonCoursewareExaminationMapperQueryAll,
- lessonCoursewareDetailLock,
- api_openFileImportInfoSave,
- api_removeTraining,
- api_getUsedLevelDetail
- } from '../../api'
- import styles from '../index.module.less'
- import { EditFilled, DeleteFilled, LockFilled, UnlockFilled } from '@vicons/antd'
- import CourseKnowledgePoint from '../model/CourseKnowledgePoint'
- import SelectAfterClassTraining from '../model/selectAfterClassTraining'
- import AddUnitTest from '../model/AddUnitTest'
- import TheLink from '@/components/TheLink'
- import { api_uploadFile } from '@/plugins/uploadFile'
- const courseTypeIds: any = []
- for(let i = 1; i <= 20; i++) {
- courseTypeIds.push({
- label: i,
- value: i
- })
- }
- export default defineComponent({
- name: 'courseConfiguration',
- props: {
- course: {
- type: Object,
- default: () => {}
- }
- },
- setup(props, ctx) {
- const message = useMessage()
- const dialog = useDialog()
- const route = useRoute()
- const addFormRef = ref()
- const addForm = reactive({
- open: false,
- id: '',
- name: '', //课时名称
- lessonTargetDesc: '', //课时名称
- lessonTrainingId: '', //课后作业
- lockEnable: 'true',
- level: null,
- accessScope: 0
- })
- // 课件添加课程
- const addCourseware = () => {
- addFormRef.value.validate(async (err: any) => {
- if (!err) {
- const body = {
- lessonCoursewareId: route.query.id,
- name: addForm.name,
- level: addForm.level,
- lessonTargetDesc: addForm.lessonTargetDesc,
- lockEnable: addForm.lockEnable,
- accessScope: addForm.accessScope
- }
- let res: any
- if (addForm.id) {
- try {
- res = await lessonCoursewareDetailUpdate({
- ...body,
- id: addForm.id
- })
- } catch (error) {}
- } else {
- try {
- res = await lessonCoursewareDetailSave(body)
- } catch (error) {}
- }
- if (res?.code == 200) {
- message.success('保存成功')
- addForm.open = false
- getDetail()
- }
- }
- })
- }
- const state = reactive({
- dataList: [] as any,
- mapperList: [] as any
- })
- const getDetail = async () => {
- try {
- const { data } = await lessonCoursewareDetailPage({
- lessonCoursewareId: route.query.id,
- page: 1,
- rows: 1000
- })
- if (Array.isArray(data?.rows)) {
- state.dataList = data.rows
- }
- } catch (error) {}
- }
- /** 查询课件下的所有阶段自测 */
- const getMapperAll = async () => {
- try {
- const { data } = await lessonCoursewareExaminationMapperQueryAll(route.query.id)
- if (Array.isArray(data)) {
- state.mapperList = data
- }
- } catch (error) {}
- }
- /** 获取级别 */
- const getLevels = async (item?: any) => {
- const { data } = await api_getUsedLevelDetail({
- id: item?.id,
- lessonCoursewareId: route.query.id
- })
- if(Array.isArray(data)) {
- courseTypeIds.forEach((item: any) => {
- item.disabled = data.includes(item.value) ? true : false
- })
- }
- }
- onMounted(() => {
- getDetail()
- getMapperAll()
- })
- //删除课时
- const hanldeDelete = (item: any) => {
- const d = dialog.warning({
- title: '警告',
- content: '是否确认删除此课时?',
- positiveText: '确定',
- negativeText: '取消',
- onPositiveClick: async () => {
- d.loading = true
- try {
- const res: any = await lessonCoursewareDetailRemove(item.id)
- if (res?.code == 200) {
- message.success('删除成功')
- getDetail()
- }
- } catch (error) {}
- d.loading = false
- }
- })
- }
- //绑定课后作业
- const afterTrain = reactive({
- open: false,
- id: ''
- })
- const addAfterTrain = async (row: any) => {
- console.log('🚀 ~ row', row)
- const body = {
- id: addForm.id,
- lessonTrainingId: row.id,
- name: addForm.name,
- lessonTargetDesc: addForm.lessonTargetDesc
- }
- try {
- const res: any = await lessonCoursewareDetailUpdate(body)
- if (res?.code == 200) {
- message.success('保存成功')
- afterTrain.open = false
- getDetail()
- }
- } catch (error) {}
- }
- // 课程配置
- const courseData = reactive({
- open: false,
- title: '',
- item: null
- })
- //阶段自测
- const unitData = reactive({
- open: false,
- model: {}
- })
- /** 切换课件是否锁定 */
- const toggleLock = (item: any) => {
- const d = dialog.warning({
- title: '警告',
- content: `是否确认${item.lockFlag ? '解锁' : '锁定'}此课时?`,
- positiveText: '确定',
- negativeText: '取消',
- onPositiveClick: async () => {
- d.loading = true
- try {
- const res = await lessonCoursewareDetailLock({ id: item.id, lockFlag: !item.lockFlag })
- message.success('操作成功')
- getDetail()
- } catch (error) {}
- d.loading = false
- }
- })
- }
- /** 删除选择的作业 */
- const hanldeRemoveTraning = (item: any) => {
- const d = dialog.warning({
- title: '警告',
- content: `是否确认删除作业?`,
- positiveText: '确定',
- negativeText: '取消',
- onPositiveClick: async () => {
- d.loading = true
- try {
- const res = await api_removeTraining(item.id)
- message.success('删除成功')
- getDetail()
- } catch (error) {}
- d.loading = false
- }
- })
- }
- const customRequest_importData = reactive({
- loading: false,
- dataType: 'EXAMINATION',
- importRef: null as any
- })
- const customRequest_importFile = async (data: UploadCustomRequestOptions) => {
- console.log(data.file)
- const msg = message.loading('正在上传文件', { duration: 0 })
- customRequest_importData.loading = true
- try {
- const fileUrl = await api_uploadFile(data.file.file, () => {})
- const res = await api_openFileImportInfoSave({
- dataType: customRequest_importData.dataType,
- fileName: data.file.name,
- importUrl: fileUrl,
- lessonId: route.query.id
- })
- console.log('🚀 ~ res:', res)
- customRequest_importData.loading = false
- if (res.data) {
- msg.destroy()
- // 空表格
- if (res.data.insertRow === 0 && res.data.invalidRow === 0) {
- message.error('导入失败,表格为空')
- return
- }
- if (res.data.respUrl) {
- dialog.error({
- title: '信息',
- content: () => (
- <NSpace>
- <div>导入失败,点击下载错误信息</div>
- <a href={res.data.respUrl} download>
- 下载
- </a>
- </NSpace>
- )
- })
- return
- }
- getDetail()
- message.success('导入成功')
- } else {
- message.error('请下载模板后,填写数据再导入')
- }
- } catch {}
- customRequest_importData.loading = false
- msg.destroy()
- }
- return () => (
- <div class={styles.courseConfiguration}>
- <NSpin show={customRequest_importData.loading}>
- <NSpace justify="space-between">
- <NSpace>
- <NButton
- disabled={route.query.isLook ? true : false}
- type="primary"
- onClick={() => {
- addForm.name = ''
- addForm.lessonTargetDesc = ''
- addForm.lessonTrainingId = ''
- addForm.id = ''
- addForm.lockEnable = ''
- addForm.accessScope = 0
- getLevels()
- addForm.open = true
- }}
- >
- 添加课程
- </NButton>
- <NButton
- type="primary"
- disabled={route.query.isLook ? true : false}
- onClick={() => {
- unitData.open = true
- unitData.model = {}
- }}
- >
- 添加阶段自测
- </NButton>
- </NSpace>
- <NSpace style={{ marginLeft: 'auto' }}>
- <NDropdown
- size="huge"
- trigger="hover"
- options={[
- {
- key: '3',
- type: 'render',
- render: () => (
- <NButton
- size="large"
- quaternary
- tag="a"
- //@ts-ignore
- 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"
- download
- >
- 单元测验模板
- </NButton>
- )
- },
- {
- key: '1',
- type: 'render',
- render: () => (
- <NButton
- size="large"
- quaternary
- tag="a"
- //@ts-ignore
- 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"
- download
- >
- 课后训练模板
- </NButton>
- )
- }
- ]}
- >
- <NButton type="primary" v-auth="downloadUnitQuiz1702251742292344833">
- 下载模板
- </NButton>
- </NDropdown>
- <div>
- <NUpload
- multiple={false}
- ref={(el: any) => (customRequest_importData.importRef = el)}
- showFileList={false}
- accept=".xlsx"
- customRequest={customRequest_importFile}
- >
- <NDropdown
- size="huge"
- trigger="hover"
- options={[
- { label: '课件', key: 'COURSEWARE' },
- { label: '单元测验', key: 'EXAMINATION' },
- { label: '课后训练', key: 'HOMEWORK' }
- ]}
- onSelect={(key: string) => {
- customRequest_importData.dataType = key
- console.log(customRequest_importData.importRef)
- customRequest_importData.importRef?.clear()
- customRequest_importData.importRef?.openOpenFileDialog()
- }}
- >
- <NButton type="primary" onClick={(e: Event) => e.stopPropagation()}>
- 导入数据
- </NButton>
- </NDropdown>
- </NUpload>
- </div>
- </NSpace>
- </NSpace>
- <NAlert class={styles.title} title="教学内容" />
- <NGrid xGap={12} yGap={8} cols={3}>
- {state.dataList.map((item: any) => {
- const mapper = state.mapperList.find(
- (n: any) => n.parentCoursewareDetailId == item.id
- )
- return (
- <>
- <NGi>
- <NCard
- // title={item.name}
- style={{
- '--n-padding-top': '5px',
- '--n-padding-bottom': '5px',
- height: '100%'
- }}
- >
- {{
- header: () => <div>{item.name}{item.level && <span style="color: red">({item.level})</span>}</div>,
- default: () => (
- <div>
- <div style={{ paddingBottom: '12px' }}>{item.lessonTargetDesc}</div>
- <table style={{ width: '100%' }}>
- <tr>
- <td>建议学习时长</td>
- <td style={{ 'text-align': 'right' }}>
- {item.lessonDurationSecond || '0'}s
- </td>
- </tr>
- <tr>
- <td>知识点</td>
- <td style={{ 'text-align': 'right' }}>
- {item.knowledgePointIds?.split(',').filter(Boolean).length || 0}个
- </td>
- </tr>
- <tr>
- <td>课后作业</td>
- <td style={{ 'text-align': 'right' }}>
- {item.lessonTrainingId ? (
- <>
- <TheLink
- // to={`/#/afterClassTrainingDetail?id=${item.lessonTrainingId}&name=${item.lessonTrainingName}&courseTypeCode=TRUMPET_SINGLE`}
- authLink="afterClassTrainingManage1599968711187746818"
- to={{
- path: '/afterClassTrainingManage',
- query: { id: item.lessonTrainingId }
- }}
- >
- {item.lessonTrainingName}
- </TheLink>
- <NTooltip>
- {{
- default: () => '删除',
- trigger: () => (
- <NButton
- v-auth="lessonCoursewareDetail/removeTraining1793827126242213890"
- quaternary
- size="small"
- circle
- onClick={() => hanldeRemoveTraning(item)}
- >
- <NIcon component={<DeleteFilled />} />
- </NButton>
- )
- }}
- </NTooltip>
- </>
- ) : (
- '无'
- )}
- </td>
- </tr>
- </table>
- </div>
- ),
- 'header-extra': () => (
- <>
- <NTooltip>
- {{
- default: () => (item.lockFlag ? '解锁' : '锁定'),
- trigger: () => (
- <NButton
- disabled={route.query.isLook ? true : false}
- quaternary
- circle
- onClick={() => toggleLock(item)}
- >
- <NIcon
- component={item.lockFlag ? <LockFilled /> : <UnlockFilled />}
- />
- </NButton>
- )
- }}
- </NTooltip>
- <NTooltip>
- {{
- default: () => '编辑',
- trigger: () => (
- <NButton
- disabled={route.query.isLook ? true : false}
- quaternary
- circle
- onClick={() => {
- addForm.name = item.name
- addForm.lessonTargetDesc = item.lessonTargetDesc
- addForm.id = item.id
- addForm.lockEnable = item.lockEnable + ''
- addForm.accessScope = item.accessScope ?? 0
- addForm.level = item.level
- getLevels(item)
- addForm.open = true
- }}
- >
- <NIcon component={<EditFilled />} />
- </NButton>
- )
- }}
- </NTooltip>
- <NTooltip>
- {{
- default: () => '删除',
- trigger: () => (
- <NButton
- disabled={route.query.isLook ? true : false}
- quaternary
- circle
- onClick={() => hanldeDelete(item)}
- >
- <NIcon component={<DeleteFilled />} />
- </NButton>
- )
- }}
- </NTooltip>
- </>
- ),
- action: () => (
- <NSpace justify="space-around">
- <NButton
- text
- disabled={route.query.isLook ? true : false}
- onClick={() => {
- courseData.title = item.name
- courseData.open = true
- courseData.item = item
- }}
- >
- 选择知识点
- </NButton>
- <NButton
- text
- disabled={route.query.isLook ? true : false}
- onClick={() => {
- addForm.id = item.id
- addForm.lessonTargetDesc = item.lessonTargetDesc
- addForm.name = item.name
- afterTrain.open = true
- }}
- >
- 选择课后作业
- </NButton>
- </NSpace>
- )
- }}
- </NCard>
- </NGi>
- {mapper && (
- <NGi>
- <NCard
- title={mapper.name}
- style={{
- '--n-padding-top': '5px',
- '--n-padding-bottom': '5px',
- '--n-color': 'rgba(238,243,254,1)',
- '--n-action-color': 'rgba(238,243,254,1)',
- height: '100%'
- }}
- >
- {{
- default: () => (
- <div>
- <div style={{ paddingBottom: '12px' }}>{mapper.desc}</div>
- <table style={{ width: '100%' }}>
- <tr>
- <td>单团学生</td>
- <td style={{ 'text-align': 'right' }}>
- {mapper?.details?.[0]?.unitExaminationName || '无'}
- </td>
- </tr>
- <tr>
- <td>双团学生</td>
- <td style={{ 'text-align': 'right' }}>
- {mapper?.details?.[1]?.unitExaminationName || '无'}
- </td>
- </tr>
- <tr>
- <td>多团学生</td>
- <td style={{ 'text-align': 'right' }}>
- {mapper?.details?.[2]?.unitExaminationName || '无'}
- </td>
- </tr>
- </table>
- </div>
- ),
- action: () => (
- <NSpace justify="space-around">
- <NButton
- text
- disabled={route.query.isLook ? true : false}
- onClick={() => {
- unitData.open = true
- unitData.model = mapper
- }}
- >
- 编辑阶段自测
- </NButton>
- </NSpace>
- )
- }}
- </NCard>
- </NGi>
- )}
- </>
- )
- })}
- </NGrid>
- </NSpin>
- {state.dataList.length ? null : <NEmpty />}
- {/* 课程编辑 */}
- <NModal
- preset="dialog"
- v-model:show={addForm.open}
- title={addForm.id ? '编辑课程' : '添加课程'}
- showIcon={false}
- >
- <NForm ref={addFormRef} model={addForm}>
- <NFormItem
- label="课程名称"
- required
- path="name"
- rule={[{ required: true, message: '请填写课程名称', trigger: ['blur', 'change'] }]}
- >
- <NInput v-model:value={addForm.name} />
- </NFormItem>
- <NFormItem label="课程编号" path="level">
- <NSelect
- filterable
- placeholder="请选择课程编号"
- clearable
- v-model:value={addForm.level}
- options={courseTypeIds}
- />
- </NFormItem>
- <NFormItem
- label="是否需要解锁"
- required
- path="lockEnable"
- rule={[{ required: true, message: '请选择是否解锁', trigger: ['blur', 'change'] }]}
- >
- <NSelect
- v-model:value={addForm.lockEnable}
- options={
- [
- {
- label: '是',
- value: 'true'
- },
- {
- label: '否',
- value: 'false'
- }
- ] as any
- }
- clearable
- ></NSelect>
- </NFormItem>
- <NFormItem
- label="是否免费"
- required
- path="accessScope"
- rule={[
- {
- type: 'number',
- required: true,
- message: '设置是否免费',
- trigger: ['blur', 'change']
- }
- ]}
- >
- <NSelect
- v-model:value={addForm.accessScope}
- options={
- [
- {
- label: '是',
- value: 0
- },
- {
- label: '否',
- value: 1
- }
- ] as any
- }
- clearable
- ></NSelect>
- </NFormItem>
- <NFormItem
- label="教学目标"
- required
- path="lessonTargetDesc"
- rule={[{ required: true, message: '请填写教学目标', trigger: ['blur', 'change'] }]}
- >
- <NInput
- type="textarea"
- rows={3}
- v-model:value={addForm.lessonTargetDesc}
- maxlength={500}
- showCount={true}
- />
- </NFormItem>
- <NSpace justify="end">
- <NButton onClick={() => (addForm.open = false)}>取消</NButton>
- <NButton type="primary" onClick={() => addCourseware()}>
- 确认
- </NButton>
- </NSpace>
- </NForm>
- </NModal>
- {/* 课后作业 */}
- <NModal
- preset="dialog"
- v-model:show={afterTrain.open}
- title="选择课后作业"
- showIcon={false}
- style={{ width: '80vw' }}
- >
- <SelectAfterClassTraining
- courseTypeCode={props.course?.courseTypeCode}
- onHandleSuccess={addAfterTrain}
- />
- </NModal>
- {/* 课程详情编辑 */}
- <NDrawer v-model:show={courseData.open} width="80vw">
- <NDrawerContent title={courseData.title} closable>
- {{
- default: () => (
- <CourseKnowledgePoint
- courseTypeCode={props.course?.courseTypeCode}
- item={courseData.item as any}
- onHandleSuccess={() => {
- getDetail()
- }}
- />
- ),
- footer: () => (
- <NSpace>
- <NButton onClick={() => (courseData.open = false)}>取消</NButton>
- <NButton type="primary" onClick={() => (courseData.open = false)}>
- 确认
- </NButton>
- </NSpace>
- )
- }}
- </NDrawerContent>
- </NDrawer>
- {/* 阶段自测 */}
- <NModal
- preset="dialog"
- v-model:show={unitData.open}
- title={(unitData.model as any)?.id ? '编辑阶段自测' : '新增阶段自测'}
- showIcon={false}
- style={{ width: '500px' }}
- >
- <AddUnitTest
- courseTypeCode={props.course?.courseTypeCode}
- list={state.dataList}
- item={unitData.model}
- onClose={(result) => {
- if (result) {
- getDetail()
- getMapperAll()
- }
- unitData.open = false
- }}
- />
- </NModal>
- </div>
- )
- }
- })
|