form.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. <template>
  2. <div class="app-container">
  3. <a-form
  4. :model="form"
  5. ref="formRef"
  6. :label-col="{ span: 4 }"
  7. :wrapper-col="{ span: 16 }"
  8. :rules="rules"
  9. :loading="formLoading"
  10. layout="horizontal"
  11. >
  12. <a-form-item label="试卷类型:">
  13. <a-select v-model:value="form.examType" placeholder="请选择试卷类型" @change="examTypeChange" allow-clear>
  14. <a-select-option v-for="item in examTypeEnum" :key="item.value" :value="item.value">
  15. {{ item.label }}
  16. </a-select-option>
  17. </a-select>
  18. </a-form-item>
  19. <a-form-item label="考试标题" name="examName" :rules="rules.examName">
  20. <a-input v-model:value="form.examName" placeholder="请输入考试标题" />
  21. </a-form-item>
  22. <a-form-item label="选择试卷" name="paperId" :rules="rules.paperId">
  23. <a-input-group compact>
  24. <a-input
  25. v-model:value="selectedPaperName"
  26. placeholder="请选择试卷"
  27. readonly
  28. style="width: calc(100% - 100px)"
  29. />
  30. <a-button type="primary" @click="addPaper" style="width: 100px">选择试卷</a-button>
  31. </a-input-group>
  32. </a-form-item>
  33. <a-form-item label="学期" name="semesterId" :rules="rules.semesterId">
  34. <a-select v-model:value="form.semesterId" placeholder="请选择学期" allowClear @change="handleSemesterChange">
  35. <a-select-option v-for="item in semesterList" :key="item.id" :value="item.id">
  36. {{ item.name }}
  37. </a-select-option>
  38. </a-select>
  39. </a-form-item>
  40. <!-- <a-form-item label="专业" name="majorId">
  41. <a-select v-model:value="form.majorId" placeholder="请选择专业" allowClear @change="handleMajorChange">
  42. <a-select-option v-for="item in majorList" :key="item.id" :value="item.id">
  43. {{ item.majorName }}
  44. </a-select-option>
  45. </a-select>
  46. </a-form-item> -->
  47. <a-form-item label="课程" name="courseId" :rules="rules.courseId">
  48. <a-select v-model:value="form.courseId" placeholder="请选择课程" allowClear :disabled="!form.semesterId">
  49. <a-select-option v-for="item in courseList" :key="item.courseId" :value="item.courseId">
  50. {{ item.courseName }}
  51. </a-select-option>
  52. </a-select>
  53. </a-form-item>
  54. <a-form-item label="开始时间" name="startTime" :rules="rules.startTime">
  55. <a-date-picker
  56. v-model:value="form.startTime"
  57. show-time
  58. format="YYYY-MM-DD HH:mm:ss"
  59. placeholder="请选择开始时间"
  60. style="width: 100%"
  61. :disabledDate="disabledStartDate"
  62. />
  63. </a-form-item>
  64. <a-form-item label="结束时间" name="endTime" :rules="rules.endTime">
  65. <a-date-picker
  66. v-model:value="form.endTime"
  67. show-time
  68. format="YYYY-MM-DD HH:mm:ss"
  69. placeholder="请选择结束时间"
  70. style="width: 100%"
  71. :disabledDate="disabledStartDate"
  72. />
  73. </a-form-item>
  74. <a-form-item label="考试状态" name="examStatus">
  75. <a-radio-group v-model:value="form.examStatus">
  76. <a-radio :value="0">未开始</a-radio>
  77. <a-radio :value="1">已开始</a-radio>
  78. <a-radio :value="2">已结束</a-radio>
  79. </a-radio-group>
  80. </a-form-item>
  81. <a-form-item>
  82. <a-space>
  83. <a-button type="primary" @click="submitForm">提交</a-button>
  84. <a-button @click="resetForm">重置</a-button>
  85. </a-space>
  86. </a-form-item>
  87. </a-form>
  88. <a-modal
  89. v-model:visible="paperPage.showDialog"
  90. width="70%"
  91. title="选择试卷"
  92. @ok="confirmPaperSelect"
  93. @cancel="() => (paperPage.showDialog = false)"
  94. >
  95. <a-form layout="inline">
  96. <a-form-item label="试卷类型">
  97. <a-select v-model:value="paperPage.queryParam.paperType" placeholder="请选择试卷类型" disabled>
  98. <a-select-option v-for="item in paperTypeEnum" :key="item.key" :value="item.key">
  99. {{ item.value }}
  100. </a-select-option>
  101. </a-select>
  102. </a-form-item>
  103. <a-form-item>
  104. <a-button type="primary" @click="examPaperSubmitForm">查询</a-button>
  105. </a-form-item>
  106. </a-form>
  107. <a-table
  108. :dataSource="paperPage.tableData"
  109. :columns="modalColumns"
  110. rowKey="id"
  111. :loading="paperPage.listLoading"
  112. :rowSelection="rowSelection"
  113. bordered
  114. :pagination="false"
  115. style="margin-top: 16px"
  116. >
  117. <!-- <template #bodyCell="{ column, record }">
  118. <template v-if="column.key === 'subjectId'">
  119. {{ subjectEnumFormat(record.subjectId) }}
  120. </template>
  121. </template> -->
  122. </a-table>
  123. <a-pagination
  124. v-show="paperPage.total > 0"
  125. :total="paperPage.total"
  126. :current="paperPage.queryParam.pageIndex"
  127. :pageSize="paperPage.queryParam.pageSize"
  128. @change="onPageChange"
  129. @showSizeChange="onPageSizeChange"
  130. show-size-changer
  131. style="margin-top: 16px; text-align: right"
  132. />
  133. </a-modal>
  134. </div>
  135. </template>
  136. <script setup>
  137. import { ref, reactive, onMounted, computed } from 'vue'
  138. import { message } from 'ant-design-vue'
  139. import { useExamStore } from '@/store/exam.js'
  140. import examManagerApi from '@/api/exam/paper/examManager.js'
  141. import examPaperApi from '@/api/exam/paper/examPaperApi.js'
  142. import resourceAuditApi from '@/api/resourceAudit.js'
  143. import tool from '@/utils/tool'
  144. import dayjs from 'dayjs'
  145. const emit = defineEmits(['success'])
  146. const props = defineProps({
  147. id: {
  148. type: Number,
  149. default: null
  150. }
  151. })
  152. const formRef = ref()
  153. const examStore = useExamStore()
  154. const paperTypeEnum = computed(() => examStore.paperTypeEnum.filter((item) => item.key !== '5'))
  155. const examTypeEnum = tool.dictList('EXAM_TYPE').filter((item) => item.value !== '3')
  156. console.log('examTypeEnum', examTypeEnum)
  157. console.log('paperTypeEnum', paperTypeEnum.value)
  158. const formLoading = ref(false)
  159. const semesterList = ref([])
  160. const majorList = ref([])
  161. const courseList = ref([])
  162. const form = reactive({
  163. id: null,
  164. examName: '',
  165. paperId: null,
  166. courseId: null,
  167. startTime: null,
  168. endTime: null,
  169. examStatus: 0,
  170. semesterId: null
  171. // majorId: null
  172. })
  173. const rules = {
  174. examName: [{ required: true, message: '请输入考试标题', trigger: 'blur' }],
  175. paperId: [{ required: true, message: '请选择试卷', trigger: 'change' }],
  176. startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
  177. endTime: [{ required: true, message: '请选择结束时间', trigger: 'change' }],
  178. semesterId: [{ required: true, message: '请选择学期', trigger: 'change' }],
  179. courseId: [{ required: true, message: '请选择课程', trigger: 'change' }]
  180. }
  181. const selectedPaperName = ref('')
  182. const modalColumns = [
  183. { title: 'Id', dataIndex: 'id', key: 'id', width: 90 },
  184. // { title: '学科', dataIndex: 'subjectId', key: 'subjectId', width: 120 },
  185. { title: '名称', dataIndex: 'name', key: 'name' },
  186. {
  187. title: '创建时间',
  188. dataIndex: 'createTimeStr',
  189. key: 'createTimeStr',
  190. width: 200
  191. }
  192. ]
  193. const paperPage = reactive({
  194. subjectFilter: [],
  195. selectedPaper: null,
  196. showDialog: false,
  197. queryParam: {
  198. paperId: null,
  199. paperType: '6',
  200. pageIndex: 1,
  201. pageSize: 5
  202. },
  203. listLoading: false,
  204. tableData: [],
  205. total: 0
  206. })
  207. // 试卷选择表格单选
  208. const selectedRowKeys = ref([])
  209. const rowSelection = reactive({
  210. type: 'radio',
  211. selectedRowKeys: selectedRowKeys,
  212. onChange: (selectedRowKeysVal, selectedRows) => {
  213. selectedRowKeys.value = selectedRowKeysVal
  214. paperPage.selectedPaper = selectedRows[0] || null
  215. }
  216. })
  217. // 学期变更处理函数
  218. const handleSemesterChange = (value) => {
  219. form.courseId = null
  220. courseList.value = []
  221. // 如果学期和专业都已选择,则查询课程列表
  222. if (value) {
  223. loadCourseList()
  224. }
  225. }
  226. // 专业变更处理函数
  227. // const handleMajorChange = (value) => {
  228. // form.courseId = null
  229. // courseList.value = []
  230. // // 如果学期和专业都已选择,则查询课程列表
  231. // if (value && form.semesterId) {
  232. // loadCourseList()
  233. // }
  234. // }
  235. // 加载课程列表
  236. const loadCourseList = () => {
  237. // 添加加载状态
  238. const courseLoading = message.loading('正在加载课程列表...', 0)
  239. // 根据选择的学期和专业加载课程列表
  240. resourceAuditApi
  241. .courseAllList({
  242. semesterId: form.semesterId
  243. })
  244. .then((res) => {
  245. if (res.code === 200) {
  246. courseList.value = res.data
  247. } else {
  248. message.error('加载课程列表失败:' + (res.msg || '未知错误'))
  249. }
  250. })
  251. .catch((err) => {
  252. message.error('加载课程列表失败:' + (err.message || '网络错误'))
  253. })
  254. .finally(() => {
  255. courseLoading()
  256. })
  257. }
  258. // 禁用开始时间大于今天的日期
  259. const disabledStartDate = (current) => {
  260. // 禁用大于今天的日期
  261. return current && current < dayjs().endOf('day')
  262. }
  263. // 试卷类型变更
  264. const paperTypeChange = () => {
  265. paperPage.queryParam.paperId = null
  266. form.paperId = null
  267. selectedPaperName.value = ''
  268. }
  269. // 考试类型变更
  270. const examTypeChange = (type) => {
  271. switch (type) {
  272. case '1': // 普通考试
  273. paperPage.queryParam.paperType = '6'
  274. break
  275. case '2': // 章节测验
  276. paperPage.queryParam.paperType = '3'
  277. break
  278. case '4': // 课时作业
  279. paperPage.queryParam.paperType = '2'
  280. break
  281. }
  282. }
  283. // 选择试卷
  284. const addPaper = () => {
  285. paperPage.showDialog = true
  286. search()
  287. }
  288. // 查询试卷
  289. const search = async () => {
  290. paperPage.listLoading = true
  291. paperPage.showDialog = true
  292. const params = {
  293. ...paperPage.queryParam,
  294. current: paperPage.queryParam.pageIndex,
  295. size: paperPage.queryParam.pageSize,
  296. paperType: paperPage.queryParam.paperType
  297. }
  298. delete params.pageIndex
  299. delete params.pageSize
  300. const data = await examPaperApi.selectExamList(params)
  301. const re = data
  302. paperPage.tableData = re.records
  303. paperPage.total = re.total
  304. paperPage.queryParam.pageIndex = re.current
  305. paperPage.listLoading = false
  306. }
  307. // 确认选择试卷
  308. const confirmPaperSelect = () => {
  309. if (!paperPage.selectedPaper) {
  310. message.warning('请选择一个试卷')
  311. return
  312. }
  313. form.paperId = paperPage.selectedPaper.id
  314. selectedPaperName.value = paperPage.selectedPaper.name
  315. paperPage.showDialog = false
  316. selectedRowKeys.value = []
  317. }
  318. // 分页
  319. const onPageChange = (page) => {
  320. paperPage.queryParam.pageIndex = page
  321. search()
  322. }
  323. const onPageSizeChange = (current, size) => {
  324. paperPage.queryParam.pageSize = size
  325. paperPage.queryParam.pageIndex = 1
  326. search()
  327. }
  328. // 查询按钮
  329. const examPaperSubmitForm = () => {
  330. paperPage.queryParam.pageIndex = 1
  331. search()
  332. }
  333. // 提交表单
  334. const submitForm = () => {
  335. formRef.value.validate().then(async () => {
  336. formLoading.value = true
  337. try {
  338. const submitData = {
  339. ...form,
  340. startTime: form.startTime ? form.startTime.format('YYYY-MM-DD HH:mm:ss') : null,
  341. endTime: form.endTime ? form.endTime.format('YYYY-MM-DD HH:mm:ss') : null
  342. }
  343. if (form.id) {
  344. await examManagerApi.edit(submitData)
  345. } else {
  346. await examManagerApi.createExam(submitData)
  347. }
  348. emit('success')
  349. } catch (e) {
  350. console.error(e)
  351. } finally {
  352. formLoading.value = false
  353. }
  354. })
  355. }
  356. // 重置表单
  357. const resetForm = () => {
  358. const lastId = form.id
  359. formRef.value.resetFields()
  360. form.id = lastId
  361. form.examName = ''
  362. form.paperId = null
  363. form.semesterId = null // 重置学期
  364. // form.majorId = null // 重置专业
  365. form.courseId = null
  366. form.startTime = null
  367. form.endTime = null
  368. form.examStatus = 0
  369. selectedPaperName.value = ''
  370. paperPage.queryParam.paperType = null
  371. majorList.value = [] // 清空专业列表
  372. courseList.value = [] // 清空课程列表
  373. }
  374. // 初始化
  375. onMounted(() => {
  376. const id = props.id
  377. if (id && parseInt(id) !== 0) {
  378. formLoading.value = true
  379. examManagerApi
  380. .select(id)
  381. .then((re) => {
  382. Object.assign(form, {
  383. ...re,
  384. startTime: re.startTime ? dayjs(re.startTime) : null,
  385. endTime: re.endTime ? dayjs(re.endTime) : null
  386. })
  387. // 如果有试卷ID,需要获取试卷名称显示
  388. if (re.paperId) {
  389. paperPage.queryParam.paperId = re.paperId
  390. // 这里可以根据需要调用接口获取试卷名称
  391. examPaperApi.select(re.paperId).then((r) => {
  392. selectedPaperName.value = r.name
  393. })
  394. }
  395. // 如果是编辑模式,需要根据已有数据加载相应的课程列表
  396. if (re.semesterId) {
  397. // 直接加载课程列表
  398. loadCourseList()
  399. }
  400. formLoading.value = false
  401. })
  402. .catch((err) => {
  403. message.error('加载考试信息失败:' + (err.message || '网络错误'))
  404. formLoading.value = false
  405. })
  406. }
  407. // 加载学期列表
  408. const semesterLoading = message.loading('正在加载学期列表...', 0)
  409. resourceAuditApi
  410. .semesterDownList()
  411. .then((res) => {
  412. if (res.code === 200) {
  413. semesterList.value = res.data
  414. } else {
  415. message.error('加载学期列表失败:' + (res.msg || '未知错误'))
  416. }
  417. })
  418. .catch((err) => {
  419. message.error('加载学期列表失败:' + (err.message || '网络错误'))
  420. })
  421. .finally(() => {
  422. semesterLoading()
  423. })
  424. // 加载专业
  425. // const majorLoading = message.loading('正在加载专业列表...', 0)
  426. // resourceAuditApi
  427. // .majordownList()
  428. // .then((res) => {
  429. // if (res.code === 200) {
  430. // majorList.value = res.data
  431. // } else {
  432. // message.error('加载专业列表失败:' + (res.msg || '未知错误'))
  433. // }
  434. // })
  435. // .catch((err) => {
  436. // message.error('加载专业列表失败:' + (err.message || '网络错误'))
  437. // })
  438. // .finally(() => {
  439. // majorLoading()
  440. // })
  441. })
  442. </script>
  443. <style lang="less" scoped>
  444. .app-container {
  445. padding: 24px;
  446. background: #fff;
  447. }
  448. </style>