form.vue 14 KB

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