Ver Fonte

feat: 达成度分析

zhangjie há 10 meses atrás
pai
commit
0c5b8e8893

+ 60 - 0
src/components/base/GradeSelect.vue

@@ -0,0 +1,60 @@
+<template>
+  <el-select
+    v-model="selected"
+    :placeholder="placeholder"
+    filterable
+    :clearable="clearable"
+    :disabled="disabled"
+    @change="selectChange"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item"
+      :value="item"
+      :label="`${item}级`"
+    >
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+export default {
+  name: "grade-select",
+  props: {
+    disabled: { type: Boolean, default: false },
+    placeholder: { type: String, default: "请选择年级" },
+    value: { type: [Number, String], default: "" },
+    clearable: { type: Boolean, default: true },
+  },
+  data() {
+    return {
+      optionList: [],
+      selected: "",
+    };
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      },
+    },
+  },
+  created() {
+    this.getOptions();
+  },
+  methods: {
+    getOptions() {
+      const options = [];
+      for (let i = 24; i < 31; i++) {
+        options.push(i);
+      }
+      this.optionList = options;
+    },
+    selectChange() {
+      this.$emit("input", this.selected);
+      this.$emit("change", this.selected);
+    },
+  },
+};
+</script>

+ 2 - 1
src/components/base/TrainingPlanCourseSelect.vue

@@ -11,8 +11,9 @@
       v-for="item in optionList"
       :key="item.id"
       :value="item.id"
-      :label="item.name"
+      :label="`${item.name}(${item.code})`"
     >
+      <span>{{ `${item.name}(${item.code})` }}</span>
     </el-option>
   </el-select>
 </template>

+ 5 - 0
src/modules/target/api.js

@@ -215,6 +215,11 @@ export const targetStatisticsReport = (datas) => {
     responseType: "blob",
   });
 };
+export const targetStatisticsNormalScoreExport = (datas) => {
+  return $postParam("/api/admin/course/degree/report/export", datas, {
+    responseType: "blob",
+  });
+};
 export const targetStatisticsChangeCheck = (datas) => {
   return $postParam("/api/admin/course/degree/report/change", datas);
 };

+ 2 - 2
src/modules/target/components/course-examine/CourseExamineWeight.vue

@@ -20,11 +20,11 @@
               <el-input-number
                 v-model="scope.row.evaluationList[cindex].weight"
                 :disabled="scope.row.evaluationList[cindex].disabled"
-                class="width-50"
+                class="width-80"
                 size="small"
                 :min="0"
                 :max="100"
-                :step="1"
+                :step="0.01"
                 step-strictly
                 :controls="false"
                 @blur="weightChange(scope.$index, cindex)"

+ 4 - 2
src/modules/target/components/course-outline/CourseOutlineBase.vue

@@ -4,8 +4,10 @@
       <el-descriptions-item label="课程大纲名称">
         {{ rowData.outlineName }}
       </el-descriptions-item>
-      <el-descriptions-item label="课程名称">
-        {{ rowData.courseName }}
+      <el-descriptions-item label="课程(代码)">
+        {{ rowData.courseName | defaultFieldFilter }}({{
+          rowData.courseCode | defaultFieldFilter
+        }})
       </el-descriptions-item>
       <el-descriptions-item label="学分">
         {{ rowData.credit }}

+ 5 - 8
src/modules/target/components/course-outline/ModifyCourseOutline.vue

@@ -15,13 +15,6 @@
       :rules="rules"
       label-width="120px"
     >
-      <el-form-item prop="courseOutlineName" label="课程大纲名称:">
-        <el-input
-          v-model.trim="modalForm.courseOutlineName"
-          placeholder="课程大纲名称"
-          clearable
-        ></el-input>
-      </el-form-item>
       <el-form-item prop="cultureProgramId" label="所属培养方案:">
         <el-select
           v-model="modalForm.cultureProgramId"
@@ -59,8 +52,9 @@
             v-for="item in courses"
             :key="item.id"
             :value="item.id"
-            :label="item.name"
+            :label="`${item.name}(${item.code})`"
           >
+            <span>{{ `${item.name}(${item.code})` }}</span>
           </el-option>
         </el-select>
       </el-form-item>
@@ -97,6 +91,9 @@
         </el-select>
       </el-form-item>
     </el-form>
+    <p class="tips-info" style="padding-left: 20px">
+      说明:课程大纲名称系统会自动按培养方案名称+课程名称+课程大纲自动命名
+    </p>
     <div slot="footer">
       <el-button type="primary" :disabled="isSubmit" @click="submit"
         >确认</el-button

+ 133 - 49
src/modules/target/components/target-statistics/DetailTargetStatistics.vue

@@ -7,13 +7,20 @@
     :show-close="false"
     append-to-body
     fullscreen
-    @opened="initData"
+    @opened="dialogOpend"
+    @close="dialogClose"
   >
     <div slot="title" class="box-justify">
       <div>
         <span>{{ course.courseName }}</span>
       </div>
       <div>
+        <el-button
+          type="primary"
+          :loading="downloading"
+          @click="toExportNormalScore"
+          >导出平时成绩</el-button
+        >
         <el-button type="primary" :loading="downloading" @click="toSave"
           >保存报告</el-button
         >
@@ -339,49 +346,59 @@
             width="100"
           ></el-table-column>
         </el-table>
+      </div>
 
-        <h4 class="part-title mb-2 mt-2">
-          课程目标达成度评价结果分析及改进措施
-        </h4>
-
-        <el-form label-position="top">
-          <el-form-item label="达成情况">
-            <el-input
-              v-model="courseBasicInfo.finishPoints"
-              type="textarea"
-              :autosize="{ minRows: 4, maxRows: 10 }"
-              resize="none"
-              placeholder="请输入"
-              clearable
-              maxlength="999"
-              show-word-limit
-            ></el-input>
-          </el-form-item>
-          <el-form-item label="课程支撑毕业要求达成情况评价">
-            <el-input
-              v-model="courseBasicInfo.requirementPoints"
-              type="textarea"
-              :autosize="{ minRows: 4, maxRows: 10 }"
-              resize="none"
-              placeholder="请输入"
-              clearable
-              maxlength="999"
-              show-word-limit
-            ></el-input>
-          </el-form-item>
-          <el-form-item label="课程持续改进">
-            <el-input
-              v-model="courseBasicInfo.courseSuggest"
-              type="textarea"
-              :autosize="{ minRows: 4, maxRows: 10 }"
-              resize="none"
-              placeholder="请输入"
-              clearable
-              maxlength="999"
-              show-word-limit
-            ></el-input>
-          </el-form-item>
-        </el-form>
+      <div class="page-head">
+        <h2>
+          <span> 课程目标达成度评价结果分析及改进措施 </span>
+        </h2>
+      </div>
+      <div class="part-box part-box-pad">
+        <div
+          v-for="item in targetSuggests"
+          :key="item.targetId"
+          class="target-suggest mb-4"
+        >
+          <h4 class="part-title">{{ item.targetName }}</h4>
+          <el-form label-position="top">
+            <el-form-item label="达成情况">
+              <el-input
+                v-model="item.finishPoints"
+                type="textarea"
+                :autosize="{ minRows: 2, maxRows: 5 }"
+                resize="none"
+                placeholder="请输入"
+                clearable
+                maxlength="999"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+            <el-form-item label="课程支撑毕业要求达成情况评价">
+              <el-input
+                v-model="item.requirementPoints"
+                type="textarea"
+                :autosize="{ minRows: 2, maxRows: 5 }"
+                resize="none"
+                placeholder="请输入"
+                clearable
+                maxlength="999"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+            <el-form-item label="课程持续改进">
+              <el-input
+                v-model="item.courseSuggest"
+                type="textarea"
+                :autosize="{ minRows: 2, maxRows: 5 }"
+                resize="none"
+                placeholder="请输入"
+                clearable
+                maxlength="999"
+                show-word-limit
+              ></el-input>
+            </el-form-item>
+          </el-form>
+        </div>
       </div>
     </div>
 
@@ -394,14 +411,17 @@
 import {
   targetStatisticsDetail,
   targetStatisticsReport,
+  targetStatisticsNormalScoreExport,
   targetStatisticsSave,
   targetStatisticsChangeCheck,
 } from "../../api";
 import { downloadByApi } from "@/plugins/download";
 import { calcSum } from "@/plugins/utils";
+import timeMixin from "@/mixins/timeMixin";
 
 export default {
   name: "detail-target-statistics",
+  mixins: [timeMixin],
   props: {
     course: {
       type: Object,
@@ -433,9 +453,13 @@ export default {
       courseTargets: [],
       targetColumnCounts: [],
       studentScoreTable: [],
+      targetSuggests: [],
       downloading: false,
     };
   },
+  beforeDestroy() {
+    this.clearSetTs();
+  },
   methods: {
     cancel() {
       this.modalIsShow = false;
@@ -443,6 +467,22 @@ export default {
     open() {
       this.modalIsShow = true;
     },
+    dialogClose() {
+      this.clearSetTs();
+    },
+    dialogOpend() {
+      this.initData();
+      this.openAutoSave();
+    },
+    openAutoSave() {
+      if (!this.modalIsShow) return;
+      this.clearSetTs();
+
+      this.addSetTime(async () => {
+        await this.toSave();
+        this.openAutoSave();
+      }, 1 * 60 * 1000);
+    },
     resetData() {
       this.commonInfo = {};
       this.courseBasicInfo = {};
@@ -455,16 +495,40 @@ export default {
       this.courseTargets = [];
       this.targetColumnCounts = [];
       this.studentScoreTable = [];
+      this.targetSuggests = [];
       this.downloading = false;
     },
     buildData(data) {
       this.commonInfo = data.commonInfo;
-      this.courseBasicInfo = {
-        ...data.courseBasicInfo,
-        finishPoints: data.finishPoints,
-        requirementPoints: data.requirementPoints,
-        courseSuggest: data.courseSuggest,
-      };
+      this.courseBasicInfo = data.courseBasicInfo;
+
+      const targetSuggests = data.targetSuggests
+        ? JSON.stringify(data.targetSuggests)
+        : [];
+      const targetSuggestsMap = {};
+      targetSuggests.forEach((item) => {
+        targetSuggestsMap[item.targetId] = {
+          finishPoints: item.finishPoints,
+          requirementPoints: item.requirementPoints,
+          courseSuggest: item.courseSuggest,
+        };
+      });
+      this.targetSuggests = data.courseEvaluationResultInfo.targetList.map(
+        (target) => {
+          const suggest = targetSuggestsMap[target.targetId] || {};
+          const finishPoints = suggest.finishPoints || "";
+          const requirementPoints = suggest.requirementPoints || "";
+          const courseSuggest = suggest.courseSuggest || "";
+
+          return {
+            targetId: target.targetId,
+            targetName: target.targetName,
+            finishPoints,
+            requirementPoints,
+            courseSuggest,
+          };
+        }
+      );
 
       this.courseTargetValue =
         data.courseEvaluationResultInfo.targetEvaluationSumValue;
@@ -473,6 +537,7 @@ export default {
           target.normalTargetWeight = calcSum(
             target.evaluationList.slice(0, -1).map((elem) => elem.targetWeight)
           );
+
           return target;
         }
       );
@@ -899,6 +964,7 @@ export default {
         cultureProgramId: this.course.cultureProgramId,
         courseId: this.course.courseId,
         ...this.courseBasicInfo,
+        targetSuggests: JSON.stringify(this.targetSuggests),
       }).catch(() => {});
       this.downloading = false;
 
@@ -921,6 +987,24 @@ export default {
       });
       this.downloading = false;
 
+      if (!res) return;
+      this.$message.success("下载成功!");
+    },
+    async toExportNormalScore() {
+      if (this.downloading) return;
+      this.downloading = true;
+
+      const res = await downloadByApi(() => {
+        const datas = {
+          cultureProgramId: this.course.cultureProgramId,
+          courseId: this.course.courseId,
+        };
+        return targetStatisticsNormalScoreExport(datas);
+      }).catch((e) => {
+        this.$message.error(e || "下载失败,请重新尝试!");
+      });
+      this.downloading = false;
+
       if (!res) return;
       this.$message.success("下载成功!");
     },

+ 13 - 13
src/modules/target/components/training-plan/ModifyTrainingPlan.vue

@@ -16,12 +16,12 @@
       :rules="rules"
       label-width="120px"
     >
-      <el-form-item prop="name" label="培养方案名称:">
-        <el-input
-          v-model.trim="modalForm.name"
-          placeholder="培养方案名称"
+      <el-form-item prop="grade" label="所属年级:">
+        <grade-select
+          v-model="modalForm.grade"
+          placeholder="所属年级"
           clearable
-        ></el-input>
+        ></grade-select>
       </el-form-item>
       <el-form-item prop="professionalId" label="所属专业:">
         <professional-select
@@ -30,6 +30,9 @@
         ></professional-select>
       </el-form-item>
     </el-form>
+    <p class="tips-info" style="padding-left: 50px">
+      说明:系统会自动按专业名称+年级+人才培养方案命名
+    </p>
     <div slot="footer">
       <el-button type="primary" :disabled="isSubmit" @click="submit"
         >确认</el-button
@@ -41,15 +44,17 @@
 
 <script>
 import { updateTrainingPlan } from "../../api";
+import GradeSelect from "@/components/base/GradeSelect.vue";
 
 const initModalForm = {
   id: null,
   professionalId: "",
-  name: "",
+  grade: 25,
 };
 
 export default {
   name: "modify-training-plan",
+  components: { GradeSelect },
   props: {
     instance: {
       type: Object,
@@ -64,13 +69,8 @@ export default {
       isSubmit: false,
       modalForm: { ...initModalForm },
       rules: {
-        name: [
-          { required: true, message: "请输入培养方案名称", trigger: "change" },
-          {
-            message: "培养方案名称不能超过30个字",
-            max: 30,
-            trigger: "change",
-          },
+        grade: [
+          { required: true, message: "请选择所属年级", trigger: "change" },
         ],
         professionalId: [
           { required: true, message: "请选择专业", trigger: "change" },

+ 6 - 1
src/modules/target/views/CourseOutlineManage.vue

@@ -63,7 +63,12 @@
         ></el-table-column>
         <el-table-column prop="outlineName" label="课程大纲" min-width="300">
         </el-table-column>
-        <el-table-column prop="courseName" label="课程名称" min-width="200">
+        <el-table-column label="课程(代码)" min-width="240">
+          <template slot-scope="scope">
+            {{ scope.row.courseName | defaultFieldFilter }}({{
+              scope.row.courseCode | defaultFieldFilter
+            }})
+          </template>
         </el-table-column>
         <el-table-column prop="credit" label="学分" width="80">
           <template slot-scope="scope">

+ 3 - 5
src/modules/target/views/RequirementStatistics.vue

@@ -7,9 +7,6 @@
             <professional-select
               v-model="filter.professionalId"
               placeholder="专业"
-              default-select
-              :clearable="false"
-              @default-selected="search"
             ></professional-select>
           </el-form-item>
           <el-form-item label="培养方案名称:">
@@ -119,12 +116,13 @@ export default {
       curRow: {},
     };
   },
+  mounted() {
+    this.search();
+  },
   methods: {
     async getList() {
       if (!this.checkPrivilege("list", "list")) return;
 
-      if (!this.filter.professionalId) return;
-
       const datas = {
         ...this.filter,
         pageNumber: this.current,

+ 3 - 5
src/modules/target/views/StudentTarget.vue

@@ -7,9 +7,6 @@
             <training-plan-select
               v-model="filter.cultureProgramId"
               placeholder="培养方案"
-              :clearable="false"
-              default-select
-              @default-selected="search"
             ></training-plan-select>
           </el-form-item>
           <el-form-item label="学生学号/姓名:">
@@ -111,12 +108,13 @@ export default {
       curRow: {},
     };
   },
+  mounted() {
+    this.search();
+  },
   methods: {
     async getList() {
       if (!this.checkPrivilege("list", "list")) return;
 
-      if (!this.filter.cultureProgramId) return;
-
       const datas = {
         ...this.filter,
         pageNumber: this.current,

+ 3 - 3
src/modules/target/views/TrainingPlanManage.vue

@@ -66,17 +66,17 @@
         <el-table-column
           class-name="action-column"
           label="操作"
-          width="220"
+          width="170"
           fixed="right"
         >
           <template slot-scope="scope">
-            <el-button
+            <!-- <el-button
               v-if="checkPrivilege('link', 'edit')"
               class="btn-primary"
               type="text"
               @click="toEdit(scope.row)"
               >编辑</el-button
-            >
+            > -->
             <el-button
               v-if="checkPrivilege('link', 'copy')"
               class="btn-primary"