Преглед изворни кода

feat(课程管理): 添加课程删除功能并优化相关组件

refactor(课程添加): 重构课程信息组件状态管理
- 使用本地ref存储courseInfoId并监听props变化
- 添加表单重置功能
- 移除调试代码和注释代码

feat(课程制作): 为章节添加添加知识点选择功能
- 在章节表单中添加知识点多选
- 添加表单验证规则
- 优化章节添加/编辑逻辑

style: 清理调试日志和注释代码
tanshanming пре 6 месеци
родитељ
комит
fea90931fb

+ 1 - 0
src/api/courseinfo/index.js

@@ -9,6 +9,7 @@ const request = moduleRequest(`/api/webapp/`)
 // 获取文件列表(区分文件路径)
 export const list = (p) => request('disk/courseinfo/page', p, 'get')
 export const copy = (p) => request('disk/courseinfo/copy', p, 'post')
+export const deletes = (p) => request('disk/courseinfo/delete', p, 'post')
 // 获取文件列表(区分文件类型)
 // export const getFileListByType = (p) => request('file/selectfilebyfiletype', p, 'get')
 

+ 22 - 34
src/views/courseAdd/components/courseInfo.vue

@@ -33,7 +33,7 @@
 			></coverUpload>
 		</a-form-item>
 
-		<a-form-item label="院系" name="collegeTwoId">
+		<!-- <a-form-item label="院系" name="collegeTwoId">
 			<a-select
 				v-model:value="formState.collegeTwoId"
 				:fieldNames="{ label: 'name', value: 'id' }"
@@ -41,14 +41,6 @@
 				placeholder="请选择专业"
 				@change="changeCollegeMajor"
 			/>
-			<!--			<a-cascader-->
-			<!--				v-model:value="majorIdName"-->
-			<!--				:options="collegeMajorOptions"-->
-			<!--				:fieldNames="{ label: 'name', value: 'id' }"-->
-			<!--				placeholder="请选择院系"-->
-			<!--				changeOnSelect-->
-			<!--				@change="changeCollegeMajor"-->
-			<!--			/>-->
 		</a-form-item>
 		<a-form-item label="专业" name="majorId">
 			<a-select
@@ -57,7 +49,7 @@
 				:options="majorOptions"
 				placeholder="请选择专业"
 			/>
-		</a-form-item>
+		</a-form-item> -->
 
 		<a-form-item label="教室描述" name="courseDesc">
 			<quill-editor
@@ -130,7 +122,6 @@
 	const courseClass = tool.dictList('COURSE_TYPE')
 
 	const handleSubmit = () => {
-		console.log('表单数据:', formState)
 		// 这里添加实际提交逻辑,例如:
 		// let params = {
 		// 	current: pagination.pageNum,
@@ -144,7 +135,6 @@
 		courseCenterApi
 			.add(formState)
 			.then((res) => {
-				console.log(res.data, '表单添加')
 				courseInfoId.value = res.data.courseId
 				// localStorage.setItem('courseInfoId', res.data.courseId)
 				emit('nextStep', res.data.courseId)
@@ -154,13 +144,11 @@
 			})
 	}
 	const handleEdit = () => {
-		console.log('表单编辑数据:', formState)
 		// collegeId
 		formState.courseDesc = toRaw(quillEditorRef.value).getHTML()
 		courseCenterApi
 			.edit({ ...formState, courseId: courseInfoId.value })
 			.then((res) => {
-				console.log(res.data, '表单编辑')
 				emit('nextStep', courseInfoId.value)
 			})
 			.catch((err) => {
@@ -208,7 +196,6 @@
 			})
 	}
 	const changeCollegeMajor = (value, selectedOptions) => {
-		console.log('Selected:', value, selectedOptions)
 		if (!value) {
 			formState.collegeTwoId = ''
 			// majorIdName.value = ''
@@ -227,7 +214,6 @@
 		// 	name: lastSelected.name,
 		// 	fullPath: selectedOptions.map((opt) => opt.name).join(' / ')
 		// }
-		console.log(formState.collegeTwoId, '最后一级id')
 		getCollegeMajor(formState.collegeTwoId)
 		// }
 	}
@@ -235,7 +221,6 @@
 		resourceAuditApi
 			.zyselect({ collegeId: id })
 			.then((res) => {
-				console.log(res.data, '专业下拉数据')
 				majorOptions.value = res.data
 			})
 			.catch((err) => {
@@ -247,7 +232,6 @@
 		resourceAuditApi
 			.courseAllList()
 			.then((res) => {
-				console.log(res.data, '获取全部课程')
 				courseOptions.value = res.data
 			})
 			.catch((err) => {
@@ -258,7 +242,6 @@
 	const getDetail = () => {
 		courseInfoId.value = props.courseInfoId
 		courseCenterApi.detail({ courseId: props.courseInfoId }).then((res) => {
-			console.log(res.data, '课程信息详情')
 			formState.courseName = res.data.courseName
 			formState.teacherId = res.data.teacherId
 			formState.collegeId = res.data.collegeId
@@ -273,26 +256,31 @@
 			formState.majorId = res.data.majorId
 		})
 	}
-	//  const quill = toRaw(myQuillEditor.value).getQuill()
-	//   if (myQuillEditor.value) {
-	//     quill.getModule('toolbar').addHandler('image', imgHandler)
-	//   }
-
-	// ————————————————
-
-	//                             版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
+	const resetForm = () => {
+		if (formState.courseName) {
+			formRef.value.resetFields()
+			formState.coverImageId = null
+			formState.courseDesc = ''
+			coverImagePath.value = undefined
+			// 重置富文本编辑器内容
+			if (quillEditorRef.value) {
+				toRaw(quillEditorRef.value).setHTML('')
+			}
+		}
+	}
 
-	// 原文链接:https://blog.csdn.net/moanuan/article/details/128240291
 	watch(
 		() => props.courseInfoId,
 		(newVal) => {
+			// 初始化下拉选项数据
+			getOrgTreeSelector()
+			getCourseAllList()
+			getlecturerListSelector()
+
 			if (newVal) {
-				getOrgTreeSelector()
-				getCourseAllList()
-				getlecturerListSelector()
-				if (props.courseInfoId) {
-					getDetail()
-				}
+				getDetail()
+			} else {
+				resetForm()
 			}
 		},
 		{ immediate: true }

+ 66 - 46
src/views/courseAdd/components/courseProduction/index.vue

@@ -61,10 +61,22 @@
 		</div>
 		<!-- 添加章节模态框 -->
 		<a-modal v-model:visible="modalVisible" :title="dialogTitle" @ok="handleOk" @cancel="handleCancel">
-			<a-form :model="formState">
-				<a-form-item label="章节名称">
+			<a-form :model="formState" ref="formRef" :rules="rules" :label-col="{ span: 7 }" :wrapper-col="{ span: 12 }">
+				<a-form-item label="章节名称" name="chapterName">
 					<a-input v-model:value="formState.chapterName" placeholder="请输入章节名称" />
 				</a-form-item>
+				<a-form-item label="知识点" name="knowledgeIds">
+					<a-select
+						mode="multiple"
+						v-model:value="formState.knowledgeIds"
+						placeholder="请选择知识点"
+						style="width: 220px"
+					>
+						<a-select-option v-for="(item, index) in knowledgeOptions" :key="index" :value="item.value"
+							>{{ item.label }}
+						</a-select-option>
+					</a-select>
+				</a-form-item>
 			</a-form>
 		</a-modal>
 		<!-- 添加课时模态框 -->
@@ -78,12 +90,15 @@
 	import courseProductionApi from '@/api/courseCenter/courseProduction.js'
 	import { useRoute, useRouter } from 'vue-router'
 	import { del, edit as editApi } from '@/api/hour/index'
+	import tool from '@/utils/tool'
 
 	const router = useRouter()
 	const route = useRoute()
 	const popoverVisible = ref({})
+	const formRef = ref(null)
 	const modeTag = ref('add')
 	const dialogTitle = ref('添加章节')
+	const knowledgeOptions = tool.dictList('knowledge')
 
 	const props = defineProps({
 		//课程id
@@ -102,8 +117,6 @@
 		addDialogRef.value.edit(item)
 	}
 	const handleDel = (item) => {
-		console.log('删除', item)
-
 		del([{ id: item.id }]).then(() => {
 			getList()
 		})
@@ -116,8 +129,13 @@
 	// 表单状态
 	const formState = reactive({
 		id: '',
-		chapterName: ''
+		chapterName: undefined,
+		knowledgeIds: []
 	})
+	const rules = {
+		chapterName: [{ required: true, message: '请输入章节名称', trigger: 'blur' }],
+		knowledgeIds: [{ required: true, message: '请选择知识点', trigger: 'blur' }]
+	}
 	const pagination = reactive({
 		pageSize: 10,
 		pageNum: 1,
@@ -129,45 +147,49 @@
 		dialogTitle.value = '添加章节'
 		modeTag.value = 'add'
 		modalVisible.value = true
+
 		formState.chapterName = ''
+		formState.knowledgeIds = []
 	}
 
 	// 确认按钮点击事件
 	const handleOk = () => {
-		let courseInfoId = props.courseInfoId
-		if (formState.chapterName && modeTag.value == 'add') {
-			courseProductionApi
-				.add({
-					courseId: courseInfoId,
-					name: formState.chapterName
-				})
-				.then((res) => {
-					console.log(res, '章节添加')
-					getList()
-				})
-				.catch((err) => {
-					console.log(err)
-				})
-			formState.chapterName = '' // 清空表单
-			modalVisible.value = false // 关闭模态框
-		}
-		if (formState.chapterName && modeTag.value == 'edit') {
-			courseProductionApi
-				.edit({
-					id: formState.id,
-					courseId: courseInfoId,
-					name: formState.chapterName
-				})
-				.then((res) => {
-					console.log(res, '章节添加')
-					getList()
-				})
-				.catch((err) => {
-					console.log(err)
-				})
-			formState.chapterName = '' // 清空表单
-			modalVisible.value = false // 关闭模态框
-		}
+		formRef.value.validate().then(() => {
+			let courseInfoId = props.courseInfoId
+			if (formState.chapterName && modeTag.value == 'add') {
+				courseProductionApi
+					.add({
+						courseId: courseInfoId,
+						name: formState.chapterName,
+						knowledgeIds: formState.knowledgeIds
+					})
+					.then((res) => {
+						getList()
+					})
+					.catch((err) => {
+						console.log(err)
+					})
+				formState.chapterName = '' // 清空表单
+				modalVisible.value = false // 关闭模态框
+			}
+			if (formState.chapterName && modeTag.value == 'edit') {
+				courseProductionApi
+					.edit({
+						id: formState.id,
+						courseId: courseInfoId,
+						name: formState.chapterName,
+						knowledgeIds: formState.knowledgeIds
+					})
+					.then((res) => {
+						getList()
+					})
+					.catch((err) => {
+						console.log(err)
+					})
+				formState.chapterName = '' // 清空表单
+				modalVisible.value = false // 关闭模态框
+			}
+		})
 	}
 
 	// 取消按钮点击事件
@@ -182,8 +204,12 @@
 		modalVisible.value = true
 		dialogTitle.value = '修改章节'
 		modeTag.value = 'edit'
+
+		formRef.value.resetFields()
+
 		formState.id = item.id
 		formState.chapterName = item.name
+		formState.knowledgeIds = item.knowledeges
 	}
 
 	// 编辑课时
@@ -191,7 +217,6 @@
 		// 实现编辑逻辑
 	}
 	const delChapter = (chapterIndex) => {
-		console.log('删除', chapterIndex)
 		// 实现编辑逻辑
 		let item = chapters.value[chapterIndex]
 		popoverVisible.value[chapterIndex] = false
@@ -199,7 +224,6 @@
 		courseProductionApi
 			.delete([{ id: item.id }])
 			.then((res) => {
-				console.log('章节列表', res)
 				getList()
 			})
 			.catch((err) => {
@@ -211,7 +235,6 @@
 		courseProductionApi
 			.allList({ courseId: props.courseInfoId })
 			.then((res) => {
-				console.log('章节列表', res)
 				chapters.value = res.data
 			})
 			.catch((err) => {
@@ -232,7 +255,6 @@
 	}
 	// 显示课时模态框
 	const onAddClassHoursOk = (data) => {
-		console.log(data, 'onAddClassHoursOk')
 		// addLessonModalVisible.value = true
 	}
 	const onAddChapter = () => {
@@ -244,11 +266,9 @@
 			if (newVal) {
 				getList()
 			}
-		},
-		{ deep: true }
+		}
 	)
 	// onMounted(() => {
-	// 	console.log('有没有id呢', props.courseInfoId)
 	// 	getList()
 	// })
 </script>

+ 21 - 20
src/views/courseAdd/index.vue

@@ -2,7 +2,6 @@
 	<div style="overflow-y: auto">
 		<!-- <img :src="images" style="width: 100%; height: 100%" /> -->
 		<div>
-			-{{ courseInfoId }}-
 			<a-tabs v-model:activeKey="activeKey" type="card">
 				<a-tab-pane key="1" tab="教室信息">
 					<courseInfo :courseInfoId="courseInfoId" @nextStep="nextStep" />
@@ -10,9 +9,9 @@
 				<a-tab-pane key="2" tab="课程制作" :disabled="courseInfoId == null">
 					<courseProduction :courseInfoId="courseInfoId" />
 				</a-tab-pane>
-				<a-tab-pane key="3" tab="学员管理" :disabled="courseInfoId == null">
+				<!-- <a-tab-pane key="3" tab="学员管理" :disabled="courseInfoId == null">
 					<StudentDetails :courseInfoId="courseInfoId"></StudentDetails>
-				</a-tab-pane>
+				</a-tab-pane> -->
 				<!--					<a-tab-pane key="4" tab="作业布置" :disabled="courseInfoId==null">-->
 				<!--						<div>这里是作业布置的内容</div>-->
 				<!--					</a-tab-pane>-->
@@ -25,36 +24,38 @@
 </template>
 
 <script setup>
-	import { ref, computed } from 'vue'
-	import Header from '@/views/portal/components/Header.vue'
-	import Footer from '@/views/portal/components/Footer.vue'
+	import { ref, computed, watch } from 'vue'
 	import courseInfo from './components/courseInfo.vue'
 	import courseProduction from './components/courseProduction/index.vue'
 	import StudentDetails from './components/StudentDetails.vue'
-	import { useRoute, useRouter } from 'vue-router'
-	const router = useRouter()
-	const route = useRoute()
 	const activeKey = ref('1') // 默认选中的标签页
-	// const courseInfoId = ref(route.query.id || null) // 编辑课程信息id
 	const props = defineProps({
 		courseInfoId: {
 			type: String,
 			default: null
 		}
 	})
-	const courseInfoId = computed(() => {
-		console.log('courseInfoId===', props.courseInfoId)
-		return props.courseInfoId
-	})
+
+	// 使用本地ref来存储courseInfoId,初始值从props获取
+	const localCourseInfoId = ref(props.courseInfoId || null)
+
+	// 监听props变化,更新本地状态
+	watch(
+		() => props.courseInfoId,
+		(newVal) => {
+			localCourseInfoId.value = newVal || null
+		},
+		{ immediate: true }
+	)
+
+	// 对外暴露的courseInfoId
+	const courseInfoId = computed(() => localCourseInfoId.value)
+
 	const nextStep = (id) => {
-		courseInfoId.value = id
+		console.log('nextStep', id)
+		localCourseInfoId.value = id
 		activeKey.value = '2'
 	}
-	const onChangeCurrent = (current) => {
-		router.push({
-			path: '/' + current
-		})
-	}
 	// onMounted(() => {
 	// })
 </script>

+ 23 - 24
src/views/courseManagement/components/ListView.vue

@@ -45,8 +45,21 @@
 					<!--					<a-button size="small" style="margin-right: 5px">选择</a-button>-->
 					<a-button v-if="record.putawayStatus == 0" size="small" style="margin-right: 5px">上架</a-button>
 				</a-popover>
-
-				<a-button size="small" @click="handleDelete(record)" style="margin-right: 5px">删除</a-button>
+				<a-popover v-model:visible="popoverDelVisibles[record.courseId]" title="确定删除?" trigger="click">
+					<template #content>
+						<a-button style="margin-right: 10px" type="primary" @click="handleDelete(record)">确定 </a-button>
+						<a-button
+							@click="
+								() => {
+									popoverDelVisibles[record.courseId] = false
+								}
+							"
+							>取消</a-button
+						>
+					</template>
+					<!--					<a-button size="small" style="margin-right: 5px">选择</a-button>-->
+					<a-button size="small" style="margin-right: 5px">删除</a-button>
+				</a-popover>
 			</template>
 		</template>
 	</a-table>
@@ -64,18 +77,14 @@
 <script setup>
 	import tool from '@/utils/tool'
 	import { ref, onMounted } from 'vue'
-	import { EyeOutlined, EditOutlined, SnippetsOutlined, DeleteOutlined } from '@ant-design/icons-vue'
-	import { list, copy } from '@/api/courseinfo'
+	import { list, copy, deletes } from '@/api/courseinfo'
 	import { useRouter } from 'vue-router'
-	import collegeApi from '@/api/college'
 	import { updateCourseStatus } from '@/api/course/courseDetail'
 
 	const router = useRouter()
 
 	const emit = defineEmits(['handleEdit', 'handleDetail'])
-	//发布按钮状态
-	const releaseVisible = ref(false)
-	const loading = ref(false) // 列表loading
+	const popoverDelVisibles = ref({})
 	const dataSources = ref([])
 	const popoverVisible = ref({})
 	const popoverVisibles = ref({})
@@ -87,8 +96,7 @@
 		{
 			title: '课程名称',
 			dataIndex: 'courseName',
-			sorter: true,
-			width: '15%'
+			sorter: true
 		},
 		{
 			title: '状态',
@@ -124,7 +132,7 @@
 			title: '操作',
 			dataIndex: 'action',
 			sorter: true,
-			width: '20%'
+			width: '285px'
 		}
 	]
 	// tool.formatTimestamp()
@@ -143,14 +151,12 @@
 		})
 	}
 	const handlerChange = (page, pageSize) => {
-		console.log('分页参数', page, pageSize)
 		// pagination.value.size = pageSize
 		// pagination.value.current = page
 
 		getList()
 	}
 	const handleDetail = (record) => {
-		console.log('查看详情', record)
 		// router.push({
 		// 	path: '/portal/courseDetails',
 		// 	query: {
@@ -162,13 +168,11 @@
 
 	// 编辑按钮点击事件
 	const handleEdit = (record) => {
-		console.log('编辑记录', record)
 		// 在这里添加编辑记录的逻辑
 
 		emit('handleEdit', record)
 	}
 	const handleCopy = (record) => {
-		console.log('拷贝记录', record)
 		// 在这里添加编辑记录的逻辑
 		copy({ courseId: record.courseId }).then((res) => {
 			if (res.code == 200) {
@@ -180,7 +184,6 @@
 
 	// 上架按钮点击事件
 	const handleShelf = (record, num) => {
-		console.log('上架记录', record)
 		popoverVisible.value[record.courseId] = false
 		popoverVisibles.value[record.courseId] = false
 		// 在这里添加上架记录的逻辑
@@ -195,8 +198,10 @@
 
 	// 删除按钮点击事件
 	const handleDelete = (record) => {
-		console.log('删除记录', record)
-		// 在这里添加删除记录的逻辑
+		popoverDelVisibles.value[record.courseId] = false
+		deletes([{ courseId: record.courseId }]).then(() => {
+			getList()
+		})
 	}
 	const getList = () => {
 		list({ ...pagination.value }).then((data) => {
@@ -211,12 +216,6 @@
 		})
 	}
 	const setList = (search) => {
-		console.log('获取列表 setList', search)
-		// courseName: '',
-		// 	collegeId: '',
-		// 	majorId: '',
-		// 	courseType: '',
-		// 	loacl: []
 		formState.value = search
 		pagination.value.current = 1
 		list({ ...pagination.value, ...formState.value }).then((data) => {