Ver código fonte

课程目标成绩管理

zhangjie 1 ano atrás
pai
commit
04661fdd9d

+ 0 - 4
src/constants/enumerate.js

@@ -239,10 +239,6 @@ export const IMPORT_TEMPLATE_TYPE = {
   examStatistics: "TEMPLATE_EXAM_STATISTICS",
   // 课程知识点
   courseProperty: "COURSE_PROPERTY",
-  // 平时成绩
-  normalScore: "NORMAL_SCORE",
-  // 期末成绩
-  endScore: "END_SCORE",
 };
 // 印刷 -------------->
 // 印刷计划状态

+ 7 - 0
src/modules/course/api.js

@@ -60,6 +60,13 @@ export const endScoreEnable = ({ id, enable }) => {
     enable,
   });
 };
+// 成绩管理-试卷蓝图详情
+export const endScorePaperPositiveDetail = (datas) => {
+  return $post(
+    "/api/admin/course/degree/score/end_exam/paper_positive/query",
+    datas
+  );
+};
 // 成绩管理-保存试卷蓝图
 export const endScorePaperPositiveSave = (datas) => {
   return $post(

+ 49 - 10
src/modules/course/components/EndScoreManage.vue

@@ -10,10 +10,11 @@
     <div class="part-box part-box-pad">
       <el-table :data="dataList">
         <el-table-column type="index" label="序号" width="70"></el-table-column>
-        <el-table-column prop="targetName" label="姓名"></el-table-column>
-        <el-table-column prop="targetName" label="学号"></el-table-column>
-        <el-table-column prop="targetValue" label="成绩"> </el-table-column>
-        <el-table-column prop="targetValue" label="成绩明细"> </el-table-column>
+        <el-table-column prop="examStudentName" label="姓名"></el-table-column>
+        <el-table-column prop="examNumber" label="学号"></el-table-column>
+        <el-table-column prop="score" label="成绩"> </el-table-column>
+        <el-table-column prop="scoreDetailContent" label="成绩明细">
+        </el-table-column>
         <el-table-column class-name="action-column" label="操作" width="120px">
           <template slot-scope="scope">
             <el-button
@@ -45,22 +46,30 @@
       title="导入期末成绩"
       :upload-url="uploadUrl"
       :format="['xls', 'xlsx']"
-      :download-handle="() => downloadTemplate('endScore')"
+      :download-handle="downloadHandle"
       :download-filename="dfilename"
       :auto-upload="false"
       @upload-success="getList"
     ></import-file>
+    <!-- SetBlueDialog -->
+    <set-blue-dialog ref="SetBlueDialog" :course="course"> </set-blue-dialog>
   </div>
 </template>
 
 <script>
-import { endScoreListPage, endScoreEnable } from "../api";
+import {
+  endScoreListPage,
+  endScoreEnable,
+  endScoreTemplateDownload,
+} from "../api";
 import ModifyEndScore from "./ModifyEndScore.vue";
+import SetBlueDialog from "./SetBlueDialog.vue";
 import ImportFile from "@/components/ImportFile.vue";
+import { downloadByApi } from "@/plugins/download";
 
 export default {
   name: "end-score-manage",
-  components: { ModifyEndScore, ImportFile },
+  components: { ModifyEndScore, SetBlueDialog, ImportFile },
   props: {
     course: {
       type: Object,
@@ -84,6 +93,7 @@ export default {
       // import
       uploadUrl: "/api/admin/course/degree/score/end_exam/import",
       dfilename: "期末成绩导入模板.xlsx",
+      downloading: false,
     };
   },
   mounted() {
@@ -98,7 +108,17 @@ export default {
         pageSize: this.size,
       };
       const data = await endScoreListPage(datas);
-      this.dataList = data.records;
+      this.dataList = data.records.map((item) => {
+        const nitem = { ...item };
+        if (item.scoreDetail) {
+          nitem.scoreDetail = JSON.parse(item.scoreDetail);
+          nitem.scoreDetailContent = nitem.scoreDetail
+            .map((item) => item.score)
+            .join();
+        }
+
+        return nitem;
+      });
       this.total = data.total;
     },
     toPage(page) {
@@ -109,12 +129,31 @@ export default {
       this.$refs.ImportFile.open();
     },
     toSetBlue() {
-      // TODO:
+      this.$refs.SetBlueDialog.open();
     },
     toEdit(row) {
       this.curRow = { ...row };
       this.$refs.ModifyEndScore.open();
-      // TODO:
+    },
+    async downloadHandle() {
+      if (this.downloading) return;
+      this.downloading = true;
+
+      const res = await downloadByApi(() => {
+        const datas = {
+          examId: this.course.examId,
+          courseCode: this.course.courseCode,
+          paperNumber: this.course.paperNumber,
+          paperType: this.course.paperType,
+        };
+        return endScoreTemplateDownload(datas);
+      }).catch((e) => {
+        this.$message.error(e || "下载失败,请重新尝试!");
+      });
+      this.downloading = false;
+
+      if (!res) return;
+      this.$message.success("下载成功!");
     },
     async toEnable(row) {
       const action = row.enable ? "禁用" : "启用";

+ 117 - 3
src/modules/course/components/ModifyEndScore.vue

@@ -1,13 +1,127 @@
 <template>
-  <div class="ModifyEndScore">ModifyEndScore</div>
+  <el-dialog
+    :visible.sync="modalIsShow"
+    title="期末成绩编辑"
+    top="10vh"
+    width="550px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @open="visibleChange"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :key="modalForm.id"
+      label-width="100px"
+    >
+      <el-form-item label="考生姓名:">
+        {{ modalForm.examStudentName }}
+      </el-form-item>
+      <el-form-item label="考生学号:">
+        {{ modalForm.examNumber }}
+      </el-form-item>
+      <el-form-item label="成绩:">
+        {{ totalScore }}
+      </el-form-item>
+      <el-form-item
+        v-for="(item, index) in modalForm.scoreDetail"
+        :key="index"
+        :label="`${item.name}:`"
+        :prop="`scoreDetail.${index}.score`"
+        :rules="{
+          required: true,
+          message: '分数不能为空',
+          trigger: 'change',
+        }"
+      >
+        <el-input-number
+          v-model="item.score"
+          class="width-80"
+          size="small"
+          :min="0"
+          :max="1000"
+          :step="0.01"
+          step-strictly
+          :controls="false"
+        >
+        </el-input-number>
+      </el-form-item>
+    </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 { calcSum, deepCopy } from "@/plugins/utils";
+import { endScoreSave } from "../api";
+
+const initModalForm = {
+  id: null,
+  examStudentName: "",
+  examNumber: "",
+  score: "",
+  scoreDetail: [],
+};
+
 export default {
   name: "ModifyEndScore",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
   data() {
-    return {};
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: { ...initModalForm },
+    };
+  },
+  computed: {
+    totalScore() {
+      return calcSum(this.modalForm.scoreDetail.map((item) => item.score || 0));
+    },
+  },
+  methods: {
+    visibleChange() {
+      this.modalForm = this.$objAssign(initModalForm, this.instance);
+      this.modalForm.scoreDetail = deepCopy(this.instance.scoreDetail);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const datas = {
+        id: this.modalForm.id,
+        score: this.totalScore,
+        scoreDetail: JSON.stringify(this.modalForm.scoreDetail),
+      };
+      const data = await endScoreSave(datas).catch(() => {});
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success("修改成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
   },
-  methods: {},
 };
 </script>

+ 109 - 3
src/modules/course/components/ModifyNormalScore.vue

@@ -1,13 +1,119 @@
 <template>
-  <div class="ModifyNormalScore">ModifyNormalScore</div>
+  <el-dialog
+    :visible.sync="modalIsShow"
+    title="平时成绩编辑"
+    top="10vh"
+    width="550px"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @open="visibleChange"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :key="modalForm.id"
+      label-width="100px"
+    >
+      <el-form-item label="考生姓名:">
+        {{ modalForm.examStudentName }}
+      </el-form-item>
+      <el-form-item label="考生学号:">
+        {{ modalForm.examNumber }}
+      </el-form-item>
+      <el-form-item
+        v-for="(item, index) in modalForm.normalScore"
+        :key="index"
+        :label="`${item.name}:`"
+        :prop="`normalScore.${index}.score`"
+        :rules="{
+          required: true,
+          message: '分数不能为空',
+          trigger: 'change',
+        }"
+      >
+        <el-input-number
+          v-model="item.score"
+          class="width-80"
+          size="small"
+          :min="0"
+          :max="1000"
+          :step="0.01"
+          step-strictly
+          :controls="false"
+        >
+        </el-input-number>
+      </el-form-item>
+    </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 { deepCopy } from "@/plugins/utils";
+import { normalScoreSave } from "../api";
+
+const initModalForm = {
+  id: null,
+  examStudentName: "",
+  examNumber: "",
+  normalScore: [],
+};
+
 export default {
   name: "ModifyNormalScore",
+  props: {
+    instance: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
   data() {
-    return {};
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      modalForm: { ...initModalForm },
+    };
+  },
+  methods: {
+    visibleChange() {
+      this.modalForm = this.$objAssign(initModalForm, this.instance);
+      this.modalForm.normalScore = deepCopy(this.instance.normalScore);
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    async submit() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const datas = {
+        id: this.modalForm.id,
+        scoreNormal: JSON.stringify({
+          normalScore: this.modalForm.normalScore,
+        }),
+      };
+      const data = await normalScoreSave(datas).catch(() => {});
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success("修改成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
   },
-  methods: {},
 };
 </script>

+ 55 - 9
src/modules/course/components/NormalScoreManage.vue

@@ -9,10 +9,15 @@
     <div class="part-box part-box-pad">
       <el-table :data="dataList">
         <el-table-column type="index" label="序号" width="70"></el-table-column>
-        <el-table-column prop="targetName" label="姓名"></el-table-column>
-        <el-table-column prop="targetName" label="学号"></el-table-column>
-        <el-table-column prop="targetValue" label="毕业要求指标">
-        </el-table-column>
+        <el-table-column prop="examStudentName" label="姓名"></el-table-column>
+        <el-table-column prop="examNumber" label="学号"></el-table-column>
+        <template v-for="(item, index) in normalScoreItems">
+          <el-table-column :key="index" :label="item">
+            <template slot-scope="scope">
+              {{ scope.row.normalScore[index].score }}
+            </template>
+          </el-table-column>
+        </template>
         <el-table-column class-name="action-column" label="操作" width="120px">
           <template slot-scope="scope">
             <el-button
@@ -44,7 +49,7 @@
       title="导入平时成绩"
       :upload-url="uploadUrl"
       :format="['xls', 'xlsx']"
-      :download-handle="() => downloadTemplate('normalScore')"
+      :download-handle="downloadHandle"
       :download-filename="dfilename"
       :auto-upload="false"
       @upload-success="getList"
@@ -53,9 +58,14 @@
 </template>
 
 <script>
-import { normalScoreListPage, normalScoreEnable } from "../api";
+import {
+  normalScoreListPage,
+  normalScoreEnable,
+  scoreTemplateDownload,
+} from "../api";
 import ModifyNormalScore from "./ModifyNormalScore.vue";
 import ImportFile from "@/components/ImportFile.vue";
+import { downloadByApi } from "@/plugins/download";
 
 export default {
   name: "normal-score-manage",
@@ -80,9 +90,11 @@ export default {
       total: 0,
       dataList: [],
       curRow: {},
+      normalScoreItems: [],
       // import
       uploadUrl: "/api/admin/course/degree/score/import",
       dfilename: "平时成绩导入模板.xlsx",
+      downloading: false,
     };
   },
   mounted() {
@@ -97,21 +109,55 @@ export default {
         pageSize: this.size,
       };
       const data = await normalScoreListPage(datas);
-      this.dataList = data.records;
+      this.dataList = data.records.map((item) => {
+        const nitem = { ...item };
+        if (!item.scoreNormal) {
+          nitem.normalScore = [];
+          return nitem;
+        }
+
+        const { normalScore } = JSON.parse(item.scoreNormal);
+        nitem.normalScore = normalScore;
+        return nitem;
+      });
       this.total = data.total;
+
+      const scoreNormal = this.dataList[0]?.scoreNormal;
+      if (scoreNormal) {
+        const { normalScore } = JSON.parse(scoreNormal);
+        this.normalScoreItems = normalScore.map((item) => item.name);
+      }
     },
     toPage(page) {
       this.current = page;
       this.getList();
     },
     toImport() {
-      // TODO:
       this.$refs.ImportFile.open();
     },
     toEdit(row) {
       this.curRow = { ...row };
       this.$refs.ModifyNormalScore.open();
-      // TODO:
+    },
+    async downloadHandle() {
+      if (this.downloading) return;
+      this.downloading = true;
+
+      const res = await downloadByApi(() => {
+        const datas = {
+          examId: this.course.examId,
+          courseCode: this.course.courseCode,
+          paperNumber: this.course.paperNumber,
+          paperType: this.course.paperType,
+        };
+        return scoreTemplateDownload(datas);
+      }).catch((e) => {
+        this.$message.error(e || "下载失败,请重新尝试!");
+      });
+      this.downloading = false;
+
+      if (!res) return;
+      this.$message.success("下载成功!");
     },
     async toEnable(row) {
       const action = row.enable ? "禁用" : "启用";

+ 137 - 0
src/modules/course/components/SetBlueDialog.vue

@@ -0,0 +1,137 @@
+<template>
+  <div>
+    <el-dialog
+      :visible.sync="modalIsShow"
+      title="设置试卷蓝图"
+      top="10vh"
+      width="600px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      append-to-body
+      @open="visibleChange"
+    >
+      <el-table :data="dataList">
+        <el-table-column
+          prop="mainNumber"
+          label="大题号"
+          width="100px"
+        ></el-table-column>
+        <el-table-column
+          prop="subNumber"
+          label="小题号"
+          width="100px"
+        ></el-table-column>
+        <el-table-column prop="dimensions" label="知识点">
+          <template slot-scope="scope">
+            <p v-for="item in scope.row.dimensions" :key="item.dimensionId">
+              {{ item.dimensionName }}
+            </p>
+          </template>
+        </el-table-column>
+        <el-table-column class-name="action-column" label="操作" width="100px">
+          <template slot-scope="scope">
+            <el-button
+              class="btn-primary"
+              type="text"
+              @click="toLink(scope.row)"
+              >关联知识点</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div slot="footer">
+        <el-button type="primary" :disabled="isSubmit" @click="submit"
+          >确认</el-button
+        >
+        <el-button @click="cancel">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 设置知识点 -->
+    <select-dimension-dialog
+      ref="SelectDimensionDialog"
+      :course-code="course.courseCode"
+      :selected-data="curRow.catogoryIds"
+      @confirm="dimensionSelected"
+    ></select-dimension-dialog>
+  </div>
+</template>
+
+<script>
+import { endScorePaperPositiveDetail, endScorePaperPositiveSave } from "../api";
+import SelectDimensionDialog from "../../base/components/course-simple/SelectDimensionDialog.vue";
+
+export default {
+  name: "SetBlueDialog",
+  components: { SelectDimensionDialog },
+  props: {
+    course: {
+      type: Object,
+      default() {
+        return {};
+      },
+    },
+  },
+  data() {
+    return {
+      modalIsShow: false,
+      isSubmit: false,
+      dataList: [],
+      curRow: {},
+    };
+  },
+  methods: {
+    async getBlueDetail() {
+      const res = await endScorePaperPositiveDetail({
+        examId: this.course.examId,
+        courseCode: this.course.courseCode,
+        paperNumber: this.course.paperNumber,
+        paperType: this.course.paperType,
+      });
+      this.dataList = res || [];
+    },
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    checkData() {
+      return this.dataList.some(
+        (item) => !item.dimensionIds || !item.dimensionIds.length
+      );
+    },
+    toLink(row) {
+      this.curRow = row;
+      this.$refs.SelectDimensionDialog.open();
+    },
+    dimensionSelected(dimensions) {
+      this.curRow.dimensions = [...dimensions];
+      this.curRow.dimensionIds = dimensions.map((item) => item.dimensionId);
+    },
+    async submit() {
+      if (!this.checkData()) {
+        this.$message.error("还有小题未设置知识点,请完成设置!");
+        return;
+      }
+      if (this.isSubmit) return;
+      this.isSubmit = true;
+      const datas = {
+        examId: this.course.examId,
+        courseCode: this.course.courseCode,
+        paperNumber: this.course.paperNumber,
+        paperType: this.course.paperType,
+        paperDimension: JSON.stringify(this.dataList),
+      };
+      const data = await endScorePaperPositiveSave(datas).catch(() => {});
+      this.isSubmit = false;
+
+      if (!data) return;
+
+      this.$message.success("修改成功!");
+      this.$emit("modified");
+      this.cancel();
+    },
+  },
+};
+</script>