Browse Source

feat: 雷同卷提交 & 评分标准导入

chenhao 2 năm trước cách đây
mục cha
commit
eea37b6d92

+ 0 - 7
src/api/system.ts

@@ -24,13 +24,6 @@ const SystemApi: DefineApiModule<System.ApiMap> = {
       'Content-Type': 'multipart/form-data',
     },
   },
-  /** 导入评分标准 */
-  importMarkStandard: {
-    url: '/xxx/xx',
-    headers: {
-      'Content-Type': 'multipart/form-data',
-    },
-  },
   /** CET成绩列表 */
   getCetScoreList: '/api/student/page',
   /** CET成绩导出接口 */

+ 8 - 7
src/components/shared/MarkHistoryList.vue

@@ -55,6 +55,12 @@ const ScoringPanelContainer = computed(() => {
   return props.modal ? BaseDialog : LessRenderComponent
 })
 
+const { fetch: getMarkScoreHistoryListWithTask, result: scoreHistoryList } = useFetch('getMarkScoreHistoryListWithTask')
+
+const { fetch: getMarkScoreHistoryListWithSecret, result: scoreHistoryListWithSecret } = useFetch(
+  'getMarkScoreHistoryListWithSecret'
+)
+
 watch(
   () => props.id,
   () => {
@@ -63,13 +69,8 @@ watch(
         ? getMarkScoreHistoryListWithTask({ taskId: props.id })
         : getMarkScoreHistoryListWithSecret({ secretNumber: props.id })
     }
-  }
-)
-
-const { fetch: getMarkScoreHistoryListWithTask, result: scoreHistoryList } = useFetch('getMarkScoreHistoryListWithTask')
-
-const { fetch: getMarkScoreHistoryListWithSecret, result: scoreHistoryListWithSecret } = useFetch(
-  'getMarkScoreHistoryListWithSecret'
+  },
+  { immediate: true }
 )
 
 const tableData = computed(() => {

+ 7 - 2
src/hooks/useOptions.ts

@@ -19,7 +19,12 @@ type QuestionList = ExtractApiResponse<'getMainQuestionList'>[0] & {
   value: number
 }
 
-const useOptions = (types: (keyof DataModel)[], initModel?: DataModel | Ref<DataModel>, autoFill = true) => {
+const useOptions = (
+  types: (keyof DataModel)[],
+  initModel?: DataModel | Ref<DataModel>,
+  autoFill = true,
+  subjectEnable: boolean | null = true
+) => {
   const dataModel = reactive<DataModel>(unref(initModel) || {})
 
   if (isRef(initModel)) {
@@ -162,7 +167,7 @@ const useOptions = (types: (keyof DataModel)[], initModel?: DataModel | Ref<Data
   }
 
   const forceRefresh = () => {
-    getSubjectList({ pageNumber: 1, pageSize: 9999 })
+    getSubjectList({ pageNumber: 1, pageSize: 9999, enable: subjectEnable || void 0 })
   }
 
   if (types.includes('subject')) {

+ 4 - 84
src/modules/admin-data/paper/components/standard.vue

@@ -1,66 +1,29 @@
 <template>
-  <base-form
-    ref="formRef"
-    :label-width="useVW(88)"
-    :groups="groups"
-    :rules="rules"
-    :items="items"
-    :model="model"
-    :disabled="loading"
-  >
+  <base-form :label-width="useVW(88)" :groups="groups" :rules="rules" :items="items" :model="model">
     <template #form-item-address>
       <span class="flex items-center">
         {{ filePath }}
       </span>
     </template>
-    <template #form-item-upload>
-      <div class="flex items-center">
-        <el-input v-model="fileName" disabled placeholder="导入文件"></el-input>
-        <el-upload
-          ref="upload"
-          v-model:file-list="fileList"
-          :limit="1"
-          :show-file-list="false"
-          :on-exceed="onExceed"
-          :auto-upload="false"
-        >
-          <el-button class="m-l-base" type="primary">浏览</el-button>
-        </el-upload>
-      </div>
-    </template>
-    <template #form-item-progress>
-      <el-progress v-show="showProgress" class="flex-1" :percentage="percentage" color="#00BA97" />
-    </template>
-    <el-form-item class="m-t-base form-footer">
-      <el-button type="primary" :loading="loading" @click="onSubmit">确定导入</el-button>
-    </el-form-item>
   </base-form>
 </template>
 
 <script setup lang="ts" name="ImportStandard">
 /** 导入评分标准 */
 import { reactive, watch, computed, ref } from 'vue'
-import { ElFormItem, ElButton, ElUpload, ElInput, ElMessage, ElProgress } from 'element-plus'
 import BaseForm from '@/components/element/BaseForm.vue'
 import useFetch from '@/hooks/useFetch'
 import useForm from '@/hooks/useForm'
 import useOptions from '@/hooks/useOptions'
-import useUploadFile from '@/hooks/useUploadFile'
 import useVW from '@/hooks/useVW'
 
 import type { FormGroup, EpFormItem, EpFormRules } from 'global-type'
-import type { ExtractApiParams } from 'api-type'
-
-const showProgress = ref(false)
-
-const { fileList, upload, percentage, setPercentage, onExceed, onUploadProgress, reset } = useUploadFile()
 
 const { fetch: getImportFilePath, result: filePath } = useFetch('getImportFilePath')
 
-const { fetch, loading } = useFetch('importMarkStandard', { onUploadProgress })
+const { subjectList, mainQuestionList, dataModel, changeModelValue } = useOptions(['subject', 'question'])
 
-const model = reactive<ExtractApiParams<'importMarkStandard'>>({
-  file: void 0,
+const model = reactive<{ subjectCode: string; mainNumber?: number }>({
   subjectCode: '',
   mainNumber: void 0,
 })
@@ -76,35 +39,21 @@ watch([() => model.subjectCode, () => model.mainNumber], () => {
     })
 })
 
-const { subjectList, mainQuestionList, dataModel, changeModelValue } = useOptions(['subject', 'question'])
-
 watch(dataModel, () => {
   model.subjectCode = dataModel.subject || ''
   model.mainNumber = dataModel.question
 })
 
-const { formRef, elFormRef, defineColumn, _ } = useForm()
-
-const fileName = computed(() => fileList.value?.[0]?.name)
-
-watch(
-  fileList,
-  () => {
-    model.file = fileList.value?.[0]?.raw
-  },
-  { deep: true }
-)
+const { defineColumn, _ } = useForm()
 
 const rules: EpFormRules = {
   subjectCode: [{ required: true, message: '请选择科目' }],
   mainNumber: [{ required: true, message: '请选择大题' }],
-  file: [{ required: true, message: '请选择导入文件' }],
 }
 
 const groups: FormGroup[] = [
   { groupTitle: '选择大题', rowKeys: ['row-1'] },
   { groupTitle: '试卷设置', rowKeys: ['row-2'] },
-  { groupTitle: '选择文件', rowKeys: ['row-3'] },
 ]
 
 const span6 = defineColumn(_, '', { span: 6 })
@@ -132,37 +81,8 @@ const items = computed<EpFormItem[]>(() => {
       slotName: 'address',
       itemDescription: { description: '试卷图片请按路径存放' },
     }),
-    span6({
-      rowKey: 'row-3',
-      label: '导入文件',
-      prop: 'file',
-      slotName: 'upload',
-    }),
-    span6({
-      rowKey: 'row-4',
-      slotName: 'progress',
-    }),
   ]
 })
-
-async function onSubmit() {
-  try {
-    const valid = await elFormRef?.value?.validate()
-    if (valid) {
-      showProgress.value = true
-      setPercentage(0)
-      await fetch(model)
-      setPercentage(100)
-      ElMessage.success(`导入成功`)
-      elFormRef?.value?.resetFields()
-      reset()
-    }
-  } catch (error) {
-    showProgress.value = false
-    setPercentage(0)
-    console.error(error)
-  }
-}
 </script>
 
 <style scoped lang="scss"></style>

+ 4 - 4
src/modules/admin-subject/manage/index.vue

@@ -14,7 +14,7 @@
             <el-popconfirm
               :width="useVW(220)"
               hide-icon
-              :title="`确认${row.enable ? '禁用' : '启用'}考试?`"
+              :title="`确认${row.enable ? '禁用' : '启用'}科目?`"
               @confirm="toggleEnable(row)"
             >
               <template #reference>
@@ -23,7 +23,7 @@
                 </el-button>
               </template>
             </el-popconfirm>
-            <el-popconfirm :width="useVW(220)" hide-icon :title="`确认删除考试?`" @confirm="onDelete(row)">
+            <el-popconfirm :width="useVW(220)" hide-icon :title="`确认删除科目?`" @confirm="onDelete(row)">
               <template #reference>
                 <el-button type="primary" link>删除</el-button>
               </template>
@@ -51,7 +51,7 @@
 
 <script setup lang="tsx" name="SubjectManage">
 /** 科目管理 */
-import { reactive, ref, computed, nextTick } from 'vue'
+import { reactive, ref, computed } from 'vue'
 import { useRouter } from 'vue-router'
 import { ElButton, ElCard, ElPopconfirm, ElFormItem, ElMessage } from 'element-plus'
 import ConfirmButton from '@/components/common/ConfirmButton.vue'
@@ -73,7 +73,7 @@ const { push } = useRouter()
 
 const subjectCode = ref<string>()
 
-const { subjectList, forceRefresh } = useOptions(['subject'])
+const { subjectList, forceRefresh } = useOptions(['subject'], {}, true, null)
 
 const request = reactive({ code: '' })
 

+ 2 - 4
src/modules/admin-user/manage/hooks/useUserManageFilter.ts

@@ -4,21 +4,19 @@ import useForm from '@/hooks/useForm'
 import useOptions, { DataModel } from '@/hooks/useOptions'
 
 import type { EpFormItem, InstanceForm, EpFormRows } from 'global-type'
-import type { ExtractApiParams } from 'api-type'
+import type { ExtractMultipleApiParams } from 'api-type'
 
 const useUserManageFilter = () => {
   const { elFormRef, formRef, defineColumn, _ } = useForm()
   const expand = ref(false)
 
-  const model = reactive<ExtractApiParams<'getUserList'>>({
+  const model = reactive<ExtractMultipleApiParams<'getUserList'>>({
     subjectCode: '',
     mainNumber: void 0,
     enable: true,
     loginName: '',
     name: '',
     role: void 0,
-    pageNumber: 1,
-    pageSize: 10,
   })
 
   const { subjectList, mainQuestionList, changeModelValue, dataModel } = useOptions(['subject', 'question'], {}, false)

+ 16 - 1
src/modules/analysis/personnel-statistics/components/StatisticsGroup.vue

@@ -110,12 +110,27 @@ watch(
   { immediate: true, deep: true }
 )
 
+type StatisticObjectiveByGroup = ExtractApiResponse<'getStatisticObjectiveByGroup'>
+
+// const getXAxisData = <K extends keyof StatisticObjectiveByGroup>(field: K, data?: StatisticObjectiveByGroup[K]) => {
+//   if (!data) {
+//     return []
+//   }
+//   const getValue = <T extends keyof ExtractArrayValue<StatisticObjectiveByGroup[K]>>(
+//     key: T,
+//     item: ExtractArrayValue<StatisticObjectiveByGroup[K]>
+//   ) => {
+//     return item[key]
+//   }
+//   return data?.map((v) => getValue(field, v))
+// }
+
 // const groupChartsOption = computed<EChartsOption>(() => {
 //   return {
 //     legend: {
 //       right: 0,
 //       itemWidth: 14,
-//       data: ['完成总量', '当日已完成', '完成比'],
+//       data: ['小组主观分布', '题组主观分布'],
 //     },
 //     xAxis: {
 //       axisLine: { show: false },

+ 36 - 31
src/modules/marking/submit-similar/index.vue

@@ -3,22 +3,26 @@
     <div class="flex-1 full-y p-extra-small fill-blank radius-base scroll-auto view-paper">
       <img :src="current?.url" alt="" />
     </div>
-    <div class="m-l-base p-base fill-blank radius-base history-view">
-      <mark-history-list :id="props.taskId" #default="{ data }" :modal="false">
+    <div class="flex direction-column full-h m-l-base p-base fill-blank radius-base history-view">
+      <div class="flex-1 overflow-hidden">
         <base-table
           ref="tableRef"
-          :data="filterSelfTask(data)"
+          size="small"
+          height="100%"
+          :data="tableData"
           :columns="columns"
           class="history-table"
+          highlight-current-row
           @current-change="onCurrentChange"
         ></base-table>
-      </mark-history-list>
-      <div class="flex items-center p-l-base">
+      </div>
+
+      <div class="flex items-center m-t-base p-l-base">
         <span>雷同卷号:</span>
-        <span>{{ query.secretNumber || 111 }}</span>
+        <span>{{ query.secretNumber }}</span>
       </div>
       <div class="flex items-center p-l-base m-t-extra-small">
-        <span class="checked-secret-number">{{ query.secretNumber || 111 }}</span>
+        <span class="checked-secret-number">{{ current?.secretNumber }}</span>
       </div>
       <div class="p-l-base m-t-base">
         <confirm-button class="confirm-buttons" size="small" @confirm="submit" @cancel="onCancel"></confirm-button>
@@ -29,13 +33,12 @@
 
 <script setup lang="tsx" name="SubmitSimilar">
 /** 提交雷同卷 */
-import { reactive, ref, computed } from 'vue'
+import { ref, computed, watch } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { ElRadio } from 'element-plus'
 import useFetch from '@/hooks/useFetch'
 import useTableCheck from '@/hooks/useTableCheck'
 import BaseTable from '@/components/element/BaseTable.vue'
-import MarkHistoryList from '@/components/shared/MarkHistoryList.vue'
 import ConfirmButton from '@/components/common/ConfirmButton.vue'
 
 import type { ExtractApiResponse } from 'api-type'
@@ -48,30 +51,33 @@ const props = defineProps<{
 const { query } = useRoute()
 const { back } = useRouter()
 
-let historyData = ref<ExtractApiResponse<'getMarkScoreHistoryListWithTask'>>([])
+const { fetch: getMarkHistory, result: markHistoryList } = useFetch('getMarkHistory')
 
 /** 过滤自己 */
-const filterSelfTask = (data?: ExtractApiResponse<'getMarkScoreHistoryListWithTask'>) => {
-  historyData.value =
-    data?.filter((d) => `${d.taskId}` !== `${props.taskId}`).map((d, index) => ({ ...d, index })) || []
-  return historyData.value
-}
+const filterSelfData = computed(() => {
+  return (
+    markHistoryList?.value?.filter((d) => `${d.taskId}` !== `${props.taskId}`).map((d, index) => ({ ...d, index })) ||
+    []
+  )
+})
 
-const { tableRef, current, onCurrentChange } = useTableCheck(historyData)
+const { tableRef, tableData, current, onCurrentChange } = useTableCheck(filterSelfData)
 
-const columns = computed<EpTableColumn<ExtractArrayValue<ExtractApiResponse<'getMarkScoreHistoryListWithTask'>>>[]>(
-  () => [
-    {
-      label: '选中雷同',
-      formatter(row) {
-        return <ElRadio modelValue={current.value?.secretNumber === row.secretNumber}></ElRadio>
-      },
-      align: 'center',
+const columns = computed<EpTableColumn<ExtractArrayValue<ExtractApiResponse<'getMarkHistory'>>>[]>(() => [
+  {
+    label: '选中雷同',
+    formatter(row) {
+      return (
+        <ElRadio modelValue={current.value?.secretNumber} label={row.secretNumber}>
+          {' '}
+        </ElRadio>
+      )
     },
-    { label: '密号', prop: 'secretNumber', align: 'center' },
-    { label: '分数', prop: 'markScore', align: 'center' },
-  ]
-)
+    align: 'center',
+  },
+  { label: '密号', prop: 'secretNumber', align: 'center' },
+  { label: '分数', prop: 'markScore', align: 'center' },
+])
 
 /** 提交 */
 const submit = async () => {
@@ -86,6 +92,8 @@ const submit = async () => {
 const onCancel = () => {
   back()
 }
+
+getMarkHistory()
 </script>
 
 <style scoped lang="scss">
@@ -95,9 +103,6 @@ const onCancel = () => {
 .history-view {
   width: 360px;
   font-size: $MediumFont;
-  .history-table {
-    max-height: 65vh;
-  }
   .checked-secret-number {
     margin-left: 74px;
     display: inline-block;

+ 2 - 11
types/api.d.ts

@@ -317,16 +317,6 @@ declare module 'api-type' {
 
     type ImportRfPaper = BaseDefine<RfPaperImport>
 
-    interface MarkStandardImport {
-      file?: File
-      /** 大题号 */
-      mainNumber?: number
-      /** 科目代码 */
-      subjectCode: string
-    }
-
-    type ImportMarkStandard = BaseDefine<MarkStandardImport>
-
     interface ScoreListItem {
       /** 准考证号 */
       examNumber: string
@@ -382,7 +372,6 @@ declare module 'api-type' {
       getImportFilePath: GetImportFilePath
       importSamplePaper: ImportSamplePaper
       importRfPaper: ImportRfPaper
-      importMarkStandard: ImportMarkStandard
       getCetScoreList: GetCetScoreList
       exportCetScoreList: ExportCetScoreList
       /** 任务设置 - 按评卷员设置 */
@@ -914,6 +903,8 @@ declare module 'api-type' {
         code?: string
         /** 科目名称 */
         name?: string
+        /** 启用/禁用 */
+        enable?: boolean
       }>,
       MultipleResult<SubjectInfo>
     >