bzkf3 лет назад: 2
Родитель
Сommit
175dabb3a7
1 измененных файлов с 563 добавлено и 0 удалено
  1. 563 0
      src/pages/step/[id].vue

+ 563 - 0
src/pages/step/[id].vue

@@ -0,0 +1,563 @@
+<script setup lang="ts" generic="T extends any, O extends any">
+import request from '~/utils/request'
+// import { stepsMap } from '~/composables/steps'
+
+const props = defineProps<{
+  id: string
+}>()
+
+const ykl_id = props.id
+
+const server = (await request({
+  url: '/yzy/kmksyjlc/detail',
+  data: {
+    ykl_id,
+  },
+})).data.one_info
+
+const ykl_lc = Object.assign(JSON.parse(Object.assign(server.ykl_lc)), { ykl_id })
+console.log('ykl_lc : ', ykl_lc)
+sessionStorage.setItem('ykl_lc', JSON.stringify(ykl_lc))
+
+const stepsReactiveMap = reactive<unknown[][][]>(ykl_lc.processList)
+
+// 先上传后划块
+const steps = reactive(
+  ykl_lc.ykj_yjlc === '1'
+    ? [
+        {
+          title: '组卷考试',
+          children: [
+            {
+              title: '出题组卷',
+              children: [
+                { title: '章节知识点出题', optional: true, description: '选择相应的章节知识点从题库中选取题目组成试卷' },
+                { title: '智能出题', optional: true, description: '填写题型数量难易度等信息系统自动生成试卷' },
+                { title: '附件出题', optional: true, description: '根据上传附件试卷进行考试' },
+              ],
+            },
+            {
+              title: '预划考号区域',
+              children: [
+                { title: '预划考号区域', optional: false, description: '根据试题内容格式制作相应的答题卡样式' },
+                { title: '考场设置(可选)', optional: true, description: '根据学生考场分配情况上传' },
+              ],
+            },
+            {
+              title: '预划流程完成',
+              children: [
+                { title: '预划流程完成', optional: false, description: '试卷内容和答题卡已确认,可进行考试' },
+              ],
+            },
+          ],
+        },
+        {
+          title: '扫描',
+          children: [
+            {
+              title: '答题卡扫描',
+              children: [
+                { title: '连接扫描仪', optional: false, description: '启动客户端扫描学生答题卡并进行识别与上传' },
+              ],
+            },
+            {
+              title: '平台接收试卷确认',
+              children: [
+                { title: '平台接收试卷确认', optional: false, description: '时间及试题均接收并识别入库完成' },
+              ],
+            },
+            {
+              title: '制作答题卡',
+              children: [
+                { title: '制作答题卡', optional: false, description: '根据试题内容格式制作相应的答题卡样式' },
+              ],
+            },
+          ],
+        },
+        {
+          title: '制作扫描处理',
+          children: [
+            {
+              title: '答题卡二次扫描',
+              children: [
+                { title: '连接扫描仪', optional: false, description: '启动客户端二次扫描批阅试卷' },
+              ],
+            },
+            {
+              title: '平台接收试卷确认',
+              children: [
+                { title: '平台接收试卷确认', optional: false, description: '确认试卷已上传' },
+              ],
+            },
+          ],
+        },
+        {
+          title: '阅卷',
+          children: [
+            {
+              title: '批阅任务分配',
+              children: [
+                { title: '批阅任务分配', optional: false, description: '对阅卷老师分配批阅任务' },
+              ],
+            },
+            {
+              title: '阅卷',
+              children: [
+                { title: '阅卷', optional: false, description: '查看批阅进度查看我的批阅任务' },
+              ],
+            },
+          ],
+        },
+        {
+          title: '成绩',
+          children: [
+            {
+              title: '成绩发布',
+              children: [
+                { title: '成绩发布', optional: false, description: '成绩汇总发布到分析平台' },
+              ],
+            },
+            {
+              title: '修改成绩',
+              children: [
+                { title: '修改成绩', optional: false, description: '考试成绩发布后三天内可修改' },
+              ],
+            },
+            {
+              title: '考试关闭',
+              children: [
+                { title: '考试关闭', optional: false, description: '最后考试结束关闭考试' },
+              ],
+            },
+          ],
+        },
+      ]
+    : [
+        {
+          title: '组卷考试',
+          children: [
+            {
+              title: '出题组卷',
+              children: [
+                { title: '章节知识点出题', optional: true, description: '选择相应的章节知识点从题库中选取题目组成试卷' },
+                { title: '智能出题', optional: true, description: '填写题型数量难易度等信息系统自动生成试卷' },
+                { title: '附件出题', optional: true, description: '根据上传附件试卷进行考试' },
+              ],
+            },
+            {
+              title: '制作答题卡',
+              children: [
+                { title: '制作答题卡', optional: false, description: '根据试题内容格式制作相应的答题卡样式' },
+                { title: '考场设置(可选)', optional: true, description: '根据学生考场分配情况上传' },
+              ],
+            },
+            {
+              title: '组卷流程完成',
+              children: [
+                { title: '组卷流程完成', optional: false, description: '试卷内容和答题卡已确认,可进行考试' },
+              ],
+            },
+          ],
+        },
+        {
+          title: '扫描',
+          children: [
+            {
+              title: '答题卡扫描',
+              children: [
+                { title: '连接扫描仪', optional: false, description: '启动客户端扫描学生答题卡并进行识别与上传' },
+              ],
+            },
+            {
+              title: '平台接收试卷确认',
+              children: [
+                { title: '平台接收试卷确认', optional: false, description: '时间及试题均接收并识别入库完成' },
+              ],
+            },
+
+          ],
+        },
+        {
+          title: '阅卷',
+          children: [
+            {
+              title: '批阅任务分配',
+              children: [
+                { title: '批阅任务分配', optional: false, description: '对阅卷老师分配批阅任务' },
+              ],
+            },
+            {
+              title: '阅卷',
+              children: [
+                { title: '阅卷', optional: false, description: '查看批阅进度查看我的批阅任务' },
+              ],
+            },
+          ],
+        },
+        {
+          title: '成绩',
+          children: [
+            {
+              title: '成绩发布',
+              children: [
+                { title: '成绩发布', optional: false, description: '成绩汇总发布到分析平台' },
+              ],
+            },
+            {
+              title: '修改成绩',
+              children: [
+                { title: '修改成绩', optional: false, description: '考试成绩发布后三天内可修改' },
+              ],
+            },
+            {
+              title: '考试关闭',
+              children: [
+                { title: '考试关闭', optional: false, description: '最后考试结束关闭考试' },
+              ],
+            },
+          ],
+        },
+      ],
+)
+
+let gid = $ref<number>(0)
+let pids = $ref<number[]>([])
+// const cid = $ref(-1)
+function getGid() {
+  return stepsReactiveMap.findLastIndex(item => item.some(subItem => subItem.some(subSubItem => judgeStepCompleted(subSubItem))))
+}
+
+function getPids() {
+  return stepsReactiveMap.map((item, idx) => (idx < gid ? 1 : 0) + item.findLastIndex(subItem => subItem.some(subSubItem => judgeStepCompleted(subSubItem))))
+}
+watch(() => stepsReactiveMap, (val) => {
+  gid = getGid()
+  pids = getPids()
+}, {
+  immediate: true,
+  deep: true,
+})
+
+let currentStep = $ref<number>(gid)
+
+const CardsRef = $shallowRef<Array<Array<typeof import('~/components/TheCard.vue')['default']>>>([])
+const lineList: any[][][] = []
+
+// onMounted(() => {
+//   CardsRef.forEach((cards, idx) => {
+//     if (idx === CardsRef.length - 1)
+//       return
+//     cards.forEach((card, idy) => {
+//       const line = new LeaderLine(
+//         card.getDom(),
+//         CardsRef[idx + 1][0].getDom(),
+//         {
+//           path: 'grid',
+//           endPlug: 'behind',
+//           size: 6,
+//           startSocket: 'right',
+//           endSocket: 'left',
+//           color: stepsReactiveMap[currentStep][idx][idy] ? '#003eee' : '#a3a3a3',
+//         },
+//       )
+//       lineList.push(line)
+//     })
+//   })
+// })
+
+function handleSwitchGid(id: number) {
+  currentStep = id
+}
+
+onMounted(() => {
+  watch(() => currentStep, (val, old) => {
+    if (old !== undefined)
+      lineList[old].forEach(lines => lines.forEach(line => line?.hide('none')))
+    if (lineList[val]?.length) {
+      lineList[val].forEach(lines => lines.forEach(line => line?.show('none')))
+    }
+    else {
+      nextTick(() => {
+        CardsRef.forEach((cards, idx) => {
+          if (idx === CardsRef.length - 1)
+            return
+          cards.forEach((card, idy) => {
+            if (card === null || CardsRef[idx + 1][0] === null)
+              return
+            const line = new LeaderLine(
+              card.getDom(),
+              CardsRef[idx + 1][0].getDom(),
+              {
+                path: 'grid',
+                endPlug: 'behind',
+                size: 6,
+                startSocket: 'right',
+                endSocket: 'left',
+                color: stepsReactiveMap[currentStep][idx][idy] ? '#003eee' : '#a3a3a3',
+              },
+            )
+            line?.position()
+            if (stepsReactiveMap[currentStep][idx][idy])
+              document.querySelectorAll('.leader-line')[line._id as number - 1]?.classList.add('z10')
+
+            lineList[val] = lineList[val] || []
+            lineList[val][idx] = lineList[val][idx] || []
+            lineList[val][idx][idy] = line
+          })
+        })
+      })
+    }
+  }, {
+    immediate: true,
+  })
+})
+
+const router = useRouter()
+
+function routerPush(path: string) {
+  router.push(path)
+}
+function windowPushState(path: string) {
+  window.open(`${location.origin}/${path}`, '_self')
+}
+
+function handleValidTask(currentStep: number, idx: number, idy: number) {
+  let lastIdx = idx
+  let lastStep = currentStep
+  const lastTasks = idx > 0 ? stepsReactiveMap[currentStep][lastIdx = idx - 1] : currentStep > 0 ? stepsReactiveMap[lastStep = currentStep - 1][lastIdx = stepsReactiveMap[currentStep - 1].length - 1] : []
+
+  if (lastTasks.every((item, idz) => {
+    if (steps[lastStep].children[lastIdx].children[idz].optional)
+      return true
+    else
+      return !!item
+  })) {
+    sessionStorage.setItem('StepId', JSON.stringify({ gid: currentStep, pid: idx, cid: idy }))
+    return true
+  }
+  else {
+    ElMessage({
+      message: '请先完成之前的任务',
+      type: 'warning',
+      grouping: true,
+    })
+    return false
+  }
+}
+
+function beforeClickTask(gid: number, pid: number, idy: number) {
+  const continueDoTask = true
+  if (!continueDoTask) {
+    ElMessage({
+      message: '无权操作',
+      type: 'warning',
+      grouping: true,
+    })
+  }
+  else {
+    return handleValidTask(gid, pid, idy)
+  }
+  return continueDoTask
+}
+
+function judgeTaskCanClick(gid: number, pid: number, idy: number) {
+  const continueDoTask = true
+  if (!continueDoTask) {
+    return false
+  }
+  else {
+    let lastIdx = pid
+    let lastStep = currentStep
+    const lastTasks = pid > 0 ? stepsReactiveMap[currentStep][lastIdx = pid - 1] : currentStep > 0 ? stepsReactiveMap[lastStep = currentStep - 1][lastIdx = stepsReactiveMap[currentStep - 1].length - 1] : []
+
+    if (lastTasks.every((item, idz) => {
+      if (steps[lastStep].children[lastIdx].children[idz].optional)
+        return true
+      else
+        return !!item
+    }))
+      return true
+    else
+      return false
+  }
+}
+
+function judgeStepCompleted(val: unknown) {
+  return (!!val) || (typeof val === 'object' && !!(val?.value))
+}
+
+function handleCompleteTask(gid: number, pid: number, cid: number, val?: unknown) {
+  const _ykl_lc_ = JSON.parse(sessionStorage.getItem('ykl_lc')!)
+  _ykl_lc_.processList[gid][pid][cid] = val || 1
+  request({
+    url: '/yzy/kmksyjlc/save',
+    data: {
+      ykl_id,
+      yk: {
+        ykl_lc: JSON.stringify(_ykl_lc_),
+      },
+    },
+  }).then((res) => {
+    if (res.code === '1') {
+      ElMessage({
+        message: '操作成功',
+        type: 'success',
+        grouping: true,
+      })
+      sessionStorage.setItem('ykl_lc', JSON.stringify(_ykl_lc_))
+
+      stepsReactiveMap[gid][pid][cid] = val || 1
+    }
+  }).catch(() => {
+    ElMessage({
+      message: '操作失败',
+      type: 'error',
+      grouping: true,
+    })
+  })
+}
+
+function handleJumpTask(gid: number, pid: number, idy: number) {
+  if (judgeStepCompleted(stepsReactiveMap[gid][pid][idy])) {
+    return ElMessage({
+      message: '该任务已完成',
+      type: 'warning',
+      grouping: true,
+    })
+  }
+  // stepsReactiveMap[gid][pid][idy] = 1
+  handleCompleteTask(gid, pid, idy)
+  if (pid === stepsReactiveMap[gid].length - 1)
+    return
+  const line = lineList[gid][pid][idy]
+  line.setOptions({ color: '#003eee' })
+  document.querySelectorAll('.leader-line')[line._id - 1]?.classList.add('z10')
+}
+
+onBeforeRouteLeave(() => {
+  lineList.forEach(lines => lines.forEach(line => line.forEach(l => l?.hide('none'))))
+})
+
+function handleCompleteTaskAuto() {
+  const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
+  handleJumpTask(gid, pid, cid)
+}
+
+const TaskEventMap: { [key: string]: () => void } = {
+  考试关闭: () => {
+    ElMessageBox({
+      title: '提示',
+      message: '确定要关闭考试吗?',
+      type: 'warning',
+      showCancelButton: true,
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+    }).then(() => {
+      const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
+      handleJumpTask(gid, pid, cid)
+    })
+  },
+}
+</script>
+
+<template>
+  <div class="w-full min-h-screen flex flex-col bg-white">
+    <NavHeader />
+    <bread-crumb />
+    <div class="flex-auto w-1200px m-auto">
+      <div class="flex flex-auto justify-start divide-x-4 divide-blue-700">
+        <div class="h-full w-220px">
+          <el-steps direction="vertical" :active="gid">
+            <el-step
+              v-for="({ title, children }, idx) in steps" :key="title" class="cursor-pointer hover:bg-light-600"
+              :class="idx === currentStep && 'bg-light-400'" @click="handleSwitchGid(idx)"
+            >
+              <template #title>
+                <div class="mb-4 font-normal">
+                  {{ title }}
+                </div>
+              </template>
+              <template #description>
+                <el-steps direction="vertical" :space="40" :active="pids[idx]">
+                  <el-step v-for="({ title }) in children" :key="title">
+                    <template #title>
+                      <div class="font-normal">
+                        {{ title }}
+                      </div>
+                    </template>
+                  </el-step>
+                </el-steps>
+              </template>
+            </el-step>
+          </el-steps>
+        </div>
+        <div class="flex-auto p-4">
+          <!-- <div ref="Ref1" class="Ref1" h-10 w-10 bg-red-500 />
+      <div ref="Ref2" class="Ref2" mt-100 h-10 w-10 bg-red-500 /> -->
+          <div class="h-full flex justify-between">
+            <div
+              v-for="(step, idx) in steps[currentStep].children " :key="idx"
+              class="h-full flex flex-col justify-evenly"
+            >
+              <the-card
+                v-for="(task, idy) in step.children " :key="idy"
+                :ref="el => { CardsRef[idx] = CardsRef[idx] || []; CardsRef[idx][idy] = el as any }" :title="task.title"
+                :description="task.description" :completed="judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy])"
+              >
+                <template #operate>
+                  <template v-if="task.title === '预划考号区域'">
+                    <div
+                      class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
+                      @click="beforeClickTask(currentStep, idx, idy) && windowPushState('/dtk/index.html')"
+                    >
+                      {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy]) ? '已经完成' : '立即开始' }}
+                    </div>
+                    <div
+                      class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
+                      @click="beforeClickTask(currentStep, idx, idy) && handleJumpTask(currentStep, idx, idy)"
+                    >
+                      {{ '跳过' }}
+                    </div>
+                  </template>
+                  <template v-else>
+                    <div
+                      class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
+                      @click="beforeClickTask(currentStep, idx, idy) && (TaskEventMap[task.title] ? TaskEventMap[task.title]() : handleCompleteTaskAuto())"
+                    >
+                      {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy]) ? '已经完成' : '立即开始' }}
+                    </div>
+                  </template>
+                </template>
+
+                <template #tip>
+                  <template v-if="task.title === '成绩发布'">
+                    <div class="mt-2 flex flex-col items-start px-1 text-xs space-y-1" style="--el-font-size-base:10px">
+                      <xgstda :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
+                      <szcjckqx :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
+                      <bjqk :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
+                    </div>
+                  </template>
+                </template>
+              </the-card>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <commonFooter />
+  </div>
+</template>
+
+<style scoped>
+:deep(.el-step:last-of-type .el-step__line) {
+  display: block;
+}
+
+:deep(.el-step__description .el-step:last-of-type .el-step__line) {
+  display: none;
+}
+
+.z10 {
+  z-index: 10;
+}
+</style>