zhangjie 3 vuotta sitten
vanhempi
commit
bb308d5972

+ 17 - 0
src/constants/navs.js

@@ -102,6 +102,23 @@ const navs = [
             isRouter: true
           }
         ]
+      },
+      {
+        name: "阅卷管理",
+        url: "stmms",
+        icon: "el-icon-set-up",
+        children: [
+          {
+            name: "阅卷任务",
+            url: "MarkTaskManage",
+            isRouter: true
+          },
+          {
+            name: "成绩归档",
+            url: "ScoreArchive",
+            isRouter: true
+          }
+        ]
       }
     ]
   },

+ 3 - 0
src/modules/base/api.js

@@ -26,6 +26,9 @@ export const userBindRoles = ({ id, roleIds }) => {
 export const userRoleListPage = () => {
   return $postParam("/api/admin/sys/role/list_to_user", {});
 };
+export const syncUserToEcs = () => {
+  return $postParam("/api/admin/sys/user/async", {});
+};
 
 // role-manage
 export const roleListPage = datas => {

+ 25 - 1
src/modules/base/views/UserManage.vue

@@ -62,6 +62,14 @@
         </el-form-item>
       </el-form>
       <div class="part-box-action">
+        <el-button
+          v-if="!checkPrivilege('button', 'sync')"
+          type="primary"
+          icon="el-icon-refresh"
+          :loading="loading"
+          @click="syncUser"
+          >同步用户</el-button
+        >
         <el-button
           type="success"
           icon="el-icon-download"
@@ -172,7 +180,13 @@
 <script>
 import ModifyUser from "../components/ModifyUser";
 import { ABLE_TYPE } from "@/constants/enumerate";
-import { userListPage, ableUser, resetPwd, userRoleListPage } from "../api";
+import {
+  userListPage,
+  ableUser,
+  resetPwd,
+  userRoleListPage,
+  syncUserToEcs
+} from "../api";
 // import { logout } from "@/modules/login/api";
 import UploadButton from "../../../components/UploadButton";
 
@@ -195,6 +209,7 @@ export default {
       roles: [],
       users: [],
       curUser: {},
+      loading: false,
       // import
       uploadUrl: "/api/admin/sys/user/import",
       downloadUrl: "/temps/userTemplate.xlsx",
@@ -274,6 +289,15 @@ export default {
       // if (row.id !== userId) return;
       // this.toLogout();
     },
+    async syncUser() {
+      if (this.loading) return;
+      this.loading = true;
+      const res = await syncUserToEcs().catch(() => {});
+      this.loading = false;
+
+      if (!res) return;
+      this.$message.success("同步任务已经提交!");
+    },
     // async toLogout() {
     //   await logout();
     //   this.$ls.clear();

+ 8 - 0
src/modules/stmms/api.js

@@ -0,0 +1,8 @@
+import { $postParam, $post } from "@/plugins/axios";
+
+export const markTaskListPage = datas => {
+  return $postParam("/api/admin/sys/user/user_list", datas);
+};
+export const uploadPaperAndAnswer = datas => {
+  return $post("/api/admin/exam/structure/upload", datas);
+};

+ 100 - 0
src/modules/stmms/components/SelectFile.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="select-file" style="display: inline-block;">
+    <el-input
+      :style="{ width: inputWidth }"
+      v-model.trim="attachmentName"
+      :placeholder="placeholder"
+      readonly
+    ></el-input>
+    <el-upload
+      :action="uploadUrl"
+      :before-upload="() => false"
+      :show-file-list="false"
+      :disabled="disabled"
+      :on-change="fileChange"
+      style="display:inline-block;margin: 0 10px;"
+    >
+      <el-button type="primary" :disabled="disabled">选择</el-button>
+    </el-upload>
+  </div>
+</template>
+
+<script>
+import { fileMD5 } from "@/plugins/md5";
+
+export default {
+  name: "select-file",
+  props: {
+    inputWidth: {
+      type: String,
+      default: "340px"
+    },
+    placeholder: {
+      type: String,
+      default: "请选择文件"
+    },
+    format: {
+      type: Array,
+      default() {
+        return ["pdf"];
+      }
+    },
+    maxSize: {
+      type: Number,
+      default: 20 * 1024 * 1024
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      attachmentName: "",
+      uploadUrl: "",
+      errorMsg: ""
+    };
+  },
+  methods: {
+    checkFileFormat(fileType) {
+      const _file_format = fileType
+        .split(".")
+        .pop()
+        .toLocaleLowerCase();
+      if (!this.format.length) return true;
+
+      return this.format.some(
+        item => item.toLocaleLowerCase() === _file_format
+      );
+    },
+    async fileChange(file) {
+      console.log(file);
+      this.errorMsg = "";
+      this.attachmentName = "";
+
+      if (file.size > this.maxSize) {
+        this.errorMsg =
+          "文件大小不能超过" + Math.floor(this.maxSize / 1024) + "M";
+        this.$emit("file-change", { errorMsg: this.errorMsg });
+        return;
+      }
+
+      if (!this.checkFileFormat(file.name)) {
+        this.errorMsg = "只支持文件格式为" + this.format.join("/");
+        this.$emit("file-change", { errorMsg: this.errorMsg });
+        return;
+      }
+
+      this.attachmentName = file.name;
+      const md5 = await fileMD5(file.raw);
+      this.$emit("file-change", {
+        file: file.raw,
+        md5
+      });
+    },
+    setAttachmentName(name) {
+      this.attachmentName = name;
+    }
+  }
+};
+</script>

+ 184 - 0
src/modules/stmms/components/UploadPaperAnswerDialog.vue

@@ -0,0 +1,184 @@
+<template>
+  <el-dialog
+    class="upload-paper-answer-dialog"
+    :visible.sync="modalIsShow"
+    title="上传试卷结构文档/标答PDF文档"
+    top="10vh"
+    width="700px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @open="visibleChange"
+  >
+    <el-form ref="modalFormComp" :model="infos" label-width="80px">
+      <div v-for="paperType in paperTypes" :key="paperType" class="part-box">
+        <h3 class="part-box-title">{{ paperType }}</h3>
+        <el-form-item
+          v-for="(val, key) in fileTypes"
+          :key="key"
+          :prop="`${paperType}.${key}`"
+          :label="`${val.name}:`"
+          :rules="{
+            required: true,
+            validator: fileValidator,
+            trigger: 'change'
+          }"
+        >
+          <select-file
+            :format="val.format"
+            :disabled="isSubmit"
+            @file-change="data => fileChange(paperType, key, data)"
+          ></select-file>
+          <el-button
+            v-if="val.downloadUrl"
+            type="success"
+            icon="el-icon-download"
+          >
+            <a :href="val.downloadUrl" :download="val.downloadName">模板下载</a>
+          </el-button>
+        </el-form-item>
+      </div>
+    </el-form>
+    <div slot="footer">
+      <el-button type="primary" :disabled="isSubmit" @click="submit"
+        >确认</el-button
+      >
+      <el-button @click="cancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { uploadPaperAndAnswer } from "../api";
+import SelectFile from "./SelectFile.vue";
+
+// const files = {
+//   files: [
+//     {
+//       paperType: "A",
+//       subjectiveQuestionFile: "File",
+//       subjectiveQuestionMd5: "string",
+//       objectiveQuestionFile: "File",
+//       objectiveQuestionMd5: "string",
+//       standardAnswerFile: "File",
+//       standardAnswerMd5: "string"
+//     }
+//   ]
+// };
+
+export default {
+  name: "upload-paper-answer-dialog",
+  components: { SelectFile },
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      }
+    }
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      infos: {},
+      paperTypes: [],
+      fileTypes: {
+        subjectiveQuestion: {
+          name: "客观题",
+          downloadUrl: "111",
+          downloadName: "客观题结构.xlsx",
+          format: ["xlsx", "xls"]
+        },
+        objectiveQuestion: {
+          name: "主观题",
+          downloadUrl: "111",
+          downloadName: "主观题答案.xlsx",
+          format: ["xlsx", "xls"]
+        },
+        standardAnswer: {
+          name: "标答",
+          format: ["pdf"]
+        }
+      }
+    };
+  },
+  methods: {
+    initData() {
+      this.paperTypes = this.instance.paperType.split(",");
+      let infos = {};
+      this.paperTypes.forEach(paperType => {
+        let item = {};
+        Object.keys(this.fileTypes).map(typeKey => {
+          item[typeKey] = {
+            file: null,
+            md5: null,
+            errorMsg: null
+          };
+        });
+        infos[paperType] = item;
+      });
+      this.infos = infos;
+    },
+    visibleChange() {
+      this.initData();
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    fileChange(paperType, typeKey, data) {
+      if (data.errorMsg) {
+        this.infos[paperType][typeKey].file = null;
+        this.infos[paperType][typeKey].md5 = null;
+        this.infos[paperType][typeKey].errorMsg = data.errorMsg;
+      } else {
+        this.infos[paperType][typeKey].file = data.file;
+        this.infos[paperType][typeKey].md5 = data.md5;
+        this.infos[paperType][typeKey].errorMsg = null;
+      }
+      this.$refs.modalFormComp.validateField(`${paperType}.${typeKey}`);
+    },
+    fileValidator(rule, value, callback) {
+      const [paperType, typeKey] = rule.field.split(".");
+      const val = this.infos[paperType][typeKey];
+
+      if (val.errorMsg) {
+        return callback(new Error(val.errorMsg));
+      } else {
+        if (!val.file) {
+          return callback(new Error("请选择文件"));
+        }
+      }
+      callback();
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+
+      let formData = new FormData();
+      formData.append("id", this.instance.id);
+      Object.entries(this.infos).forEach(([paperType, vals], index) => {
+        const indexName = `files[${index}]`;
+        formData.append(`${indexName}.paperType`, paperType);
+        Object.keys(vals).forEach(typeKey => {
+          formData.append(`${indexName}.${typeKey}File`, vals[typeKey].file);
+          formData.append(`${indexName}.${typeKey}Md5`, vals[typeKey].md5);
+        });
+      });
+      const data = await uploadPaperAndAnswer(formData).catch(() => {});
+      this.isSubmit = false;
+      if (!data) return;
+
+      this.$message.success("上传成功!");
+      this.$emit("modified");
+      this.cancel();
+    }
+  }
+};
+</script>

+ 16 - 0
src/modules/stmms/router.js

@@ -0,0 +1,16 @@
+// print
+import MarkTaskManage from "./views/MarkTaskManage.vue";
+import ScoreArchive from "./views/ScoreArchive.vue";
+
+export default [
+  {
+    path: "/stmms/mark-task-manage",
+    name: "MarkTaskManage",
+    component: MarkTaskManage
+  },
+  {
+    path: "/stmms/score-archive",
+    name: "ScoreArchive",
+    component: ScoreArchive
+  }
+];

+ 117 - 0
src/modules/stmms/views/MarkTaskManage.vue

@@ -0,0 +1,117 @@
+<template>
+  <div class="mark-task-manage">
+    <div class="part-box part-box-filter part-box-flex">
+      <div></div>
+      <div class="part-box-action">
+        <el-button
+          v-if="!checkPrivilege('button', 'select')"
+          type="primary"
+          @click="toPage(1)"
+          >查询</el-button
+        >
+      </div>
+    </div>
+    <div class="part-box part-box-pad">
+      <el-table ref="TableList" :data="taskList">
+        <el-table-column prop="examId" label="考试ID"></el-table-column>
+        <el-table-column prop="examName" label="考试姓名"></el-table-column>
+        <el-table-column prop="enable" label="状态" width="100">
+          <template slot-scope="scope">
+            {{ scope.row.enable | enableFilter }}
+          </template>
+        </el-table-column>
+        <el-table-column class-name="action-column" label="操作" width="220px">
+          <template slot-scope="scope">
+            <el-button
+              v-if="!checkPrivilege('link', 'edit')"
+              class="btn-primary"
+              type="text"
+              @click="toUpload(scope.row)"
+              >上传试卷结构/标答</el-button
+            >
+            <el-button
+              v-if="!checkPrivilege('link', 'reset')"
+              class="btn-danger"
+              type="text"
+              @click="toMark(scope.row)"
+              >开始阅卷</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="part-page">
+        <el-pagination
+          background
+          layout="total,prev, pager, next"
+          :current-page="current"
+          :total="total"
+          :page-size="size"
+          @current-change="toPage"
+        >
+        </el-pagination>
+      </div>
+    </div>
+
+    <UploadPaperAnswerDialog
+      ref="UploadPaperAnswerDialog"
+      :instance="curTask"
+      @modified="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { markTaskListPage } from "../api";
+import UploadPaperAnswerDialog from "../components/UploadPaperAnswerDialog";
+
+export default {
+  name: "mark-task-manage",
+  components: { UploadPaperAnswerDialog },
+  data() {
+    return {
+      filter: {},
+      current: 1,
+      size: this.GLOBAL.pageSize,
+      total: 0,
+      taskList: [
+        {
+          id: "111",
+          examId: "111",
+          examName: "232323",
+          paperType: "A,B",
+          enable: false
+        }
+      ],
+      curTask: {}
+    };
+  },
+  mounted() {
+    // this.toPage(1);
+  },
+  methods: {
+    async getList() {
+      if (!this.checkPrivilege("list", "list")) return;
+      const datas = {
+        ...this.filter,
+        pageNumber: this.current,
+        pageSize: this.size
+      };
+      const data = await markTaskListPage(datas);
+      this.taskList = data.records;
+      this.total = data.total;
+    },
+    toPage(page) {
+      this.current = page;
+      this.getList();
+    },
+    toUpload(row) {
+      console.log(row);
+      this.curTask = row;
+      this.$refs.UploadPaperAnswerDialog.open();
+    },
+    toMark(row) {
+      console.log(row);
+    }
+  }
+};
+</script>

+ 15 - 0
src/modules/stmms/views/ScoreArchive.vue

@@ -0,0 +1,15 @@
+<template>
+  <div class="score-archive">
+    score-archive
+  </div>
+</template>
+
+<script>
+export default {
+  name: "score-archive",
+  data() {
+    return {};
+  },
+  methods: {}
+};
+</script>

+ 2 - 1
src/router.js

@@ -10,6 +10,7 @@ import base from "./modules/base/router";
 import exam from "./modules/exam/router";
 import print from "./modules/print/router";
 import customer from "./modules/customer/router";
+import stmms from "./modules/stmms/router";
 // card part
 import card from "./modules/card/router";
 // admin
@@ -41,7 +42,7 @@ let router = new Router({
       path: "/home/:nextRouter?",
       name: "Home",
       component: Home,
-      children: [...base, ...exam, ...print, ...customer]
+      children: [...base, ...exam, ...print, ...customer, ...stmms]
     },
     { ...login },
     { ...admin },

+ 1 - 1
src/views/Home.vue

@@ -216,7 +216,7 @@ export default {
     ...mapState("exam", ["waitTaskCount"])
   },
   created() {
-    this.getMenus();
+    this.getMenus1();
   },
   methods: {
     ...mapActions("exam", ["updateWaitTaskCount"]),