Bläddra i källkod

Merge branch 'master' into liua

* master:
  压缩包上传清空
  发布成绩修改参数
  教研员删除
  教研员设置
  方便测试调整:阅卷todo
la 2 år sedan
förälder
incheckning
19eaabe5da

+ 4 - 0
auto-imports.d.ts

@@ -12,6 +12,8 @@ declare global {
   const $shallowRef: typeof import('vue/macros')['$shallowRef']
   const $toRef: typeof import('vue/macros')['$toRef']
   const EffectScope: typeof import('vue')['EffectScope']
+  const ElMessage: typeof import('element-plus/es')['ElMessage']
+  const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
   const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
   const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
   const computed: typeof import('vue')['computed']
@@ -298,6 +300,8 @@ declare module 'vue' {
     readonly $shallowRef: UnwrapRef<typeof import('vue/macros')['$shallowRef']>
     readonly $toRef: UnwrapRef<typeof import('vue/macros')['$toRef']>
     readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
+    readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
+    readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
     readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
     readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
     readonly computed: UnwrapRef<typeof import('vue')['computed']>

+ 1 - 1
src/pages/process/index.vue

@@ -85,7 +85,7 @@
                   <span class="inline-block align-middle leading-28px">更多</span>
                   <div class="more-list">
                     <ul>
-                      <li :class="item.btn_check.btn_jyysz != '1'?'disabled':''">教研员设置</li>
+                      <li :class="item.btn_check.btn_jyysz != '1'?'disabled':''" @click="linkTo({name:'process-jyysz-ykj_id',params:{ykj_id:item.ykj_id}})">教研员设置</li>
                       <li :class="item.btn_check.btn_jsgzsz != '1'?'disabled':''" @click="editJfgz(item)">分数计算规则设置</li>
                       <li :class="item.btn_check.btn_smpyjd != '1'?'disabled':''" @click="linkTo({name:'process-smpyjd-ykj_id',params:{ykj_id:item.ykj_id}})">扫描批阅进度</li>
                       <li :class="item.btn_check.btn_ksfx != '1'?'disabled':''" @click="linkTo({name:'ksfx-cjfx_cjd-ykj_id',params:{ykj_id:item.ykj_id}})">考试分析</li>

+ 394 - 0
src/pages/process/jyysz/[ykj_id].vue

@@ -0,0 +1,394 @@
+<script setup>
+import request from "~/utils/request";
+import {REQUEST} from "~/utils/request";
+import {user} from "~/store";
+import {useRouter} from "vue-router";
+
+const router = useRouter();
+const route = useRoute();
+const linkTo = (obj) => {
+  router.push(obj);
+};
+let ykj_id = $ref('');
+let keyword = $ref('');
+let limit = $ref(10);
+let total = $ref(0);
+let cur_page = $ref(1);
+let listData = $ref([]);
+let dialogVisible = $ref(false);
+let title = $ref('');
+let is_edit = $ref(false);
+let project = $ref({})
+let subject = $ref([])
+let subject_list = $ref([])
+let teacher = $ref({
+  value: '',
+  label: '',
+  user_realname: ''
+})
+let yj_id = $ref('')
+let teacher_list = $ref([])
+
+function getListData() {
+  request({
+    url: "/yzy/jyy/index",
+    data: {
+      ykj_id: ykj_id,
+      keyword: keyword,
+      page: cur_page,
+      limit: limit
+    },
+  }).then((res) => {
+    if (res.code === '1') {
+      listData = res.data.page_data;
+      total = Number(res.data.total_rows);
+      cur_page = Number(res.data.page_now);
+    }
+  })
+}
+
+function getProjectInfo() {
+  let data = {
+    ykj_id: ykj_id
+  }
+  request({
+    url: "/yzy/ksjh/detail",
+    data: data,
+  }).then((res) => {
+    if (res.code === '1') {
+      project = res.data.one_info;
+      subject_list = project.lc;
+      gerUsers();
+    }
+  })
+}
+
+function filterData() {
+  cur_page = 1;
+  getListData();
+}
+
+const handleSelectionChange = (val) => {
+  cur_page = val;
+  getListData();
+};
+
+function addTeacher() {
+  is_edit = false;
+  subject = [];
+  title = '增加教研员';
+  dialogVisible = true;
+  teacher = {
+    value: '',
+    label: '',
+    user_realname: ''
+  }
+}
+
+function gerUsers() {
+  request({
+    url: window.GLOBAL_CONFIG.uc + "/user/main/index",
+    data: {
+      sm_id: project.ykj_lkxx,
+      user_role_id: user.user_role_id,
+      page: '1',
+      limit: '999'
+    },
+  }).then((res) => {
+    if (res.code === '1') {
+      teacher_list = res.data.page_data;
+    }
+  })
+}
+
+function editTeacher(item) {
+  is_edit = true;
+  title = '编辑教研员';
+  teacher = {
+    value:item.yj_user_id,
+    label:item.yj_username,
+    user_realname:item.yj_realname
+  }
+  yj_id = item.yj_id;
+  subject = [];
+  for(let i in item.yj_subject_id.split(',')) {
+    let obj = {
+      value:item.yj_subject_id.split(',')[i],
+      label:item.yj_subject_name.split(',')[i]
+    }
+    subject.push(obj)
+  }
+  dialogVisible = true;
+}
+function del_teacher(item) {
+  ElMessageBox.confirm("确认删除该教研员?", "", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+
+    request({
+      url: "/yzy/jyy/delete",
+      data: {
+        yj_id:item.yj_id
+      },
+    }).then((res) => {
+      if (res.code === "1") {
+        ElMessage({
+          type: "success",
+          message: "删除成功",
+        });
+        getListData();
+      }
+    });
+  })
+}
+function handleSubmit() {
+  let subject_ids = [];
+  let subject_names = [];
+  for (let i in subject) {
+    subject_ids.push(subject[i].value);
+    subject_names.push(subject[i].label);
+  }
+  if (!is_edit) {
+    request({
+
+      url: '/yzy/jyy/add',
+      data: {
+        issubmit: '1',
+        yzy_jyy: {
+          ykj_id: ykj_id,
+          yj_user_id: teacher.value,
+          yj_realname: teacher.user_realname,
+          yj_username: teacher.label,
+          yj_subject_id: subject_ids.join(','),
+          yj_subject_name: subject_names.join(',')
+        }
+      },
+    }).then((res) => {
+      if (res.code === '1') {
+        ElMessage.success("教研员添加成功!");
+        dialogVisible = false;
+        getListData();
+      }
+    })
+  } else {
+    request({
+
+      url: '/yzy/jyy/edit',
+      data: {
+        issubmit: '1',
+        yj_id:yj_id,
+        yzy_jyy: {
+          ykj_id: ykj_id,
+          yj_user_id: teacher.value,
+          yj_realname: teacher.user_realname,
+          yj_username: teacher.label,
+          yj_subject_id: subject_ids.join(','),
+          yj_subject_name: subject_names.join(',')
+        }
+      },
+    }).then((res) => {
+      if (res.code === '1') {
+        ElMessage.success("教研员编辑成功!");
+        dialogVisible = false;
+        getListData();
+      }
+    })
+  }
+
+}
+
+if (route.params.ykj_id) {
+  ykj_id = route.params.ykj_id;
+  getListData();
+  getProjectInfo();
+}
+</script>
+<route lang="json">
+{
+"meta":{
+"title":"教研员设置",
+"breadcrumb":true
+}
+}
+</route>
+<template>
+  <NavHeader/>
+  <bread-crumb/>
+  <div class="w-1200px m-auto">
+    <div class="relative -mt-40px flex justify-end">
+      <button type="button" class="back-btn" @click="linkTo({name:'process'})">返回</button>
+    </div>
+    <div class="mt-10px w-full bg-hex-fff min-h-700px py-20px px-15px">
+      <div class="flex align-center">
+        <el-input
+          v-model="keyword"
+          class="ml-20px"
+          style="width: 225px;"
+          size="large"
+          clearable
+          @keyup.enter="filterData"
+          @clear="filterData"
+          placeholder="请输入关键字"
+        />
+        <el-button color="#003eee" class="ml-10px" type="primary" size="large" @click="filterData">搜索</el-button>
+        <button type="button" class="ml-10px add-btn">
+          <el-icon class="inline-block align-middle">
+            <Plus/>
+          </el-icon>
+          <span class="ml-5px inline-block align-middle" @click="addTeacher">新增教研员</span>
+        </button>
+      </div>
+      <h3 class="mt-20px mb-10px text-13px text-hex-6F6F6F">(此处为查看扫描批阅进度的权限赋予设置)</h3>
+      <div v-if="listData.length > 0">
+        <table class="data-table" cellpadding="0" cellspacing="0">
+          <tr>
+            <th>教研员名称</th>
+            <th>教研员账号</th>
+            <th>权限科目</th>
+            <th>操作</th>
+          </tr>
+          <tr v-for="item in listData">
+            <td>{{ item.yj_realname }}</td>
+            <td>{{ item.yj_username }}</td>
+            <td>{{ item.yj_subject_name }}</td>
+            <td>
+              <button type="button" class="op-btn edit" @click="editTeacher(item)">编辑</button>
+              <button type="button" class="ml-15px op-btn del" @click="del_teacher(item)">删除</button>
+            </td>
+          </tr>
+        </table>
+        <div class="mt-20px page-new flex justify-end">
+          <el-pagination v-model:current-page="cur_page" v-model:page-size="limit" layout="total,prev, pager, next"
+                         :total="total" :background="true" @current-change="handleSelectionChange"></el-pagination>
+        </div>
+      </div>
+      <div v-else class="no-data">
+        <div>
+          <h3 class="no-data-img"></h3>
+          <h4 class="mt-25px text-18px text-hex-0048e5 text-center">暂无数据</h4>
+        </div>
+      </div>
+    </div>
+  </div>
+  <commonFooter/>
+  <el-dialog
+    v-model="dialogVisible"
+    :title="title"
+    width="500px"
+    append-to-body
+  >
+    <div>
+      <el-form label-width="120px" size="large">
+        <el-form-item label="教研员">
+          <el-select v-model="teacher" placeholder="请选择教研员" filterable style="width: 100%">
+            <el-option v-for="item in teacher_list" :label="item.user_realname+' '+ item.user_phone"
+                       :value="{value:item.user_id,label:item.user_name,user_realname:item.user_realname}"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="可查看学科">
+          <el-select v-model="subject" placeholder="请选择学科" multiple filterable style="width: 100%">
+            <el-option :value-key="item.ze_xueke" v-for="item in subject_list" :label="item.ze_xueke_name"
+                       :value="{value:item.ze_xueke,label:item.ze_xueke_name}"/>
+          </el-select>
+        </el-form-item>
+        <div class="mt-40px text-center">
+          <el-button class="mr-30px" @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" color="#003eee" :disabled="teacher.value === '' || subject.length === 0"
+                     @click="handleSubmit">确定
+          </el-button>
+        </div>
+      </el-form>
+    </div>
+  </el-dialog>
+</template>
+
+<style scoped lang="scss">
+$color: #0048e5;
+::v-deep .el-pagination.is-background .btn-next.is-active,
+::v-deep .el-pagination.is-background .btn-prev.is-active,
+::v-deep .el-pagination.is-background .el-pager li.is-active {
+  background-color: $color;
+}
+
+.add-btn {
+  width: 129px;
+  height: 40px;
+  background: #ffffff;
+  border: 1px solid $color;
+  border-radius: 4px;
+  font-size: 14px;
+  color: $color;
+  text-align: center;
+
+  .el-icon {
+    font-size: 16px;
+  }
+}
+
+.data-table {
+  width: 100%;
+  table-layout: fixed;
+
+  tr:nth-child(even) {
+    background: #F1F7FF;
+  }
+
+  th {
+    height: 50px;
+    background: $color;
+    font-weight: normal;
+    text-align: center;
+    font-size: 16px;
+    color: #fff;
+
+    &:first-child {
+      border-radius: 6px 0 0 0;
+    }
+
+    &:last-child {
+      border-radius: 0 6px 0 0;
+    }
+  }
+
+  td {
+    padding: 15px 0;
+    font-size: 16px;
+    color: #474747;
+    text-align: center;
+  }
+}
+
+.op-btn {
+  width: 56px;
+  height: 30px;
+  background: #ffffff;
+  font-size: 14px;
+  border-radius: 2px;
+
+  &.edit {
+    border: 1px solid $color;
+    color: $color;
+  }
+
+  &.del {
+    border: 1px solid #E50101;
+    color: #E50101;
+  }
+}
+
+.no-data {
+  width: 100%;
+  height: 450px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  .no-data-img {
+    width: 233px;
+    height: 199px;
+    background: url("/images/no-data.png") center no-repeat;
+  }
+}
+</style>

+ 30 - 1
src/pages/process/ysb/[ykl_id]/[ze_id].vue

@@ -30,6 +30,31 @@ function showDetail(item) {
    dialogVisible = true;
    detailData = item.detail;
 }
+function clearZip(item) {
+  ElMessageBox.confirm("确认执行清空操作?", "", {
+    confirmButtonText: "确认",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+
+    request({
+      url: "/yzy/scan/zip_clear",
+      data: {
+        ze_id:ze_id,
+        user_id:item.user_id
+      },
+    }).then((res) => {
+      if (res.code === "1") {
+        ElMessage({
+          type: "success",
+          message: "操作成功!",
+        });
+        dialogVisible = false;
+        getDetail();
+      }
+    });
+  })
+}
 if (route.params.ze_id) {
   ze_id = route.params.ze_id;
   ykl_id = route.params.ykl_id;
@@ -85,11 +110,15 @@ if (route.params.ze_id) {
           <th>姓名</th>
           <th>账号</th>
           <th>上传份数</th>
+          <th>操作</th>
         </tr>
         <tr v-for="item in detailData">
           <td>{{item.realname}}</td>
           <td>{{item.username}}</td>
           <td>{{item.zip_num}}</td>
+          <td>
+            <button type="button" class="op-btn" @click="clearZip(item)">清空压缩包</button>
+          </td>
         </tr>
       </table>
     </div>
@@ -151,10 +180,10 @@ $color: #0048e5;
   }
 }
 .op-btn {
-  width: 50px;
   height: 30px;
   background: #fff;
   border: 1px solid #003eee;
+  padding: 0 10px;
   border-radius: 2px;
   font-size: 14px;
   color: #003eee;

+ 53 - 27
src/pages/step/[id].vue

@@ -321,7 +321,7 @@ function routerPush(path: RouteLocationRaw) {
   router.push(path)
 }
 function windowPushState(path: string) {
-  // !未启用
+  // ! 未启用
   sessionStorage.setItem('historyLocation', location.href)
   window.open(`${location.origin}/${path}`, '_self')
   // location.replace(`${location.origin}/${path}`)
@@ -405,17 +405,36 @@ function judgeStepCompleted(val: unknown) {
   return (!!val) || (typeof val === 'object' && !!(val?.value))
 }
 
-function handleCompleteTask(gid: number, pid: number, cid: number, val?: unknown): Promise<any> {
+function handleCompleteTask(gid: number, pid: number, cid: number, val?: unknown, ext?: any): Promise<any> {
   const _ykl_lc_ = JSON.parse(sessionStorage.getItem('ykl_lc')!)
   _ykl_lc_.processList[gid][pid][cid] = val || 1
+  const reqData: any = {
+    ykl_id,
+    yk: {
+      ykl_lc: JSON.stringify(_ykl_lc_),
+    },
+  }
+  // 把ext上的属性合并到reqData上,考虑嵌套的情况
+  if (ext) {
+    Object.keys(ext).forEach((key) => {
+      if (typeof ext[key] === 'object') {
+        if (reqData[key]) {
+          reqData[key] = {
+            ...reqData[key],
+            ...ext[key],
+          }
+        }
+        else { reqData[key] = ext[key] }
+      }
+      else {
+        reqData[key] = ext[key]
+      }
+    })
+  }
+
   return request({
     url: '/yzy/kmksyjlc/save',
-    data: {
-      ykl_id,
-      yk: {
-        ykl_lc: JSON.stringify(_ykl_lc_),
-      },
-    },
+    data: reqData,
   }).then((res) => {
     if (res.code === '1') {
       ElMessage({
@@ -436,7 +455,7 @@ function handleCompleteTask(gid: number, pid: number, cid: number, val?: unknown
   })
 }
 
-async function handleJumpTask(gid: number, pid: number, idy: number) {
+async function handleJumpTask(gid: number, pid: number, idy: number, ext?: object) {
   // 验证任务是否完成
   if (judgeStepCompleted(stepsReactiveMap[gid][pid][idy])) {
     return ElMessage({
@@ -446,7 +465,7 @@ async function handleJumpTask(gid: number, pid: number, idy: number) {
     })
   }
   // stepsReactiveMap[gid][pid][idy] = 1
-  const res = await handleCompleteTask(gid, pid, idy)
+  const res = await handleCompleteTask(gid, pid, idy, 1, ext)
   if (res.code === '1') {
     if (pid !== stepsReactiveMap[gid].length - 1) {
       const line = lineList[gid][pid][idy]
@@ -461,9 +480,9 @@ onBeforeRouteLeave(() => {
   lineList.forEach(lines => lines.forEach(line => line.forEach(l => l?.hide('none'))))
 })
 
-function handleCompleteTaskAuto() {
+function handleCompleteTaskAuto(ext?: object) {
   const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
-  return handleJumpTask(gid, pid, cid)
+  return handleJumpTask(gid, pid, cid, ext)
 }
 
 const TaskEventMap: { [key: string]: () => void } = {
@@ -498,10 +517,10 @@ const TaskEventMap: { [key: string]: () => void } = {
     window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy},upload_papers`, '_blank')
     handleCompleteTaskAuto()
   },
-  '压缩包上传情况': () => {
-    // todo: 需调整【压缩包】上传情况
+  '压缩包上传情况': async () => {
+    await handleCompleteTaskAuto()
+    // TODO: 需调整【压缩包】上传情况
     routerPush(`/process/ysb/${ykl_lc.ykl_id}/${ykl_lc.ze_id}`)
-    handleCompleteTaskAuto()
   },
   '答题卡二次扫描': () => {
     window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy},review_papers`, '_blank')
@@ -519,7 +538,9 @@ const TaskEventMap: { [key: string]: () => void } = {
   '批阅任务分配': () => {
     windowPushState(`${window.GLOBAL_CONFIG.base}/taskassignment-liankao.html`)
   },
-  '阅卷': () => {
+  '阅卷': async () => {
+    await handleCompleteTaskAuto()
+    // todo: 需调整【阅卷】
     windowPushState(`${window.GLOBAL_CONFIG.base}/single-review-liankao.html?ze_id=${ykl_lc.ze_id}`)
   },
   '成绩发布': () => {
@@ -544,7 +565,7 @@ const TaskEventMap: { [key: string]: () => void } = {
             })
             if (res0.code !== '1')
               throw new Error(res0.msg)
-            const res1 = await handleCompleteTaskAuto()
+            const res1 = await handleCompleteTaskAuto({ force: 1 })
             if (res1.code !== '1')
               throw new Error(res1.msg)
             ykl_lc.ykl_stat_ready = 2
@@ -561,18 +582,23 @@ const TaskEventMap: { [key: string]: () => void } = {
           console.log('正常发布')
           instance.cancelButtonLoading = loading = true
           try {
-            const res0 = await request({
-              url: '/yzy/kmksyjlc/save',
-              data: {
-                ykl_id,
-                yk: {
-                  ykl_sffbcj: 1,
-                },
+            // const res0 = await request({
+            //   url: '/yzy/kmksyjlc/save',
+            //   data: {
+            //     ykl_id,
+            //     yk: {
+            //       ykl_sffbcj: 1,
+            //     },
+            //   },
+            // })
+            // if (res0.code !== '1')
+            //   throw new Error(res0.msg)
+            const res1 = await handleCompleteTaskAuto({
+              force: 1,
+              yk: {
+                ykl_sffbcj: 1,
               },
             })
-            if (res0.code !== '1')
-              throw new Error(res0.msg)
-            const res1 = await handleCompleteTaskAuto()
             if (res1.code !== '1')
               throw new Error(res1.msg)
             ykl_lc.ykl_stat_ready = 1