Explorar el Código

feat: bug fix

chenhao hace 2 años
padre
commit
74a15ce499

+ 1 - 1
src/api/api-types/statistics.d.ts

@@ -343,7 +343,7 @@ export namespace Statistics {
     /** 是否在线 */
     online: boolean
     /** 重评待确认量 */
-    reMarkConfirmCount: number
+    reMarkUnConfirmCount: number
     /** 重评量 */
     reMarkCount: number
     /** 最低分(近N分钟) */

+ 8 - 0
src/api/api-types/user.d.ts

@@ -211,6 +211,10 @@ export namespace User {
       }[]
     }
   >
+  /** 设置试卷配置信息 */
+  type SetUserMarkConfig = BaseDefine<{ config: string }>
+  /** 获取试卷配置信息 */
+  type GetUserMarkConfig = BaseDefine<null, string>
 
   /** >>> user api end <<< */
   export interface ApiMap {
@@ -233,5 +237,9 @@ export namespace User {
     getMarkerList: GetMarkerList
     /** 用户分组 - 发消息 */
     getUserGroup: GetUserGroup
+    /** 设置试卷配置信息 */
+    setUserMarkConfig: SetUserMarkConfig
+    /** 获取试卷配置信息 */
+    getUserMarkConfig: GetUserMarkConfig
   }
 }

+ 4 - 0
src/api/user.ts

@@ -44,6 +44,10 @@ const UserApi: DefineApiModule<User.ApiMap> = {
   getMarkerList: '/api/user/marker/list',
   /** 用户分组 - 发消息 */
   getUserGroup: '/api/user/group',
+  /** 设置试卷配置信息 */
+  setUserMarkConfig: '/api/user/config/set',
+  /** 获取试卷配置信息 */
+  getUserMarkConfig: '/api/user/config/get',
 }
 
 export default UserApi

+ 27 - 0
src/components/shared/MarkHeader.vue

@@ -27,6 +27,7 @@
 
 <script setup lang="ts" name="MarkHeader">
 import { reactive, ref, computed, useAttrs, watch } from 'vue'
+import useFetch from '@/hooks/useFetch'
 import SvgIcon from '@/components/common/SvgIcon.vue'
 import ColorPicker from '@/components/common/ColorPicker.vue'
 import Message from '@/components/shared/message/Message.vue'
@@ -128,6 +129,7 @@ const rotate = ref<number>(0)
 
 /** front-color */
 const frontColor = ref<string>('')
+
 /** background-color */
 const backgroundColor = ref<string>('')
 
@@ -171,6 +173,31 @@ const emitEvent = (type: EventType, val?: string | number | boolean | number[])
   }
   emits('click', { type: type, value: val })
 }
+
+type MarkConfig = {
+  center: boolean
+  ratio: number
+  rotate: number
+  frontColor: string
+  backgroundColor: string
+}
+
+const setCurrentConfig = (config: MarkConfig) => {
+  center.value = config.center ?? center.value
+  ratio.value = config.ratio ?? ratio.value
+  rotate.value = config.rotate ?? rotate.value
+  frontColor.value = config.frontColor ?? frontColor.value
+  backgroundColor.value = config.backgroundColor ?? backgroundColor.value
+}
+
+const loadUserConfig = async () => {
+  try {
+    const configStr = await useFetch('getUserMarkConfig').fetch()
+    const config = JSON.parse(configStr)
+  } catch (error) {
+    console.error(error)
+  }
+}
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
src/hooks/useOptions.ts

@@ -75,7 +75,7 @@ const useOptions = (
   const subjectList = computed(() => {
     return (
       subjectResult.value?.result?.map((subject) => {
-        return { ...subject, value: subject.code, label: subject.name }
+        return { ...subject, value: subject.code, label: `${subject.code}-${subject.name}` }
       }) || []
     )
   })

+ 4 - 1
src/hooks/useSetImgBg.ts

@@ -167,8 +167,11 @@ function canvasRotate(inputCanvas: HTMLCanvasElement, rotate = 0) {
 
   let x = -canvasWidth / 2
   let y = -canvasWidth / 2
+
   rotate = rotate % 360
 
+  console.log(rotate)
+
   if (rotate % 180 !== 0) {
     if (rotate === -90 || rotate === 270) {
       x = -W + canvasWidth / 2
@@ -403,7 +406,7 @@ export const useSetImgBg = (option: Ref<SetImgBgOption>) => {
     rawPixelPoints.value = []
     rawMainColor.value = []
     if (imageData.value && rawCanvas.value) {
-      const { pixelPoints, pixelsInfo, mainColor } = getMainColorWithPointes({
+      const { pixelPoints, mainColor } = getMainColorWithPointes({
         imageData: imageData.value,
         canvas: rawCanvas.value,
         basePoint: option.value.basePoint,

+ 21 - 5
src/modules/admin-exam/edit-exam/index.vue

@@ -37,7 +37,7 @@ const initModel: ExtractApiParams<'saveExamInfo'> = {
   name: '',
   doubtReject: true,
   markingMode: 'MOUSE',
-  maxTaskRecover: void 0,
+  maxTaskRecover: 30,
   maxMarkingDuration: void 0,
   spotCheckReject: true,
   userNameCollect: true,
@@ -51,10 +51,16 @@ const { formRef, elFormRef, defineColumn, _ } = useForm()
 const rules: EpFormRules = {
   name: [{ required: true, message: '请填写考试名称' }],
   markingMode: [{ required: true, message: '请选择评卷模式' }],
-  maxMarkingDuration: [{ required: true, message: '请设置在线评卷时长' }],
+  maxMarkingDuration: [
+    { required: true, message: '请设置在线评卷时长' },
+    { type: 'number', min: 1, max: 1440, message: '在线评卷时长限制1-1440分钟' },
+  ],
   spotCheckReject: [{ required: true, message: '抽查卷是否允许打回' }],
   doubtReject: [{ required: true, message: '问题卷是否允许打回' }],
-  maxTaskRecover: [{ required: true, message: '请设置自动任务回收的时间' }],
+  maxTaskRecover: [
+    { required: true, message: '请设置自动任务回收的时间' },
+    { type: 'number', min: 1, max: 1440, message: '任务回收时间限制1-1440分钟' },
+  ],
   userNameCollect: [{ required: true, message: '是否收集用户姓名' }],
   enable: [{ required: true, message: '是否启用考试' }],
 }
@@ -69,10 +75,20 @@ const items: EpFormItem[] = [
     prop: 'markingMode',
     slot: { options: [{ value: 'MOUSE', label: '键盘鼠标模式' }] },
   }),
-  span8({ label: '在线评卷时长', slotType: 'input', prop: 'maxMarkingDuration' }),
+  span8({
+    label: '在线评卷时长',
+    slotType: 'inputNumber',
+    prop: 'maxMarkingDuration',
+    slot: { stepStrictly: true, step: 1 },
+  }),
   span8({ label: '抽查卷允许打回', slotType: 'select', prop: 'spotCheckReject', slot: { options: TrueOrFalse } }),
   span8({ label: '问题卷允许打回', slotType: 'select', prop: 'doubtReject', slot: { options: TrueOrFalse } }),
-  span8({ label: '自动任务回收(分钟)', slotType: 'input', prop: 'maxTaskRecover' }),
+  span8({
+    label: '自动任务回收(分钟)',
+    slotType: 'inputNumber',
+    prop: 'maxTaskRecover',
+    slot: { stepStrictly: true, step: 1 },
+  }),
   span8({ label: '用户姓名收集', slotType: 'select', prop: 'userNameCollect', slot: { options: TrueOrFalse } }),
   span8({ label: '状态', slotType: 'select', prop: 'enable', slot: { options: StatusMap } }),
 ]

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

@@ -165,8 +165,8 @@ function onAddMainQuestion() {
 
 /** 编辑科目 */
 function onEdit(row: ExtractMultipleApiResponse<'getSubjectList'>) {
-  const { id, name, code, enable } = row
-  Object.assign(editInfo, { id, name, code, enable })
+  const { id, name, code, enable, objectiveScore } = row
+  Object.assign(editInfo, { id, name, code, enable, objectiveScore })
   toggleVisible(true)
 }
 

+ 37 - 19
src/modules/admin-user/edit-user/index.vue

@@ -49,15 +49,17 @@ const model = reactive<ExtractApiParams<'saveUserInfo'>>(initModel)
 
 const { formRef, elFormRef } = useForm()
 
-const rules: EpFormRules = {
-  subjectCode: [{ required: true, message: '请选择科目' }],
-  mainNumber: [{ required: true, message: '请选择大题' }],
-  markingGroupNumber: [{ required: true, message: '请选择小组' }],
-  role: [{ required: true, message: '请选择用户角色' }],
-  loginName: [{ required: true, message: '请填写账号代码' }],
-  password: [{ required: true, message: '请填写用户密码' }],
-  enable: [{ required: true, message: '请选择用户状态' }],
-}
+const rules = computed<EpFormRules>(() => {
+  return {
+    subjectCode: [{ required: true, message: '请选择科目' }],
+    mainNumber: [{ required: true, message: '请选择大题' }],
+    markingGroupNumber: model.role !== 'CHIEF' ? [{ required: true, message: '请选择小组' }] : [],
+    role: [{ required: true, message: '请选择用户角色' }],
+    loginName: [{ required: true, message: '请填写账号代码' }],
+    password: [{ required: true, message: '请填写用户密码' }],
+    enable: [{ required: true, message: '请选择用户状态' }],
+  }
+})
 
 const { subjectList, mainQuestionList, groupList, dataModel, changeModelValue } = useOptions([
   'subject',
@@ -89,6 +91,7 @@ const items = computed<EpFormItem[]>(() => {
         placeholder: '请选择科目',
         onChange: changeModelValue('subject'),
         options: subjectList.value,
+        disabled: isEdit,
       },
     },
     {
@@ -99,16 +102,7 @@ const items = computed<EpFormItem[]>(() => {
         placeholder: '大题号-大题名称',
         onChange: changeModelValue('question'),
         options: mainQuestionList.value,
-      },
-    },
-    {
-      label: '小组',
-      slotType: 'select',
-      prop: 'markingGroupNumber',
-      slot: {
-        placeholder: '用户所在小组',
-        options: groupList.value,
-        onChange: changeModelValue('group'),
+        disabled: isEdit,
       },
     },
     {
@@ -118,14 +112,29 @@ const items = computed<EpFormItem[]>(() => {
       slot: {
         options: ROLE_OPTION,
         placeholder: '设置用户角色',
+        disabled: isEdit,
       },
     },
+    model.role !== 'CHIEF'
+      ? {
+          label: '小组',
+          slotType: 'select',
+          prop: 'markingGroupNumber',
+          slot: {
+            placeholder: '用户所在小组',
+            options: groupList.value,
+            onChange: changeModelValue('group'),
+            disabled: isEdit,
+          },
+        }
+      : null,
     {
       label: '账号代码',
       slotType: 'input',
       prop: 'loginName',
       slot: {
         placeholder: '账号代码',
+        disabled: isEdit,
       },
     },
     !isEdit && {
@@ -135,6 +144,15 @@ const items = computed<EpFormItem[]>(() => {
       slot: {
         showPassword: true,
         placeholder: '设置用户密码',
+        disabled: isEdit,
+      },
+    },
+    {
+      label: '姓名',
+      slotType: 'input',
+      prop: 'name',
+      slot: {
+        placeholder: '设置用户姓名',
       },
     },
     {

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

@@ -61,7 +61,7 @@ const columns: EpTableColumn<ExtractArrayValue<ExtractApiResponse<'getStatistics
   { align: 'center', label: '客观题0分量', prop: 'objectiveZero', width: usePX(84) },
   { align: 'center', label: '客观平均分', prop: 'objectiveAvg', width: usePX(76) },
   { align: 'center', label: '客观标准差', prop: 'objectiveStd', width: usePX(76) },
-  { align: 'center', label: '重评/待确认', prop: 'reMarkConfirmCount', width: usePX(106) },
+  { align: 'center', label: '重评/待确认', prop: 'reMarkUnConfirmCount', width: usePX(106) },
   { align: 'center', label: '抽查量', prop: 'checkCount', width: usePX(52) },
   { align: 'center', label: '抽查改正量', prop: 'checkCorrectCount', width: usePX(76) },
   { align: 'center', label: '相关系数', prop: 'xyRelate', width: usePX(64) },

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

@@ -82,7 +82,7 @@ const columns: EpTableColumn<ExtractArrayValue<ExtractApiResponse<'getStatistics
   { align: 'center', label: '客观题0分量', prop: 'objectiveZero', width: usePX(84) },
   { align: 'center', label: '客观平均分', prop: 'objectiveAvg', width: usePX(76) },
   { align: 'center', label: '客观标准差', prop: 'objectiveStd', width: usePX(76) },
-  { align: 'center', label: '重评/待确认', prop: 'reMarkConfirmCount', width: usePX(106) },
+  { align: 'center', label: '重评/待确认', prop: 'reMarkUnConfirmCount', width: usePX(106) },
   { align: 'center', label: '抽查量', prop: 'checkCount', width: usePX(52) },
   { align: 'center', label: '抽查改正量', prop: 'checkCorrectCount', width: usePX(76) },
   { align: 'center', label: '相关系数', prop: 'xyRelate', width: usePX(64) },

+ 6 - 1
src/modules/bootstrap/login/index.vue

@@ -116,7 +116,12 @@ function loginSuccess(loginInfo: ExtractApiResponse<'userLogin'>) {
   }
 }
 
-sessionStorage.clear()
+function initLogin() {
+  sessionStorage.clear()
+  mainStore.$reset()
+}
+
+initLogin()
 </script>
 
 <style scoped lang="scss">

+ 0 - 1
src/modules/example/ImageModify.vue

@@ -101,4 +101,3 @@ const { drawing, dataUrl } = useSetImgBg(imgOption)
   }
 }
 </style>
-convertColor

+ 42 - 20
src/modules/marking/mark/index.vue

@@ -65,9 +65,8 @@
 
 <script setup lang="ts" name="MarkingMark">
 /** 阅卷-正式评卷 */
-import { computed, nextTick, ref, watch } from 'vue'
+import { computed, nextTick, ref, watch, onBeforeUnmount } from 'vue'
 import { useRouter } from 'vue-router'
-import { debounce } from 'lodash-es'
 import { ElButton, ElRadioGroup, ElRadioButton, ElRadio, ElMessage } from 'element-plus'
 import { minus } from '@/utils/common'
 import { useSetImgBg } from '@/hooks/useSetImgBg'
@@ -96,7 +95,7 @@ const { push, replace } = useRouter()
 
 const { getSpentTime, resume } = useSpentTime()
 
-const CACHE_NUM = 3
+const CACHE_NUM = 2
 
 type TaskType = ExtractArrayValue<ExtractApiResponse<'getMarkingTask'>>['taskType'] | 'default' | 'remarking'
 
@@ -160,27 +159,50 @@ const historyTaskChange = (task: HistoryTaskType) => {
   })
 }
 
-const debounceGetMarkingTask = debounce(getMarkingTask, 5000)
+const setCurrentTask = () => {
+  currentTask.value = currentTaskPool.shift()
+  currentTaskType.value =
+    currentTask.value && markStatusIcon[currentTask.value.taskType] ? currentTask.value.taskType : 'FORMAL'
+}
+
+let refreshTimer: number | null = null
+
+onBeforeUnmount(() => {
+  if (refreshTimer) {
+    clearTimeout(refreshTimer)
+    refreshTimer = null
+  }
+})
+
+const refreshTaskPool = (force = false, isRefresh = false) => {
+  if (refreshTimer) {
+    clearTimeout(refreshTimer)
+  }
+  refreshTimer = window.setTimeout(
+    () => {
+      if (currentTaskPool.length < (isRefresh ? Number.MAX_SAFE_INTEGER : CACHE_NUM)) {
+        getMarkingTask().then((result) => {
+          if (result?.length) {
+            currentTaskPool[isRefresh ? 'unshift' : 'push'](...result)
+          }
+          if (currentTaskPool?.length && !currentTask.value) {
+            setCurrentTask()
+          }
+          refreshTaskPool()
+        })
+      }
+    },
+    force ? 0 : 5000
+  )
+}
 
 /**
  * @param force 即时更新任务
  * @param isRefresh 是否有插队任务
  */
 const getNextTask = (force = false, isRefresh = false) => {
-  currentTask.value = currentTaskPool.shift()
-  currentTaskType.value =
-    currentTask.value && markStatusIcon[currentTask.value.taskType] ? currentTask.value.taskType : 'FORMAL'
-  if (currentTaskPool.length < (isRefresh ? Number.MAX_SAFE_INTEGER : CACHE_NUM)) {
-    const getTaskApi = force ? getMarkingTask : debounceGetMarkingTask
-    getTaskApi()?.then((result) => {
-      if (result?.length) {
-        currentTaskPool[isRefresh ? 'push' : 'unshift'](...result)
-        if (currentTaskPool.length && !currentTask.value) {
-          getNextTask()
-        }
-      }
-    })
-  }
+  setCurrentTask()
+  refreshTaskPool(force, isRefresh)
 }
 
 /** 给分板 */
@@ -225,7 +247,7 @@ const onSubmit: InstanceType<typeof ScoringPanelWithConfirm>['onSubmit'] = async
       taskId: currentTask.value.taskId,
       taskType: currentTask.value.taskType,
     })
-    await getNextTask(true, submitResult.refresh)
+    await getNextTask(true, submitResult?.refresh)
   } catch (error) {
     console.error(error)
     scoringPanelVisible.value = true
@@ -262,7 +284,7 @@ const onSubmitProblem = async () => {
     taskId: currentTask.value.taskId,
     taskType: currentTask.value.taskType,
   })
-  await getNextTask(true, submitResult.refresh)
+  await getNextTask(true, submitResult?.refresh)
 }
 
 /** 提交问题卷 & 雷同卷 */

+ 3 - 6
src/modules/monitor/training-monitoring/index.vue

@@ -48,7 +48,7 @@
 import { computed } from 'vue'
 import { useRouter } from 'vue-router'
 import { ElButton, ElMessage } from 'element-plus'
-import { minus } from '@/utils/common'
+import { minus, isDefine } from '@/utils/common'
 import BaseForm from '@/components/element/BaseForm.vue'
 import BaseTable from '@/components/element/BaseTable.vue'
 import useVW from '@/hooks/useVW'
@@ -85,11 +85,8 @@ const columns = computed<EpTableColumn<TableDataType>[]>(() => {
         }
         const score = row.scoreList[i]
         const standardScore = standardScores[i]
-        return (
-          <span style={{ color: minus(score, standardScore) ? '#f00' : 'inherit' }}>
-            {diffShow.value ? minus(score, standardScore) : score}
-          </span>
-        )
+        const diff = isDefine(score) ? minus(score, standardScore) : ''
+        return <span style={{ color: diff ? '#f00' : 'inherit' }}>{diffShow.value ? diff : score}</span>
       },
     })) || []
   return [

+ 1 - 1
src/plugins/request/index.ts

@@ -6,7 +6,7 @@ import { logout } from '@/utils/shared'
 import useMainStore from '@/store/main'
 
 const toastError = (message?: string) => {
-  message && ElMessage.error(message)
+  message && ElMessage({ message, type: 'error', grouping: true })
 }
 
 const request = axios.create({