index.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <template>
  2. <div class="flex direction-column">
  3. <div class="flex items-center fill-blank p-medium-base">
  4. <span class="subject-name">{{ subjectInfo?.name }}</span>
  5. <confirm-button
  6. class="m-l-auto"
  7. size="small"
  8. ok-text="新增"
  9. cancel-text="返回"
  10. @confirm="onAddMainQuestion"
  11. @cancel="back"
  12. ></confirm-button>
  13. </div>
  14. <div class="flex-1 p-base">
  15. <el-card shadow="never">
  16. <base-table size="small" border stripe :data="tableData" :columns="columns">
  17. <template #column-operation="{ row }">
  18. <el-button type="primary" link @click="onEditSubQuestion(row)">编辑</el-button>
  19. <el-popconfirm :width="useVW(220)" hide-icon :title="`确认删除题目?`" @confirm="onDelete(row)">
  20. <template #reference>
  21. <el-button type="primary" link>删除</el-button>
  22. </template>
  23. </el-popconfirm>
  24. <el-button v-if="row.firstMain" type="primary" link @click="onEditMainQuestion(row)">大题设置</el-button>
  25. </template>
  26. </base-table>
  27. </el-card>
  28. </div>
  29. <base-dialog v-model="visibleSubQuestionEditor" unless :footer="false" destroy-on-close>
  30. <base-form
  31. ref="formRef"
  32. :label-width="useVW(72)"
  33. :model="editSubInfo"
  34. :items="items"
  35. :rules="rules"
  36. :disabled="saving"
  37. >
  38. <template #form-item-mainQuestion> {{ [editSubInfo.mainNumber, editSubInfo.mainTitle].join('-') }} </template>
  39. <template #form-item-subQuestion> {{ editSubInfo.subNumber }} </template>
  40. <el-form-item class="m-t-base">
  41. <confirm-button :loading="saving" @confirm="onSubmit" @cancel="toggleVisible(false)"></confirm-button>
  42. </el-form-item>
  43. </base-form>
  44. </base-dialog>
  45. </div>
  46. </template>
  47. <script setup lang="ts" name="SubjectStructManage">
  48. /** 科目试卷结构管理 */
  49. import { reactive, ref, computed } from 'vue'
  50. import { useRouter } from 'vue-router'
  51. import { ElButton, ElCard, ElFormItem, ElPopconfirm, ElMessage } from 'element-plus'
  52. import ConfirmButton from '@/components/common/ConfirmButton.vue'
  53. import BaseTable from '@/components/element/BaseTable.vue'
  54. import BaseForm from '@/components/element/BaseForm.vue'
  55. import BaseDialog from '@/components/element/BaseDialog.vue'
  56. import useFetch from '@/hooks/useFetch'
  57. import useForm from '@/hooks/useForm'
  58. import useVW from '@/hooks/useVW'
  59. import type { EpTableColumn, EpFormItem, EpFormRules } from 'global-type'
  60. import type { ExtractApiResponse } from '@/api/api'
  61. const { back, push } = useRouter()
  62. const props = defineProps<{ id: number | string }>()
  63. const { fetch: getSubjectInfo, result: subjectInfo } = useFetch('getSubjectInfo')
  64. const { fetch: getSubQuestionList, result: subQuestionList } = useFetch('getSubQuestionList')
  65. type SubQuestion = ExtractArrayValue<ExtractApiResponse<'getSubQuestionList'>>
  66. type WithFirstMainTag = SubQuestion & { firstMain: boolean }
  67. const tableData = computed<Array<WithFirstMainTag>>(() => {
  68. const MainMap: Record<number, boolean> = {}
  69. return subQuestionList.value?.map((sub) => {
  70. const mainHas = !!MainMap[sub.mainNumber]
  71. if (!mainHas) {
  72. MainMap[sub.mainNumber] = true
  73. }
  74. return { ...sub, firstMain: !mainHas }
  75. })
  76. })
  77. const columns: EpTableColumn[] = [
  78. { label: '大题号', prop: 'mainNumber' },
  79. { label: '大题名称', prop: 'mainTitle' },
  80. { label: '小题号', prop: 'subNumber' },
  81. { label: '小题满分', prop: 'totalScore' },
  82. { label: '间隔分', prop: 'intervalScore' },
  83. { label: '操作', slotName: 'operation' },
  84. ]
  85. if (props.id) {
  86. getSubjectInfo({ id: +props.id }).then((info) => {
  87. getSubQuestionList({ subjectCode: info.code })
  88. })
  89. }
  90. /** 新增大题 */
  91. function onAddMainQuestion() {
  92. if (subjectInfo.value.code) {
  93. push({ name: 'EditStruct', params: { subjectCode: subjectInfo.value.code } })
  94. }
  95. }
  96. /** 编辑大题 */
  97. function onEditMainQuestion(row: ExtractArrayValue<ExtractApiResponse<'getSubQuestionList'>>) {
  98. if (subjectInfo.value.code) {
  99. push({ name: 'EditStruct', params: { subjectCode: subjectInfo.value.code, mainNumber: row.mainNumber } })
  100. }
  101. }
  102. const { fetch: editSubQuestion, loading: saving } = useFetch('editSubQuestion')
  103. const editSubInfo = reactive<Partial<ExtractArrayValue<ExtractApiResponse<'getSubQuestionList'>>>>({})
  104. const { formRef, elFormRef } = useForm()
  105. const rules = computed<EpFormRules>(() => {
  106. return {
  107. intervalScore: [{ required: true, message: '请填写间隔分' }],
  108. }
  109. })
  110. const items = computed<EpFormItem[]>(() => {
  111. return [
  112. { label: '大题', slotName: 'mainQuestion' },
  113. { label: '小题号', slotName: 'subQuestion' },
  114. {
  115. label: '间隔分',
  116. prop: 'intervalScore',
  117. slotType: 'inputNumber',
  118. slot: { placeholder: '间隔分', stepStrictly: true, step: 1 },
  119. },
  120. ]
  121. })
  122. const visibleSubQuestionEditor = ref<boolean>(false)
  123. function toggleVisible(visible: boolean) {
  124. visibleSubQuestionEditor.value = visible
  125. }
  126. /** 编辑小题 */
  127. function onEditSubQuestion(row: ExtractArrayValue<ExtractApiResponse<'getSubQuestionList'>>) {
  128. Object.assign(editSubInfo, row)
  129. toggleVisible(true)
  130. }
  131. async function onSubmit() {
  132. try {
  133. const valid = await elFormRef?.value?.validate()
  134. valid && (await editSubQuestion({ id: editSubInfo.id, intervalScore: editSubInfo.intervalScore }))
  135. ElMessage.success(`保存成功`)
  136. subjectInfo?.value?.code && getSubQuestionList({ subjectCode: subjectInfo.value.code })
  137. toggleVisible(false)
  138. } catch (error) {
  139. console.error(error)
  140. }
  141. }
  142. /** 删除 */
  143. const { fetch: deleteSubQuestion } = useFetch('deleteSubQuestion')
  144. function onDelete(row: ExtractArrayValue<ExtractApiResponse<'getSubQuestionList'>>) {
  145. row.id &&
  146. deleteSubQuestion({ id: row.id }).then(() => {
  147. subjectInfo?.value?.code && getSubQuestionList({ subjectCode: subjectInfo.value.code })
  148. })
  149. }
  150. </script>
  151. <style scoped lang="scss"></style>