Parcourir la source

课程管理新增部分页面开发联调

zhangsq il y a 7 mois
Parent
commit
cfbfada4ac

+ 1 - 0
package.json

@@ -34,6 +34,7 @@
 		"@vue-office/docx": "^1.2.0",
 		"@vue-office/docx": "^1.2.0",
 		"@vue-office/excel": "1.2.0",
 		"@vue-office/excel": "1.2.0",
 		"@vue-office/pdf": "1.2.0",
 		"@vue-office/pdf": "1.2.0",
+		"@vueup/vue-quill": "^1.2.0",
 		"ant-design-vue": "3.2.14",
 		"ant-design-vue": "3.2.14",
 		"axios": "1.1.3",
 		"axios": "1.1.3",
 		"codemirror": "^6.0.2",
 		"codemirror": "^6.0.2",

+ 22 - 0
src/api/courseCenter/courseinfo.js

@@ -0,0 +1,22 @@
+import { baseRequest } from '@/utils/newRequest'
+
+const request = (url, ...arg) => baseRequest(`/api/webapp/` + url, ...arg)
+
+export default {
+	// 获取授课教师下拉
+	lecturerList(data) {
+		return request('sys/user/allList', data, 'get')
+	},
+	// 课程信息添加
+	add(data) {
+		return request('disk/courseinfo/add', data, 'post')
+	},
+	// 课程信息编辑
+	edit(data) {
+		return request('disk/courseinfo/edit', data, 'post')
+	},
+	// 获取课程信息详情
+	detail(data) {
+		return request('disk/courseinfo/detail', data, 'get')
+	}
+}

+ 5 - 0
src/router/portal.js

@@ -62,6 +62,11 @@ const portal = [
 				name: 'portal.courseDetails',
 				name: 'portal.courseDetails',
 				path: '/portal/courseDetails',
 				path: '/portal/courseDetails',
 				component: () => import('@/views/courseDetails/index.vue')
 				component: () => import('@/views/courseDetails/index.vue')
+			},
+			{
+				name: 'portal.courseAdd',
+				path: '/portal/courseAdd',
+				component: () => import('@/views/courseAdd/index.vue')
 			}
 			}
 		]
 		]
 	},
 	},

+ 4 - 0
src/router/whiteList.js

@@ -43,6 +43,10 @@ const constRouters = [
 		path: '/portal/courseDetails',
 		path: '/portal/courseDetails',
 		component: () => import('@/views/courseDetails/index.vue')
 		component: () => import('@/views/courseDetails/index.vue')
 	},
 	},
+	{
+		path: '/portal/courseAdd',
+		component: () => import('@/views/courseAdd/index.vue')
+	},
 	{
 	{
 		path: '/other',
 		path: '/other',
 		name: 'other',
 		name: 'other',

+ 274 - 0
src/views/courseAdd/components/courseInfo.vue

@@ -0,0 +1,274 @@
+<template>
+	<a-form
+		:model="formState"
+		:rules="rules"
+		ref="formRef"
+		layout="horizontal"
+		:label-col="{ span: 2 }"
+		:wrapper-col="{ span: 12 }"
+	>
+		<a-form-item label="教室名称" name="courseName">
+			<a-input v-model:value="formState.courseName" placeholder="输入教室名称" />
+		</a-form-item>
+
+		<a-form-item label="授课教师" name="teacherId">
+			<a-select
+				v-model:value="formState.teacherId"
+				:fieldNames="{ label: 'name', value: 'id' }"
+				:options="teacherOptions"
+				placeholder="请选择授课教师"
+			/>
+		</a-form-item>
+
+		<a-form-item label="课程分类" name="courseType">
+			<a-select v-model:value="formState.courseType" :options="courseClass" placeholder="选择课程分类" />
+		</a-form-item>
+
+		<a-form-item label="上传封面" name="coverImageId">
+			<coverUpload
+				:coverImageId="formState.coverImageId"
+				:imageUrl="coverImagePath"
+				@handleChangeCover="handleChangeCover"
+				@handleRemoveCover="handleRemoveCover"
+			></coverUpload>
+		</a-form-item>
+		<a-form-item label="教室描述" name="courseDesc">
+			<quill-editor v-model:content="formState.courseDesc" contentType="html" theme="snow" />
+		</a-form-item>
+		<a-form-item label="院系" name="collegeId">
+			<a-cascader
+				v-model:value="majorIdName"
+				:options="collegeMajorOptions"
+				:fieldNames="{ label: 'name', value: 'id', children: 'children' }"
+				placeholder="请选择院系"
+				changeOnSelect
+				@change="changeCollegeMajor"
+			/>
+		</a-form-item>
+		<a-form-item label="专业" name="majorId">
+			<a-select
+				v-model:value="formState.majorId"
+				:fieldNames="{ label: 'majorName', value: 'majorCode' }"
+				:options="majorOptions"
+				placeholder="请选择专业"
+			/>
+		</a-form-item>
+		<a-form-item :wrapper-col="{ offset: 5, span: 12 }">
+			<a-button
+				type="primary"
+				v-if="!courseInfoId"
+				style="margin-right: 10px"
+				@click="() => formRef.validate().then(handleSubmit)"
+				>提交</a-button
+			>
+			<a-button type="primary" v-if="courseInfoId" @click="() => formRef.validate().then(handleEdit)"
+				>编辑提交</a-button
+			>
+		</a-form-item>
+	</a-form>
+</template>
+
+<script setup>
+	import { reactive, ref, onMounted } from 'vue'
+	import { LoadingOutlined, PlusOutlined } from '@ant-design/icons-vue'
+	import { QuillEditor } from '@vueup/vue-quill'
+	import '@vueup/vue-quill/dist/vue-quill.snow.css'
+	import resourceAuditApi from '@/api/resourceAudit.js'
+	import courseCenterApi from '@/api/courseCenter/courseinfo.js'
+	import coverUpload from '@/views/myResources/coverUpload/index.vue'
+	const emit = defineEmits(['nextStep'])
+	import tool from '@/utils/tool'
+	const props = defineProps({
+		//课程id
+		courseInfoId: {
+			type: Number,
+			required: true,
+			default: null
+		}
+	})
+	const formState = reactive({
+		courseName: null,
+		teacherId: null,
+		courseType: null,
+		courseDesc: null,
+		collegeId: null, //院校一级id
+		collegeTwoId: null, //院校二级id
+		collegeThreeId: null, //院校三级id
+		majorId: '1', //专业
+		coverImageId: null //封面id
+	})
+	const rules = {
+		courseName: [{ required: true, message: '请输入教室名称', trigger: 'blur' }],
+		teacherId: [{ required: true, message: '请选择授课教师', trigger: 'change' }],
+		courseType: [{ required: true, message: '请选择课程分类', trigger: 'change' }],
+		courseDesc: [{ required: true, message: '请输入教室描述', trigger: 'change' }],
+		collegeId: [{ required: true, message: '请选择院系', trigger: 'change' }],
+		majorId: [{ required: true, message: '请选择专业', trigger: 'change' }],
+		coverImageId: [{ required: true, message: '请上传封面', trigger: 'change' }]
+	}
+	const loading = ref(false)
+	const formRef = ref(null)
+	const courseInfoId = ref(null) //课程表单添加成功id
+	const collegeMajorOptions = ref([]) //院系
+	const majorIdName = ref([]) //院系回显
+	const majorOptions = ref([]) //专业
+	const courseOptions = ref([]) //课程
+	const teacherOptions = ref([]) //教师
+	const coverImagePath = ref() // 预览回显
+	const courseClass = tool.dictList('COURSE_TYPE')
+
+	const handleSubmit = () => {
+		console.log('表单数据:', formState)
+		// 这里添加实际提交逻辑,例如:
+		// let params = {
+		// 	current: pagination.pageNum,
+		// 	size: pagination.pageSize,
+		// 	verifyStatus: formState.verifyStatus,
+		// 	fileName: formState.fileName
+		// }
+		courseCenterApi
+			.add(formState)
+			.then((res) => {
+				console.log(res.data, '表单添加')
+				courseInfoId.value = res.data.courseId
+				emit('nextStep')
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	const handleEdit = () => {
+		console.log('表单编辑数据:', formState)
+		courseCenterApi
+			.edit({ ...formState, courseId: courseInfoId.value })
+			.then((res) => {
+				console.log(res.data, '表单添加')
+				courseInfoId.value = res.data.courseId
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	// 封面文件id
+	const handleChangeCover = (fileId) => {
+		formState.coverImageId = fileId
+	}
+
+	// 移除封面文件
+	const handleRemoveCover = () => {
+		formState.coverImageId = null
+	}
+	//获取教师人员
+	const getlecturerListSelector = () => {
+		courseCenterApi
+			.lecturerList()
+			.then((res) => {
+				console.log(res.data, '获取教师下拉数据')
+				teacherOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	//院系组织查询
+	const getOrgTreeSelector = () => {
+		resourceAuditApi
+			.orgTreeSelector()
+			.then((res) => {
+				console.log(res.data, '获取组织树选择器')
+				collegeMajorOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	const changeCollegeMajor = (value, selectedOptions) => {
+		console.log('Selected:', value, selectedOptions)
+		if (!value) {
+			majorIdName.value = ''
+			return false
+		}
+		majorIdName.value = selectedOptions.map((it) => it.name).join('/')
+		formState.collegeId = value[0] || null
+		formState.collegeTwoId = value[1] || null
+		formState.collegeThreeId = value[2] || null
+		if (selectedOptions.length) {
+			// 获取选中的最后一级
+			const lastSelected = selectedOptions[selectedOptions.length - 1]
+			// formState.selectedCollegeMajor = {
+			// 	id: lastSelected.id,
+			// 	name: lastSelected.name,
+			// 	fullPath: selectedOptions.map((opt) => opt.name).join(' / ')
+			// }
+			console.log(lastSelected, '最后一级id')
+			getCollegeMajor(lastSelected.id)
+		}
+	}
+	const getCollegeMajor = (id) => {
+		resourceAuditApi
+			.zyselect({ collegeId: id })
+			.then((res) => {
+				console.log(res.data, '专业下拉数据')
+				majorOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	//获取课程下拉
+	const getCourseAllList = () => {
+		resourceAuditApi
+			.courseAllList()
+			.then((res) => {
+				console.log(res.data, '获取全部课程')
+				courseOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+	// 获取课程信息
+	const getDetail = () => {
+		courseCenterApi.detail({ id: props.courseInfoId }).then((res) => {
+			console.log(res.data, '课程信息详情')
+			formState.courseName = res.data.courseName
+			formState.teacherId = res.data.teacherId
+			majorIdName.value = res.data.collegeAllId?.split(',')
+			getCollegeMajor(majorIdName.value[majorIdName.value.length - 1])
+			formState.courseType = res.data.courseType
+			formState.courseDesc = res.data.courseDesc
+			formState.coverImageId = res.data.coverImageId
+			formState.majorId = res.data.majorId
+		})
+	}
+
+	onMounted(() => {
+		getOrgTreeSelector()
+		getCourseAllList()
+		getlecturerListSelector()
+		if (props.courseInfoId) {
+			getDetail()
+		}
+	})
+</script>
+
+<style scoped>
+	.avatar-uploader > .ant-upload {
+		width: 128px;
+		height: 128px;
+	}
+	.ant-upload-select-picture-card i {
+		font-size: 32px;
+		color: #999;
+	}
+
+	.ant-upload-select-picture-card .ant-upload-text {
+		margin-top: 8px;
+		color: #666;
+	}
+
+	/* 调整表单间距 */
+	.ant-form-item {
+		margin-bottom: 16px;
+	}
+</style>

+ 256 - 0
src/views/courseAdd/components/courseProduction/addClassHours.vue

@@ -0,0 +1,256 @@
+<template>
+	<a-modal
+		v-model:visible="modalVisible"
+		title="添加课时"
+		:footer="null"
+		width="700px"
+		@cancel="handleCancel"
+		class="add-class-hours-modal"
+	>
+		<a-form :model="form" :rules="rules" ref="formRef" layout="vertical">
+			<a-form-item label="课时名称:" name="title" required>
+				<a-input v-model:value="form.title" placeholder="输入内容" />
+			</a-form-item>
+			<a-form-item label="选择视频:" required>
+				<div class="video-select-row">
+					<a-select v-model:value="form.video" style="width: 220px; margin-right: 12px" placeholder="选择已有资源">
+						<a-select-option v-for="item in videoList" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
+					</a-select>
+					<a-upload :show-upload-list="false" :before-upload="beforeUploadVideo" :custom-request="dummyRequest">
+						<a-button type="primary">上传新资源</a-button>
+					</a-upload>
+				</div>
+			</a-form-item>
+			<a-form-item label="上传封面:" required>
+				<div class="cover-upload-row">
+					<a-upload
+						:show-upload-list="false"
+						:before-upload="beforeUploadImg"
+						:custom-request="dummyRequest"
+						accept=".jpg,.png"
+					>
+						<div class="cover-upload-box">
+							<img v-if="form.coverUrl" :src="form.coverUrl" class="cover-img" />
+							<div v-else class="cover-placeholder">
+								<PictureOutlined style="font-size: 32px; color: #bbb" />
+							</div>
+						</div>
+					</a-upload>
+					<div class="cover-tip">支持jpg、png等格式文件上传,文件大小不超过10MB</div>
+				</div>
+			</a-form-item>
+			<a-form-item label="上传讲义:">
+				<a-upload
+					:show-upload-list="false"
+					:before-upload="beforeUploadDoc"
+					:custom-request="dummyRequest"
+					accept=".ppt,.pptx,.doc,.docx,.pdf"
+				>
+					<a-button><CloudUploadOutlined /> 上传文件</a-button>
+				</a-upload>
+				<span class="upload-tip">支持ppt、word等格式文件上传,文件大小不超过10MB</span>
+			</a-form-item>
+			<a-form-item label="上传字幕:">
+				<a-upload
+					:show-upload-list="false"
+					:before-upload="beforeUploadSrt"
+					:custom-request="dummyRequest"
+					accept=".srt"
+				>
+					<a-button><CloudUploadOutlined /> 上传文件</a-button>
+				</a-upload>
+				<span class="upload-tip">仅支持srt格式文件上传,文件大小不超过1MB</span>
+			</a-form-item>
+			<div class="footer-btns">
+				<a-button @click="handleCancel">取消</a-button>
+				<a-button type="primary" @click="handleOk">确定</a-button>
+			</div>
+		</a-form>
+	</a-modal>
+</template>
+
+<script setup>
+	import { ref, reactive, watch, defineProps, defineEmits } from 'vue'
+	import { message } from 'ant-design-vue'
+	import { PictureOutlined, CloudUploadOutlined } from '@ant-design/icons-vue'
+
+	const props = defineProps({
+		visible: Boolean
+	})
+	const emit = defineEmits(['update:visible', 'ok'])
+
+	const modalVisible = ref(props.visible)
+	watch(
+		() => props.visible,
+		(v) => {
+			modalVisible.value = v
+		}
+	)
+	watch(modalVisible, (v) => {
+		emit('update:visible', v)
+	})
+
+	const formRef = ref()
+	const form = reactive({
+		title: '',
+		video: '',
+		coverUrl: '',
+		docUrl: '',
+		srtUrl: ''
+	})
+
+	const rules = {
+		title: [{ required: true, message: '请输入课时名称' }],
+		video: [{ required: true, message: '请选择或上传视频' }],
+		coverUrl: [{ required: true, message: '请上传封面' }]
+	}
+
+	// mock视频资源
+	const videoList = ref([
+		{ id: 'v1', name: '示例视频1.mp4' },
+		{ id: 'v2', name: '示例视频2.mp4' }
+	])
+
+	function beforeUploadImg(file) {
+		const isImg = file.type === 'image/jpeg' || file.type === 'image/png'
+		const isLt10M = file.size / 1024 / 1024 < 10
+		if (!isImg) {
+			message.error('只能上传jpg/png图片')
+			return false
+		}
+		if (!isLt10M) {
+			message.error('图片不能超过10MB')
+			return false
+		}
+		// mock上传
+		const reader = new FileReader()
+		reader.onload = (e) => {
+			form.coverUrl = e.target.result
+		}
+		reader.readAsDataURL(file)
+		return false
+	}
+	function beforeUploadVideo(file) {
+		// 这里只做类型和大小校验,mock上传
+		const isVideo = file.type.startsWith('video/')
+		const isLt500M = file.size / 1024 / 1024 < 500
+		if (!isVideo) {
+			message.error('只能上传视频文件')
+			return false
+		}
+		if (!isLt500M) {
+			message.error('视频不能超过500MB')
+			return false
+		}
+		// mock添加到下拉
+		videoList.value.push({ id: 'mock_' + Date.now(), name: file.name })
+		form.video = videoList.value[videoList.value.length - 1].id
+		return false
+	}
+	function beforeUploadDoc(file) {
+		const isDoc = /\.(ppt|pptx|doc|docx|pdf)$/i.test(file.name)
+		const isLt10M = file.size / 1024 / 1024 < 10
+		if (!isDoc) {
+			message.error('仅支持ppt、word、pdf格式')
+			return false
+		}
+		if (!isLt10M) {
+			message.error('文件不能超过10MB')
+			return false
+		}
+		form.docUrl = file.name
+		return false
+	}
+	function beforeUploadSrt(file) {
+		const isSrt = file.name.endsWith('.srt')
+		const isLt1M = file.size / 1024 / 1024 < 1
+		if (!isSrt) {
+			message.error('仅支持srt格式')
+			return false
+		}
+		if (!isLt1M) {
+			message.error('文件不能超过1MB')
+			return false
+		}
+		form.srtUrl = file.name
+		return false
+	}
+	function dummyRequest({ onSuccess }) {
+		setTimeout(() => {
+			onSuccess && onSuccess()
+		}, 500)
+	}
+	function handleOk() {
+		formRef.value.validate().then(() => {
+			emit('ok', { ...form })
+			modalVisible.value = false
+		})
+	}
+	function handleCancel() {
+		modalVisible.value = false
+	}
+</script>
+
+<style lang="less" scoped>
+	.add-class-hours-modal {
+		.ant-modal-content {
+			border-radius: 10px;
+		}
+		.ant-modal-header {
+			border-radius: 10px 10px 0 0;
+		}
+		.ant-form-item {
+			margin-bottom: 24px;
+		}
+		.video-select-row {
+			display: flex;
+			align-items: center;
+		}
+		.cover-upload-row {
+			display: flex;
+			align-items: center;
+			.cover-upload-box {
+				width: 120px;
+				height: 120px;
+				background: #f7f8fa;
+				border-radius: 8px;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 24px;
+				border: 1px dashed #d9d9d9;
+				cursor: pointer;
+				.cover-img {
+					width: 100%;
+					height: 100%;
+					object-fit: cover;
+					border-radius: 8px;
+				}
+				.cover-placeholder {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 100%;
+					height: 100%;
+					color: #bbb;
+					font-size: 32px;
+				}
+			}
+			.cover-tip {
+				color: #888;
+				font-size: 13px;
+			}
+		}
+		.upload-tip {
+			color: #888;
+			font-size: 13px;
+			margin-left: 12px;
+		}
+		.footer-btns {
+			display: flex;
+			justify-content: flex-end;
+			gap: 16px;
+			margin-top: 24px;
+		}
+	}
+</style>

+ 255 - 0
src/views/courseAdd/components/courseProduction/index.vue

@@ -0,0 +1,255 @@
+<template>
+	<div class="course-chapter">
+		<!-- 添加章节按钮 -->
+		<a-button type="primary" class="add-chapter-btn" @click="showModal">添加章节</a-button>
+
+		<!-- 章节列表 -->
+		<div v-for="(chapter, chapterIndex) in chapters" :key="chapterIndex" class="chapter">
+			<!-- 章节标题 -->
+			<div class="chapter-title">
+				<span>{{ chapter.title }}</span>
+				<a-icon type="edit" @click="editChapter(chapterIndex)" />
+			</div>
+
+			<!-- 添加课时按钮 -->
+			<a-button class="add-chapter-btn1" type="primary" size="small" @click="showAddLessonModal(chapterIndex)">
+				<PlusOutlined /> 添加课时</a-button
+			>
+			<!-- 课时列表 -->
+			<div v-for="(lesson, lessonIndex) in chapter.lessons" :key="lessonIndex" class="lesson">
+				<a-row :gutter="48">
+					<a-col :span="4">
+						<!-- 视频封面 -->
+						<img src="@/assets/images/fileImg/gif.png" alt="Video Cover" class="video-cover" />
+					</a-col>
+					<a-col :span="16">
+						<!-- 课时信息 -->
+						<div class="lesson-info">
+							<div class="lesson-title">{{ lesson.title }}</div>
+							<div class="lesson-details">
+								<span>视频大小:{{ lesson.size }}MB</span>
+								<span>发布时间:{{ lesson.publishTime }}</span>
+								<span>发布人:{{ lesson.publisher }}</span>
+							</div>
+						</div>
+					</a-col>
+					<a-col :span="4">
+						<!-- 编辑和删除按钮 -->
+						<div class="lesson-actions">
+							<EditOutlined class="action-icon" @click="$emit('edit-lesson', lesson)" />
+							<DeleteOutlined class="action-icon" @click="$emit('delete-lesson', lesson)" />
+						</div>
+					</a-col>
+				</a-row>
+			</div>
+		</div>
+		<!-- 添加章节模态框 -->
+		<a-modal v-model:visible="modalVisible" title="添加章节" @ok="handleOk" @cancel="handleCancel">
+			<a-form :model="formState">
+				<a-form-item label="章节名称">
+					<a-input v-model:value="formState.chapterName" placeholder="请输入章节名称" />
+				</a-form-item>
+			</a-form>
+		</a-modal>
+		<!-- 添加课时模态框 -->
+		<addClassHours v-model:visible="addLessonModalVisible" @ok="onAddClassHoursOk" />
+	</div>
+</template>
+
+<script setup>
+	import { ref } from 'vue'
+	import addClassHours from './addClassHours.vue'
+	const addLessonModalVisible = ref(false)
+	// 章节数据
+	const chapters = ref([
+		{
+			title: '第一章 课程导学',
+			lessons: [
+				{
+					title: '1-1 课程简介',
+					size: 300,
+					publishTime: '2025-07-01 10:23:59',
+					publisher: '张三'
+				},
+				{
+					title: '1-2 课程前瞻',
+					size: 300,
+					publishTime: '2025-07-01 10:23:59',
+					publisher: '张三'
+				}
+			]
+		},
+		{
+			title: '第二章 课程XX',
+			lessons: [
+				{
+					title: '2-1 课时标题',
+					size: 300,
+					publishTime: '2025-07-01 10:23:59',
+					publisher: '张三'
+				},
+				{
+					title: '2-2 课时标题',
+					size: 300,
+					publishTime: '2025-07-01 10:23:59',
+					publisher: '张三'
+				},
+				{
+					title: '2-3 课时标题',
+					size: 300,
+					publishTime: '2025-07-01 10:23:59',
+					publisher: '张三'
+				}
+			]
+		}
+	])
+	// 模态框显示状态
+	const modalVisible = ref(false)
+	const currentChapterIndex = ref(null)
+	// 表单状态
+	const formState = ref({
+		chapterName: ''
+	})
+	// 显示模态框
+	const showModal = () => {
+		modalVisible.value = true
+	}
+
+	// 确认按钮点击事件
+	const handleOk = () => {
+		if (formState.value.chapterName) {
+			chapters.value.push({
+				title: formState.value.chapterName,
+				lessons: []
+			})
+			formState.value.chapterName = '' // 清空表单
+			modalVisible.value = false // 关闭模态框
+		}
+	}
+
+	// 取消按钮点击事件
+	const handleCancel = () => {
+		formState.value.chapterName = '' // 清空表单
+		modalVisible.value = false // 关闭模态框
+	}
+	// 编辑章节
+	const editChapter = (chapterIndex) => {
+		// 实现编辑逻辑
+	}
+
+	// 编辑课时
+	const editLesson = (chapterIndex, lessonIndex) => {
+		// 实现编辑逻辑
+	}
+
+	// 删除课时
+	const deleteLesson = (chapterIndex, lessonIndex) => {
+		chapters.value[chapterIndex].lessons.splice(lessonIndex, 1)
+	}
+	// 显示课时模态框
+	const showAddLessonModal = (chapterIndex) => {
+		currentChapterIndex.value = chapterIndex
+		addLessonModalVisible.value = true
+	}
+	// 显示课时模态框
+	const onAddClassHoursOk = (data) => {
+		console.log(data, 'onAddClassHoursOk')
+		// addLessonModalVisible.value = true
+	}
+</script>
+
+<style scoped>
+	.chapter {
+		width: 80%;
+	}
+	.course-chapter {
+		padding: 20px;
+	}
+
+	.chapter-title {
+		background: #f0f0f0;
+		padding: 10px;
+		margin-bottom: 10px;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+	}
+
+	.lesson {
+		width: 100%;
+		height: 120px;
+		display: flex;
+		align-items: center;
+		background: #f7f8fa;
+		border-radius: 8px;
+		margin-bottom: 16px;
+		padding: 16px 4px;
+		box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.03);
+		transition: box-shadow 0.2s;
+	}
+
+	.video-cover {
+		width: 100%;
+		height: 100%;
+		object-fit: cover;
+		border-radius: 4px;
+	}
+
+	.lesson-info {
+		margin-left: 10px;
+	}
+
+	.lesson-title {
+		font-weight: bold;
+		margin-bottom: 30px;
+	}
+
+	.lesson-details {
+		display: flex;
+		flex-wrap: wrap;
+	}
+
+	.lesson-details span {
+		margin-right: 10px;
+	}
+	/* 模态框内样式 */
+	.ant-modal-content {
+		width: 400px;
+	}
+
+	.ant-modal-body {
+		padding: 20px;
+	}
+
+	.ant-form-item-label > label {
+		font-weight: normal;
+	}
+	.lesson-actions {
+		display: flex;
+		align-items: center;
+	}
+	.action-icon {
+		font-size: 18px;
+		color: #347aff;
+		margin-left: 18px;
+		cursor: pointer;
+		transition: color 0.2s;
+	}
+	.action-icon:hover {
+		color: #1d5fd6;
+	}
+	.add-chapter-btn {
+		background: #ffff;
+		border: 1px solid #347aff;
+		color: #347aff;
+		border-radius: 3px;
+		margin-bottom: 10px;
+	}
+	.add-chapter-btn1 {
+		color: #ffff;
+		border: 1px solid #347aff;
+		background: #347aff;
+		border-radius: 3px;
+		margin-bottom: 10px;
+	}
+</style>

+ 0 - 0
src/views/courseAdd/components/courseProduction/课程制作


+ 40 - 0
src/views/courseAdd/index.vue

@@ -0,0 +1,40 @@
+<template>
+	<div style="margin: 20px 500px">
+		<a-tabs v-model:activeKey="activeKey" type="card">
+			<a-tab-pane key="1" tab="教室信息">
+				<courseInfo :courseInfoId="courseInfoId" @nextStep="nextStep" />
+			</a-tab-pane>
+			<a-tab-pane key="2" tab="课程制作">
+				<courseProduction />
+			</a-tab-pane>
+			<a-tab-pane key="3" tab="学员管理">
+				<div>这里是学员管理的内容</div>
+			</a-tab-pane>
+			<a-tab-pane key="4" tab="作业布置">
+				<div>这里是作业布置的内容</div>
+			</a-tab-pane>
+			<a-tab-pane key="5" tab="测试布置">
+				<div>这里是测试布置的内容</div>
+			</a-tab-pane>
+		</a-tabs>
+	</div>
+</template>
+
+<script setup>
+	import { ref, onMounted } from 'vue'
+	import courseInfo from './components/courseInfo.vue'
+	import courseProduction from './components/courseProduction/index.vue'
+	import { useRoute, useRouter } from 'vue-router'
+	const route = useRoute()
+	const activeKey = ref('1') // 默认选中的标签页
+	const courseInfoId = ref(route.query.id || null) // 编辑课程信息id
+	const nextStep = () => {
+		activeKey.value = '2'
+	}
+	// onMounted(() => {
+	// })
+</script>
+
+<style scoped>
+	/* 自定义样式 */
+</style>

+ 10 - 10
src/views/myResources/personalResources/index.vue

@@ -123,16 +123,16 @@
 				return myResources
 				return myResources
 			case 'favorites':
 			case 'favorites':
 				return defineAsyncComponent(() => import('@/views/myFavorites/index.vue'))
 				return defineAsyncComponent(() => import('@/views/myFavorites/index.vue'))
-			case 'albums':
-				return defineAsyncComponent(() => import('@/views/myResources/personalResources/Albums.vue'))
-			case 'questionBank':
-				return defineAsyncComponent(() => import('@/views/myResources/personalResources/QuestionBank.vue'))
-			case 'classroom':
-				return defineAsyncComponent(() => import('@/views/myResources/personalResources/Classroom.vue'))
-			case 'courses':
-				return defineAsyncComponent(() => import('@/views/myResources/personalResources/Courses.vue'))
-			case 'tasks':
-				return defineAsyncComponent(() => import('@/views/myResources/personalResources/Tasks.vue'))
+			// case 'albums':
+			// 	return defineAsyncComponent(() => import('@/views/myResources/personalResources/Albums.vue'))
+			// case 'questionBank':
+			// 	return defineAsyncComponent(() => import('@/views/myResources/personalResources/QuestionBank.vue'))
+			// case 'classroom':
+			// 	return defineAsyncComponent(() => import('@/views/myResources/personalResources/Classroom.vue'))
+			// case 'courses':
+			// 	return defineAsyncComponent(() => import('@/views/myResources/personalResources/Courses.vue'))
+			// case 'tasks':
+			// 	return defineAsyncComponent(() => import('@/views/myResources/personalResources/Tasks.vue'))
 			default:
 			default:
 				return myResources
 				return myResources
 		}
 		}