Explorar el Código

feat(课程/考试): 添加题库类型支持并优化课程管理功能

- 在考试模块中添加题库类型枚举和相关API
- 移除年级和学科选择,替换为题库类型筛选
- 实现课程下架和删除功能
- 优化课程详情页的课时展示逻辑
- 统一时间格式化显示
tanshanming hace 7 meses
padre
commit
6e2ae7d6ed

+ 4 - 0
src/api/course/courseDetail.js

@@ -7,6 +7,10 @@ const request = moduleRequest(`/api/webapp/`)
 export const getCourseDetail = (p) => request('disk/courseinfo/detail', p, 'get')
 // 获取章节全部列表
 export const getChapterAllList = (p) => request('disk/chapter/allList', p, 'get')
+//课程-修改状态
+export const updateCourseStatus = (p) => request('disk/courseinfo/updateStatus', p, 'post')
+//删除课程
+export const deleteCourse = (p) => request('disk/courseinfo/delete', p, 'post')
 // 部门与成员 mock 数据
 export const mockDepartments = [
 	{

+ 6 - 1
src/store/exam.js

@@ -24,6 +24,10 @@ export const useExamStore = defineStore('exam', {
 		subjects: [],
 		// 枚举相关
 		user: {
+			bankTypeEnum: [
+				{ key: 1, value: '练习题目库' },
+				{ key: 2, value: '问卷题目库' }
+			],
 			sexEnum: [
 				{ key: 1, value: '男' },
 				{ key: 2, value: '女' }
@@ -133,7 +137,8 @@ export const useExamStore = defineStore('exam', {
 			}
 			return null
 		},
-		getLevelEnum: (state) => state.user.levelEnum
+		getLevelEnum: (state) => state.user.levelEnum,
+		getBankTypeEnum: (state) => state.user.bankTypeEnum
 	},
 	actions: {
 		async initSubject(action) {

+ 0 - 187
src/views/courseDetails/components/EditCourse.vue

@@ -1,187 +0,0 @@
-<template>
-	<a-form
-		:model="form"
-		:rules="rules"
-		ref="formRef"
-		:label-col="{ span: 5 }"
-		:wrapper-col="{ span: 18 }"
-		labelAlign="left"
-		class="edit-course-form"
-	>
-		<a-form-item label="工单标题" name="title" required>
-			<a-input v-model:value="form.title" placeholder="工单标题" />
-		</a-form-item>
-		<a-form-item label="关联客户" name="customer" required>
-			<a-select v-model:value="form.customer" placeholder="选择客户">
-				<a-select-option v-for="item in customerList" :key="item.value" :value="item.value">{{
-					item.label
-				}}</a-select-option>
-			</a-select>
-		</a-form-item>
-		<a-form-item label="产品" name="product">
-			<a-select v-model:value="form.product" placeholder="选择订单">
-				<a-select-option v-for="item in productList" :key="item.value" :value="item.value">{{
-					item.label
-				}}</a-select-option>
-			</a-select>
-		</a-form-item>
-		<a-form-item label="工单类型" name="type" required>
-			<a-select v-model:value="form.type" placeholder="选择类型">
-				<a-select-option v-for="item in typeList" :key="item.value" :value="item.value">{{
-					item.label
-				}}</a-select-option>
-			</a-select>
-		</a-form-item>
-		<a-form-item label="情况说明" name="desc">
-			<a-textarea v-model:value="form.desc" :maxlength="300" :rows="4" placeholder="请输入情况说明" show-count />
-		</a-form-item>
-		<a-form-item label="信息来源" name="source">
-			<a-select v-model:value="form.source" placeholder="选择信息来源">
-				<a-select-option v-for="item in sourceList" :key="item.value" :value="item.value">{{
-					item.label
-				}}</a-select-option>
-			</a-select>
-		</a-form-item>
-		<a-form-item label="上传附件" name="attachments">
-			<a-upload
-				v-model:file-list="form.attachments"
-				:before-upload="beforeUpload"
-				:multiple="true"
-				:list-type="picture - card"
-				:show-upload-list="{ showPreviewIcon: false }"
-				:custom-request="dummyRequest"
-				:accept="'.jpg,.png'"
-			>
-				<a-button>上传文件</a-button>
-			</a-upload>
-			<div class="upload-tip">请上传jpg、png图片附件,最多可上传4张,单张大小不要超过8M。</div>
-		</a-form-item>
-		<a-form-item label="联系人" name="contact" required>
-			<a-input v-model:value="form.contact" placeholder="联系人" />
-		</a-form-item>
-		<a-form-item label="联系电话" name="phone">
-			<a-input v-model:value="form.phone" placeholder="联系电话" />
-		</a-form-item>
-		<a-form-item label="所属区域" name="region">
-			<a-select v-model:value="form.region" placeholder="请选择">
-				<a-select-option v-for="item in regionList" :key="item.value" :value="item.value">{{
-					item.label
-				}}</a-select-option>
-			</a-select>
-		</a-form-item>
-		<a-form-item label="详细地址" name="address">
-			<a-input v-model:value="form.address" placeholder="详细地址" />
-		</a-form-item>
-		<a-form-item style="text-align: right; margin-top: 32px">
-			<a-button @click="emit('close')" style="margin-right: 16px">取消</a-button>
-			<a-button type="primary" @click="onSubmit">保存</a-button>
-		</a-form-item>
-	</a-form>
-</template>
-
-<script setup>
-	import { ref, watch } from 'vue'
-	const props = defineProps({
-		course: { type: Object, default: () => ({}) }
-	})
-	const emit = defineEmits(['close'])
-
-	const formRef = ref()
-	const form = ref({
-		title: '',
-		customer: '',
-		product: '',
-		type: '',
-		desc: '',
-		source: '',
-		attachments: [],
-		contact: '',
-		phone: '',
-		region: '',
-		address: ''
-	})
-
-	// mock 下拉数据
-	const customerList = [
-		{ label: '张三公司', value: 'zhangsan' },
-		{ label: '李四企业', value: 'lisi' }
-	]
-	const productList = [
-		{ label: '订单A', value: 'a' },
-		{ label: '订单B', value: 'b' }
-	]
-	const typeList = [
-		{ label: '售后', value: 'after' },
-		{ label: '投诉', value: 'complain' }
-	]
-	const sourceList = [
-		{ label: '电话', value: 'phone' },
-		{ label: '微信', value: 'wechat' }
-	]
-	const regionList = [
-		{ label: '浙江舟山', value: 'zhoushan' },
-		{ label: '杭州', value: 'hangzhou' }
-	]
-
-	watch(
-		() => props.course,
-		(val) => {
-			form.value = {
-				...form.value,
-				...val
-			}
-		},
-		{ deep: true, immediate: true }
-	)
-
-	// 校验规则
-	const rules = {
-		title: [{ required: true, message: '请输入工单标题' }],
-		customer: [{ required: true, message: '请选择客户' }],
-		type: [{ required: true, message: '请选择工单类型' }],
-		contact: [{ required: true, message: '请输入联系人' }]
-	}
-
-	// 附件上传限制
-	function beforeUpload(file, fileList) {
-		const isImg = file.type === 'image/jpeg' || file.type === 'image/png'
-		const isLt8M = file.size / 1024 / 1024 < 8
-		if (!isImg) {
-			window.$message?.error('只能上传jpg/png图片')
-			return false
-		}
-		if (!isLt8M) {
-			window.$message?.error('单张图片不能超过8M')
-			return false
-		}
-		if (form.value.attachments.length + fileList.length > 4) {
-			window.$message?.error('最多上传4张图片')
-			return false
-		}
-		return true
-	}
-	// mock上传
-	function dummyRequest({ onSuccess }) {
-		setTimeout(() => {
-			onSuccess && onSuccess()
-		}, 500)
-	}
-
-	function onSubmit() {
-		formRef.value.validate().then(() => {
-			console.log('保存数据', form.value)
-			emit('close')
-		})
-	}
-</script>
-
-<style lang="less" scoped>
-	.edit-course-form {
-		padding-top: 24px;
-		.upload-tip {
-			color: #888;
-			font-size: 12px;
-			margin-top: 4px;
-		}
-	}
-</style>

+ 19 - 16
src/views/courseDetails/components/tab/LessonDetails.vue

@@ -1,25 +1,24 @@
 <template>
 	<div class="section-list">
 		<div v-for="section in pagedSections" :key="section.id" class="section-block">
-			<div class="section-title">{{ section.title }}</div>
-			<div v-for="lesson in section.lessons" :key="lesson.id" class="lesson-row">
-				<div class="lesson-cover">
-					<a-avatar shape="square" :size="48" icon="play-circle" />
-				</div>
-				<div class="lesson-info">
-					<div class="lesson-title">{{ lesson.title }}</div>
-					<div class="lesson-meta">
-						<span>时长:{{ lesson.duration }}</span>
-						<span>视频大小:{{ lesson.size }}</span>
-						<span>发布时间:{{ lesson.publishTime }}</span>
-						<span>发布人:{{ lesson.author }}</span>
+			<div class="section-title">{{ section.name }}</div>
+			<div v-if="section.classHours && section.classHours.length > 0">
+				<div v-for="lesson in section.classHours" :key="lesson.id" class="lesson-row">
+					<div class="lesson-cover">
+						<a-avatar shape="square" :size="48" icon="play-circle" />
+					</div>
+					<div class="lesson-info">
+						<div class="lesson-title">{{ lesson.name }}</div>
+						<div class="lesson-meta">
+							<span>创建时间:{{ lesson.createTime }}</span>
+							<span>创建人:{{ lesson.createUserName }}</span>
+						</div>
 					</div>
-				</div>
-				<div class="lesson-actions">
-					<EditOutlined class="action-icon" @click="$emit('edit-lesson', lesson)" />
-					<DeleteOutlined class="action-icon" @click="$emit('delete-lesson', lesson)" />
 				</div>
 			</div>
+			<div v-else class="no-lessons">
+				<a-empty description="暂无课时" />
+			</div>
 		</div>
 		<!-- 分页 -->
 		<div class="pagination-box">
@@ -146,4 +145,8 @@
 	.pagination-box .ant-select {
 		min-width: 90px;
 	}
+	.no-lessons {
+		padding: 40px 0;
+		text-align: center;
+	}
 </style>

+ 75 - 5
src/views/courseDetails/index.vue

@@ -16,8 +16,8 @@
 				<div class="action-box">
 					<div class="btn-group">
 						<a-button @click="editVisible = true"> <EditOutlined /> 编辑课程</a-button>
-						<a-button> <DownOutlined /> 下架课程</a-button>
-						<a-button> <DeleteOutlined /> 删除课程</a-button>
+						<a-button @click="handleTakeOffCourse"> <DownOutlined /> 下架课程</a-button>
+						<a-button @click="handleDeleteCourse"> <DeleteOutlined /> 删除课程</a-button>
 					</div>
 					<div class="extra-box">
 						<div class="row">
@@ -65,7 +65,7 @@
 
 		<!-- 编辑课程弹窗 -->
 		<a-modal v-model:visible="editVisible" title="新建工单" :footer="null" width="700px" @cancel="editVisible = false">
-			<EditCourse :course="course" @close="editVisible = false" />
+			<CourseAdd />
 		</a-modal>
 		<!-- 编辑课时弹窗 -->
 		<AddClassHours v-model:visible="addClassHoursVisible" @ok="onAddClassHoursOk" />
@@ -75,12 +75,13 @@
 <script setup>
 	import { ref, computed, onMounted } from 'vue'
 	import { EyeOutlined, ClockCircleOutlined, EditOutlined, DeleteOutlined, DownOutlined } from '@ant-design/icons-vue'
-	import EditCourse from './components/EditCourse.vue'
+	import { message, Modal } from 'ant-design-vue'
 	import AddClassHours from './components/AddClassHours.vue'
 	import LessonDetails from './components/tab/LessonDetails.vue'
 	import StudentDetails from './components/tab/StudentDetails.vue'
 	import LearningStatistics from './components/tab/LearningStatistics.vue'
-	import { getCourseDetail } from '@/api/course/courseDetail.js'
+	import CourseAdd from '../courseAdd/index.vue'
+	import { getCourseDetail, getChapterAllList, updateCourseStatus, deleteCourse } from '@/api/course/courseDetail.js'
 	import { useRoute } from 'vue-router'
 	import sysConfig from '@/config/index'
 	const route = useRoute()
@@ -129,11 +130,19 @@
 		const params = {
 			courseId: route.query.id
 		}
+		// 获取课程基本信息
 		getCourseDetail(params).then((res) => {
 			course.value = {
 				...course.value,
 				...res.data
 			}
+
+			// 获取章节和课时信息
+			getChapterAllList(params).then((chapterRes) => {
+				if (chapterRes.data && Array.isArray(chapterRes.data)) {
+					course.value.sections = chapterRes.data
+				}
+			})
 		})
 	})
 
@@ -170,6 +179,67 @@
 		const minutes = Math.floor((diff / (1000 * 60)) % 60)
 		return `${days * 24 + hours}小时${minutes}分钟`
 	}
+
+	// 处理下架课程
+	function handleTakeOffCourse() {
+		Modal.confirm({
+			title: '确认下架课程',
+			content: `确定要下架课程"${course.value.courseName}"吗?下架后学员将无法访问该课程。`,
+			okText: '确认下架',
+			cancelText: '取消',
+			onOk: async () => {
+				try {
+					const params = {
+						courseId: course.value.courseId,
+						putawayStatus: '0' // 假设0表示下架状态
+					}
+					const res = await updateCourseStatus(params)
+					if (res.code === 200) {
+						message.success('课程下架成功')
+						// 更新课程状态
+						course.value.putawayStatus = '0'
+						course.value.putawayStatusName = '已下架'
+					} else {
+						message.error(res.msg || '操作失败')
+					}
+				} catch (error) {
+					console.error('下架课程失败:', error)
+					message.error('下架课程失败,请稍后重试')
+				}
+			}
+		})
+	}
+
+	// 处理删除课程
+	function handleDeleteCourse() {
+		Modal.confirm({
+			title: '确认删除课程',
+			content: `确定要删除课程"${course.value.courseName}"吗?删除后将无法恢复。`,
+			okText: '确认删除',
+			okType: 'danger',
+			cancelText: '取消',
+			onOk: async () => {
+				try {
+					const params = [
+						{
+							courseId: course.value.courseId
+						}
+					]
+					const res = await deleteCourse(params)
+					if (res.code === 200) {
+						message.success('课程删除成功')
+						// 删除成功后返回课程列表页
+						window.history.back()
+					} else {
+						message.error(res.msg || '删除失败')
+					}
+				} catch (error) {
+					console.error('删除课程失败:', error)
+					message.error('删除课程失败,请稍后重试')
+				}
+			}
+		})
+	}
 </script>
 
 <style lang="less" scoped>

+ 14 - 7
src/views/exm/exampaper/form.vue

@@ -8,7 +8,7 @@
 			:rules="rules"
 			:loading="formLoading"
 		>
-			<a-form-item label="年级" name="level" :rules="rules.level">
+			<!-- <a-form-item label="年级" name="level" :rules="rules.level">
 				<a-select v-model:value="form.level" placeholder="请选择年级" @change="levelChange">
 					<a-select-option v-for="item in levelEnum" :key="item.key" :value="item.key">
 						{{ item.value }}
@@ -21,7 +21,7 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
-			</a-form-item>
+			</a-form-item> -->
 			<a-form-item label="试卷类型" name="paperType" :rules="rules.paperType">
 				<a-select v-model:value="form.paperType" placeholder="请选择试卷类型">
 					<a-select-option v-for="item in paperTypeEnum" :key="item.key" :value="item.key">
@@ -90,6 +90,13 @@
 						</a-select-option>
 					</a-select>
 				</a-form-item>
+				<a-form-item label="题库类型">
+					<a-select v-model:value="questionPage.queryParam.bankType" allow-clear style="width: 120px">
+						<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">
+							{{ item.value }}
+						</a-select-option>
+					</a-select>
+				</a-form-item>
 				<a-form-item>
 					<a-button type="primary" @click="queryForm">查询</a-button>
 				</a-form-item>
@@ -126,7 +133,7 @@
 	import questionApi from '@/api/exam/question/tQuestionApi'
 	import QuestionShow from '@/views/exm/question/components/Show.vue'
 	import { message } from 'ant-design-vue'
-	import dayjs from 'dayjs'
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 	const props = defineProps({
 		id: {
 			type: Number,
@@ -139,8 +146,8 @@
 
 	const form = reactive({
 		id: null,
-		level: null,
-		subjectId: null,
+		// level: null,
+		// subjectId: null,
 		paperType: 1,
 		limitDateTime: [],
 		name: '',
@@ -267,8 +274,8 @@
 		const lastId = form.id
 		Object.assign(form, {
 			id: null,
-			level: null,
-			subjectId: null,
+			// level: null,
+			// subjectId: null,
 			paperType: 1,
 			limitDateTime: [],
 			name: '',

+ 7 - 5
src/views/exm/exampaper/index.vue

@@ -5,7 +5,7 @@
 			<a-form-item label="题目ID:">
 				<a-input v-model:value="queryParam.id" placeholder="请输入题目ID" allow-clear />
 			</a-form-item>
-			<a-form-item label="年级:">
+			<!-- <a-form-item label="年级:">
 				<a-select
 					v-model:value="queryParam.level"
 					placeholder="请选择年级"
@@ -24,7 +24,7 @@
 						{{ item.name }} ( {{ item.levelName }} )
 					</a-select-option>
 				</a-select>
-			</a-form-item>
+			</a-form-item> -->
 			<a-form-item>
 				<a-button type="primary" @click="submitForm">查询</a-button>
 				<a-button type="primary" @click="openDrawer('add')" style="margin-left: 8px">添加</a-button>
@@ -85,14 +85,15 @@
 	import { useExamStore } from '@/store/exam'
 	import examPaperApi from '@/api/exam/paper/examPaperApi'
 	import FormEdit from './form.vue'
+	import { parseTime } from '@/utils/exam'
 
 	const examStore = useExamStore()
 
 	// 响应式数据
 	const queryParam = reactive({
 		id: null,
-		level: null,
-		subjectId: null,
+		// level: null,
+		// subjectId: null,
 		current: 1,
 		size: 10
 	})
@@ -149,7 +150,8 @@
 			title: '创建时间',
 			dataIndex: 'createTime',
 			key: 'createTime',
-			width: 160
+			width: 200,
+			customRender: ({ text }) => parseTime(text, '{y}-{m}-{d} {h}:{i}:{s}')
 		},
 		{
 			title: '操作',

+ 18 - 9
src/views/exm/question/edit/gap-filling.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="app-container">
 		<a-form :model="form" ref="formRef" :rules="rules" layout="vertical">
-			<a-form-item label="年级:" name="gradeLevel" required>
+			<!-- <a-form-item label="年级:" name="gradeLevel" required>
 				<a-select v-model:value="form.gradeLevel" placeholder="年级" @change="levelChange">
 					<a-select-option v-for="item in levelEnum" :key="item.key" :value="item.key">
 						{{ item.value }}
@@ -14,6 +14,13 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
+			</a-form-item> -->
+			<a-form-item label="题库类型:" name="bankType" required>
+				<a-select v-model:value="form.bankType" placeholder="题库类型">
+					<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">
+						{{ item.value }}
+					</a-select-option>
+				</a-select>
 			</a-form-item>
 			<a-form-item label="题干:" name="title" required>
 				<a-input v-model:value="form.title" readonly @click="inputClick(form, 'title')" />
@@ -73,6 +80,7 @@
 	import tQuestionApi from '@/api/exam/question/tQuestionApi'
 	import QuestionShow from '../components/Show.vue'
 	import Editor from '@/components/Editor/index.vue'
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 
 	const examStore = useExamStore()
 	const props = defineProps({
@@ -86,18 +94,20 @@
 	const form = reactive({
 		id: null,
 		questionType: 4,
-		gradeLevel: null,
-		subjectId: null,
+		// gradeLevel: null,
+		// subjectId: null,
 		title: '',
 		items: [],
 		analyze: '',
 		correct: '',
 		score: '',
-		difficult: 0
+		difficult: 0,
+		bankType: 1
 	})
 	const subjectFilter = ref([])
 	const formLoading = ref(false)
 	const rules = {
+		bankType: [{ required: true, message: '请选择题库类型', trigger: 'change' }],
 		gradeLevel: [{ required: true, message: '请选择年级', trigger: 'change' }],
 		subjectId: [{ required: true, message: '请选择学科', trigger: 'change' }],
 		title: [{ required: true, message: '请输入题干', trigger: 'blur' }],
@@ -127,8 +137,6 @@
 		if (id && parseInt(id) !== 0) {
 			formLoading.value = true
 			tQuestionApi.select(id).then((re) => {
-				Object.assign(form, re)
-				levelChange()
 				Object.assign(form, re)
 				formLoading.value = false
 			})
@@ -215,14 +223,15 @@
 		Object.assign(form, {
 			id: null,
 			questionType: 4,
-			gradeLevel: null,
-			subjectId: null,
+			// gradeLevel: null,
+			// subjectId: null,
 			title: '',
 			items: [],
 			analyze: '',
 			correct: '',
 			score: '',
-			difficult: 0
+			difficult: 0,
+			bankType: 1
 		})
 		form.id = lastId
 	}

+ 18 - 9
src/views/exm/question/edit/multiple-choice.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="app-container">
 		<a-form :model="form" ref="formRef" :rules="rules" layout="vertical">
-			<a-form-item label="年级:" name="gradeLevel" required>
+			<!-- <a-form-item label="年级:" name="gradeLevel" required>
 				<a-select v-model:value="form.gradeLevel" placeholder="年级" @change="levelChange">
 					<a-select-option v-for="item in levelEnum" :key="item.key" :value="item.key">
 						{{ item.value }}
@@ -14,6 +14,13 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
+			</a-form-item> -->
+			<a-form-item label="题库类型:" name="bankType" required>
+				<a-select v-model:value="form.bankType" placeholder="题库类型">
+					<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">
+						{{ item.value }}
+					</a-select-option>
+				</a-select>
 			</a-form-item>
 			<a-form-item label="题干:" name="title" required>
 				<a-input v-model:value="form.title" readonly @click="inputClick(form, 'title')" />
@@ -79,6 +86,7 @@
 	import tQuestionApi from '@/api/exam/question/tQuestionApi'
 	import QuestionShow from '../components/Show.vue'
 	import Editor from '@/components/Editor/index.vue'
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 
 	const examStore = useExamStore()
 	const props = defineProps({
@@ -92,8 +100,8 @@
 	const form = reactive({
 		id: null,
 		questionType: 2,
-		gradeLevel: null,
-		subjectId: null,
+		// gradeLevel: null,
+		// subjectId: null,
 		title: '',
 		items: [
 			{ id: null, prefix: 'A', content: '' },
@@ -105,11 +113,13 @@
 		correct: '',
 		correctArray: [],
 		score: '',
-		difficult: 0
+		difficult: 0,
+		bankType: 1
 	})
 	const subjectFilter = ref([])
 	const formLoading = ref(false)
 	const rules = {
+		bankType: [{ required: true, message: '请选择题库类型', trigger: 'change' }],
 		gradeLevel: [{ required: true, message: '请选择年级', trigger: 'change' }],
 		subjectId: [{ required: true, message: '请选择学科', trigger: 'change' }],
 		title: [{ required: true, message: '请输入题干', trigger: 'blur' }],
@@ -140,8 +150,6 @@
 		if (id && parseInt(id) !== 0) {
 			formLoading.value = true
 			tQuestionApi.select(id).then((re) => {
-				Object.assign(form, re)
-				levelChange()
 				Object.assign(form, re)
 				formLoading.value = false
 			})
@@ -210,8 +218,8 @@
 		Object.assign(form, {
 			id: null,
 			questionType: 2,
-			gradeLevel: null,
-			subjectId: null,
+			// gradeLevel: null,
+			// subjectId: null,
 			title: '',
 			items: [
 				{ id: null, prefix: 'A', content: '' },
@@ -223,7 +231,8 @@
 			correct: '',
 			correctArray: [],
 			score: '',
-			difficult: 0
+			difficult: 0,
+			bankType: 1
 		})
 		form.id = lastId
 	}

+ 17 - 8
src/views/exm/question/edit/short-answer.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="app-container">
 		<a-form :model="form" ref="formRef" :rules="rules" layout="vertical">
-			<a-form-item label="年级:" name="gradeLevel" required>
+			<!-- <a-form-item label="年级:" name="gradeLevel" required>
 				<a-select v-model:value="form.gradeLevel" placeholder="年级" @change="levelChange">
 					<a-select-option v-for="item in levelEnum" :key="item.key" :value="item.key">
 						{{ item.value }}
@@ -14,6 +14,13 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
+			</a-form-item> -->
+			<a-form-item label="题库类型:" name="bankType" required>
+				<a-select v-model:value="form.bankType" placeholder="题库类型">
+					<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">
+						{{ item.value }}
+					</a-select-option>
+				</a-select>
 			</a-form-item>
 			<a-form-item label="题干:" name="title" required>
 				<a-input v-model:value="form.title" readonly @click="inputClick(form, 'title')" />
@@ -63,6 +70,7 @@
 	import tQuestionApi from '@/api/exam/question/tQuestionApi'
 	import QuestionShow from '../components/Show.vue'
 	import Editor from '@/components/Editor/index.vue'
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 
 	const examStore = useExamStore()
 	const props = defineProps({
@@ -76,18 +84,20 @@
 	const form = reactive({
 		id: null,
 		questionType: 5,
-		gradeLevel: null,
-		subjectId: null,
+		// gradeLevel: null,
+		// subjectId: null,
 		title: '',
 		items: [],
 		analyze: '',
 		correct: '',
 		score: '',
-		difficult: 0
+		difficult: 0,
+		bankType: 1
 	})
 	const subjectFilter = ref([])
 	const formLoading = ref(false)
 	const rules = {
+		bankType: [{ required: true, message: '请选择题库类型', trigger: 'change' }],
 		gradeLevel: [{ required: true, message: '请选择年级', trigger: 'change' }],
 		subjectId: [{ required: true, message: '请选择学科', trigger: 'change' }],
 		title: [{ required: true, message: '请输入题干', trigger: 'blur' }],
@@ -118,8 +128,6 @@
 		if (id && parseInt(id) !== 0) {
 			formLoading.value = true
 			tQuestionApi.select(id).then((re) => {
-				Object.assign(form, re)
-				levelChange()
 				Object.assign(form, re)
 				formLoading.value = false
 			})
@@ -161,13 +169,14 @@
 		Object.assign(form, {
 			id: null,
 			questionType: 5,
-			gradeLevel: null,
-			subjectId: null,
+			// gradeLevel: null,
+			// subjectId: null,
 			title: '',
 			items: [],
 			analyze: '',
 			correct: '',
 			score: '',
+			bankType: 1,
 			difficult: 0
 		})
 		form.id = lastId

+ 18 - 9
src/views/exm/question/edit/single-choice.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="app-container">
 		<a-form :model="form" ref="formRef" :rules="rules" layout="vertical">
-			<a-form-item label="年级:" name="gradeLevel" required>
+			<!-- <a-form-item label="年级:" name="gradeLevel" required>
 				<a-select v-model:value="form.gradeLevel" placeholder="年级" @change="levelChange">
 					<a-select-option v-for="item in levelEnum" :key="item.key" :value="item.key">
 						{{ item.value }}
@@ -14,6 +14,13 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
+			</a-form-item> -->
+			<a-form-item label="题库类型:" name="bankType" required>
+				<a-select v-model:value="form.bankType" placeholder="题库类型">
+					<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">
+						{{ item.value }}
+					</a-select-option>
+				</a-select>
 			</a-form-item>
 			<a-form-item label="题干:" name="title" required>
 				<a-input v-model:value="form.title" readonly @click="inputClick(form, 'title')" />
@@ -79,6 +86,7 @@
 	import tQuestionApi from '@/api/exam/question/tQuestionApi'
 	import QuestionShow from '../components/Show.vue'
 	import Editor from '@/components/Editor/index.vue'
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 
 	const examStore = useExamStore()
 	const props = defineProps({
@@ -92,8 +100,8 @@
 	const form = reactive({
 		id: null,
 		questionType: 1,
-		gradeLevel: null,
-		subjectId: null,
+		// gradeLevel: null,
+		// subjectId: null,
 		title: '',
 		items: [
 			{ prefix: 'A', content: '' },
@@ -104,11 +112,13 @@
 		analyze: '',
 		correct: '',
 		score: '',
-		difficult: 0
+		difficult: 0,
+		bankType: 1
 	})
 	const subjectFilter = ref([])
 	const formLoading = ref(false)
 	const rules = {
+		bankType: [{ required: true, message: '请选择题库类型', trigger: 'change' }],
 		gradeLevel: [{ required: true, message: '请选择年级', trigger: 'change' }],
 		subjectId: [{ required: true, message: '请选择学科', trigger: 'change' }],
 		title: [{ required: true, message: '请输入题干', trigger: 'blur' }],
@@ -139,8 +149,6 @@
 		if (id && parseInt(id) !== 0) {
 			formLoading.value = true
 			tQuestionApi.select(id).then((re) => {
-				Object.assign(form, re)
-				levelChange()
 				Object.assign(form, re)
 				formLoading.value = false
 			})
@@ -198,8 +206,8 @@
 		Object.assign(form, {
 			id: null,
 			questionType: 1,
-			gradeLevel: null,
-			subjectId: null,
+			// gradeLevel: null,
+			// subjectId: null,
 			title: '',
 			items: [
 				{ prefix: 'A', content: '' },
@@ -210,7 +218,8 @@
 			analyze: '',
 			correct: '',
 			score: '',
-			difficult: 0
+			difficult: 0,
+			bankType: 1
 		})
 		form.id = lastId
 	}

+ 18 - 9
src/views/exm/question/edit/true-false.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="app-container">
 		<a-form :model="form" ref="formRef" :rules="rules" layout="vertical">
-			<a-form-item label="年级:" name="gradeLevel" required>
+			<!-- <a-form-item label="年级:" name="gradeLevel" required>
 				<a-select v-model:value="form.gradeLevel" placeholder="年级" @change="levelChange">
 					<a-select-option v-for="item in levelEnum" :key="item.key" :value="item.key">
 						{{ item.value }}
@@ -14,6 +14,13 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
+			</a-form-item> -->
+			<a-form-item label="题库类型:" name="bankType" required>
+				<a-select v-model:value="form.bankType" placeholder="题库类型">
+					<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">
+						{{ item.value }}
+					</a-select-option>
+				</a-select>
 			</a-form-item>
 			<a-form-item label="题干:" name="title" required>
 				<a-input v-model:value="form.title" readonly @click="inputClick(form, 'title')" />
@@ -77,6 +84,7 @@
 	import tQuestionApi from '@/api/exam/question/tQuestionApi'
 	import QuestionShow from '../components/Show.vue'
 	import Editor from '@/components/Editor/index.vue'
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 	const examStore = useExamStore()
 	const props = defineProps({
 		id: {
@@ -89,8 +97,8 @@
 	const form = reactive({
 		id: null,
 		questionType: 3,
-		gradeLevel: null,
-		subjectId: null,
+		// gradeLevel: null,
+		// subjectId: null,
 		title: '',
 		items: [
 			{ id: null, prefix: 'A', content: '是' },
@@ -99,11 +107,13 @@
 		analyze: '',
 		correct: '',
 		score: '',
-		difficult: 0
+		difficult: 0,
+		bankType: 1
 	})
 	const subjectFilter = ref([])
 	const formLoading = ref(false)
 	const rules = {
+		bankType: [{ required: true, message: '请选择题库类型', trigger: 'change' }],
 		gradeLevel: [{ required: true, message: '请选择年级', trigger: 'change' }],
 		subjectId: [{ required: true, message: '请选择学科', trigger: 'change' }],
 		title: [{ required: true, message: '请输入题干', trigger: 'blur' }],
@@ -134,8 +144,6 @@
 		if (id && parseInt(id) !== 0) {
 			formLoading.value = true
 			tQuestionApi.select(id).then((re) => {
-				Object.assign(form, re)
-				levelChange()
 				Object.assign(form, re)
 				formLoading.value = false
 			})
@@ -177,8 +185,8 @@
 		Object.assign(form, {
 			id: null,
 			questionType: 3,
-			gradeLevel: null,
-			subjectId: null,
+			// gradeLevel: null,
+			// subjectId: null,
 			title: '',
 			items: [
 				{ id: null, prefix: 'A', content: '是' },
@@ -187,7 +195,8 @@
 			analyze: '',
 			correct: '',
 			score: '',
-			difficult: 0
+			difficult: 0,
+			bankType: 1
 		})
 		form.id = lastId
 	}

+ 13 - 5
src/views/exm/question/index.vue

@@ -7,7 +7,7 @@
 			<a-form-item label="题目内容:">
 				<a-input v-model:value="queryParam.content" allow-clear />
 			</a-form-item>
-			<a-form-item label="年级:">
+			<!-- <a-form-item label="年级:">
 				<a-select
 					v-model:value="queryParam.level"
 					placeholder="年级"
@@ -26,6 +26,13 @@
 						{{ item.name + ' ( ' + item.levelName + ' )' }}
 					</a-select-option>
 				</a-select>
+			</a-form-item> -->
+			<a-form-item label="题库类型:">
+				<a-select v-model:value="queryParam.bankType" placeholder="题库类型" allow-clear style="width: 100px">
+					<a-select-option v-for="item in bankTypeEnum" :key="item.key" :value="item.key">{{
+						item.value
+					}}</a-select-option>
+				</a-select>
 			</a-form-item>
 			<a-form-item label="题型:">
 				<a-select v-model:value="queryParam.questionType" allow-clear style="width: 100px">
@@ -150,16 +157,17 @@
 	import { StarFilled, StarOutlined } from '@ant-design/icons-vue'
 	import { Modal } from 'ant-design-vue'
 	import { parseTime } from '@/utils/exam'
-
+	const bankTypeEnum = computed(() => examStore.getBankTypeEnum)
 	const examStore = useExamStore()
 
 	const queryParam = reactive({
 		id: null,
 		questionType: null,
-		level: null,
-		subjectId: null,
+		// level: null,
+		// subjectId: null,
 		pageIndex: 1,
-		pageSize: 10
+		pageSize: 10,
+		bankType: null
 	})
 
 	const subjectFilter = ref([])

+ 5 - 6
src/views/exm/task/form.vue

@@ -94,7 +94,6 @@
 	import { useExamStore } from '@/store/exam.js'
 	import taskApi from '@/api/exam/paper/task.js'
 	import examPaperApi from '@/api/exam/paper/examPaperApi.js'
-	import { parseTime } from '@/utils/exam'
 	const emit = defineEmits(['success'])
 	const props = defineProps({
 		id: {
@@ -104,8 +103,8 @@
 	})
 	const formRef = ref()
 	const examStore = useExamStore()
-	const { levelEnum, subjects, subjectEnumFormat } = examStore
-
+	const { subjectEnumFormat } = examStore
+	const levelEnum = computed(() => examStore.getLevelEnum)
 	const formLoading = ref(false)
 	const form = reactive({
 		id: null,
@@ -167,14 +166,14 @@
 	// 初始化学科
 	const initSubject = async (cb) => {
 		await examStore.initSubject()
-		paperPage.subjectFilter = subjects
+		paperPage.subjectFilter = examStore.subjects
 		if (cb) cb()
 	}
 
 	// 年级变更
 	const levelChange = () => {
 		paperPage.queryParam.subjectId = null
-		paperPage.subjectFilter = subjects.filter((data) => data.level === form.gradeLevel)
+		paperPage.subjectFilter = examStore.subjects.filter((data) => data.level === form.gradeLevel)
 	}
 
 	// 添加试卷
@@ -265,7 +264,7 @@
 	// 初始化
 	onMounted(() => {
 		initSubject(() => {
-			paperPage.subjectFilter = subjects
+			paperPage.subjectFilter = examStore.subjects
 		})
 		const id = props.id
 		if (id && parseInt(id) !== 0) {