Procházet zdrojové kódy

课程目标达成情况

zhangjie před 2 roky
rodič
revize
c3ca17f751

+ 9 - 0
src/constants/menus-data.js

@@ -1679,6 +1679,15 @@ export default [
       }
     ]
   },
+  {
+    id: "1401",
+    name: "课程目标达成度",
+    url: "CourseTargetResult",
+    type: "MENU",
+    parentId: "14",
+    sequence: 1,
+    enable: true
+  },
   {
     id: "21",
     name: "数据配置",

+ 849 - 0
src/modules/college/course/CourseTargetResult.vue

@@ -0,0 +1,849 @@
+<template>
+  <div class="course-target-result">
+    <div class="page-head page-head-flex">
+      <h2>
+        <span>课程基本情况</span>
+      </h2>
+      <el-button type="primary">导出报告</el-button>
+    </div>
+    <div class="part-box part-box-pad">
+      <table class="table">
+        <tr>
+          <td>课程编码</td>
+          <td>{{ baseInfo.courseCode }}</td>
+          <td>课程名称</td>
+          <td>{{ baseInfo.courseName }}</td>
+          <td>课程类别</td>
+          <td>
+            <el-input
+              v-model="baseInfo.courseType"
+              placeholder="请填写课程类别"
+              size="small"
+            ></el-input>
+          </td>
+          <td>学分</td>
+          <td>
+            <el-input-number
+              v-model="baseInfo.stdScore"
+              placeholder="请录入学分"
+              size="small"
+              :min="0"
+              :max="999"
+              :controls="false"
+              style="width:100px"
+            ></el-input-number>
+          </td>
+        </tr>
+        <tr>
+          <td>考核方式</td>
+          <td>
+            <el-input
+              v-model="baseInfo.examType"
+              placeholder="请填写考核方式"
+              size="small"
+            ></el-input>
+          </td>
+          <td>开课时间</td>
+          <td>{{ baseInfo.courseStartTime }}</td>
+          <td>授课对象</td>
+          <td>{{ baseInfo.teachClazz }}</td>
+          <td>学时</td>
+          <td>
+            <el-input-number
+              v-model="baseInfo.teachHours"
+              placeholder="请录入学时"
+              :min="0"
+              :max="999"
+              :controls="false"
+              size="small"
+              style="width:100px"
+            ></el-input-number>
+          </td>
+        </tr>
+        <tr>
+          <td>选课人数</td>
+          <td>
+            <el-input-number
+              v-model="baseInfo.studentCount"
+              placeholder="请录入选课人数"
+              :min="0"
+              :max="999"
+              :controls="false"
+              size="small"
+              style="width:125px"
+            ></el-input-number>
+          </td>
+          <td>参评人数</td>
+          <td>{{ baseInfo.commentCount }}</td>
+          <td>课程目标达成度期望值</td>
+          <td colspan="3">
+            <el-select
+              v-model="baseInfo.courseTarget"
+              size="small"
+              style="width:100%"
+            >
+              <el-option
+                v-for="item in expectancyList"
+                :key="item"
+                :value="item"
+                :label="item"
+              ></el-option>
+            </el-select>
+          </td>
+        </tr>
+        <tr>
+          <td>任课老师</td>
+          <td>{{ baseInfo.teachTeacher }}</td>
+          <td>评价负责人</td>
+          <td>
+            <el-input
+              v-model="baseInfo.commentManager"
+              placeholder="请填写评价负责人姓名"
+              size="small"
+            ></el-input>
+          </td>
+          <td>评价参与人</td>
+          <td colspan="3">
+            <el-input
+              v-model="baseInfo.commentUsers"
+              placeholder="请填写评价人姓名"
+              size="small"
+            ></el-input>
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="page-head">
+      <h2>
+        <span>课程目标与毕业要求对应关系</span>
+        <el-popover
+          popper-class="el-popper-dark"
+          placement="right-start"
+          width="500"
+          trigger="hover"
+        >
+          <i class="el-icon-question" slot="reference"></i>
+          <div>
+            <p>
+              请根据《课程教学大纲》中的课程对“毕业要求”进行填写,课程目标及毕业要求指标点会自动显示题库系统试题标记内容,支持修改
+            </p>
+          </div>
+        </el-popover>
+      </h2>
+    </div>
+    <div class="part-box part-box-pad">
+      <table class="table">
+        <tr>
+          <th>课程目标</th>
+          <th>毕业要求指标</th>
+          <th>毕业要求</th>
+        </tr>
+        <tr v-for="item in courseTargetList" :key="item.name">
+          <td style="width:240px">{{ item.name }}</td>
+          <td>
+            <el-input
+              v-model="item.indicator"
+              placeholder="请录入相关毕业要求指标"
+              type="textarea"
+              size="small"
+              :autosize="{ minRows: 4, maxRows: 8 }"
+            ></el-input>
+          </td>
+          <td>
+            <el-input
+              v-model="item.demand"
+              placeholder="请录入相关毕业要求"
+              type="textarea"
+              size="small"
+              :autosize="{ minRows: 4, maxRows: 8 }"
+            ></el-input>
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="page-head">
+      <h2>
+        <span>课程目标评价方法</span>
+        <el-popover
+          popper-class="el-popper-dark"
+          placement="right-start"
+          width="500"
+          trigger="hover"
+        >
+          <i class="el-icon-question" slot="reference"></i>
+          <div>
+            <p>
+              评价环节如:考勤、作业、章节测验、小设计、课程论文、期末成绩等,在课程目标考核对应的考试环节的表格中打√
+            </p>
+          </div>
+        </el-popover>
+      </h2>
+    </div>
+    <div class="part-box part-box-pad">
+      <h4>{{ baseInfo.examName }}</h4>
+      <table class="table table-big">
+        <tr>
+          <th>评价环节</th>
+          <th>评价方式</th>
+          <th v-for="item in courseTargetList" :key="item.name">
+            {{ item.name }}
+          </th>
+        </tr>
+        <tr v-for="row in commentMothodList" :key="row.k">
+          <td v-if="row.rowspan" :rowspan="row.rowspan">
+            {{ row.mainTypeName }}
+          </td>
+          <td>{{ row.subTypeName }}</td>
+          <td v-for="item in row.courseTargetList" :key="item.name">
+            <el-checkbox v-model="item.checked"></el-checkbox>
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="page-head">
+      <h2>
+        <span>课程目标考核分布</span>
+        <el-popover
+          popper-class="el-popper-dark"
+          placement="right-start"
+          width="500"
+          trigger="hover"
+        >
+          <i class="el-icon-question" slot="reference"></i>
+          <div>
+            <p>
+              课程目标分布会自动按题库系统里试卷下试题标记的属性内容进行显示
+            </p>
+          </div>
+        </el-popover>
+      </h2>
+    </div>
+    <div class="part-box part-box-pad">
+      <table class="table table-big text-center ">
+        <tr>
+          <th rowspan="2">试题号</th>
+          <th rowspan="2">合计</th>
+          <template v-for="(item, idex) in structs">
+            <th :key="idex" :colspan="item.subQuestionCount">{{ idex + 1 }}</th>
+          </template>
+        </tr>
+        <tr>
+          <template v-for="(item, index) in structs">
+            <th v-for="n in item.subQuestionCount" :key="`${index}-${n}`">
+              {{ n }}
+            </th>
+          </template>
+        </tr>
+        <tr v-for="item in scores" :key="item.name">
+          <td>{{ item.name }}</td>
+          <td>{{ item.totalScore || "" }}</td>
+          <td v-for="(elem, eind) in item.scores" :key="eind">
+            {{ elem || "" }}
+          </td>
+        </tr>
+      </table>
+
+      <div class="chart-box" style="height:300px;margin-top:20px">
+        <v-chart
+          v-if="scoreDistributionChartOption"
+          :option="scoreDistributionChartOption"
+        ></v-chart>
+      </div>
+    </div>
+    <div class="page-head">
+      <h2>
+        <span>课程目标达成评价结果</span>
+        <el-popover
+          popper-class="el-popper-dark"
+          placement="right-start"
+          width="500"
+          trigger="hover"
+        >
+          <i class="el-icon-question" slot="reference"></i>
+          <div>
+            <p>
+              1.评价依据:填写通过考核什么内容实现课程目标的评价;
+            </p>
+            <p>
+              2.目标分值:对应考核环节的满分;
+            </p>
+            <p>
+              3.权重:对应考核环节在对应的课程目标中的权重,目标下各项权重相加等于1;
+            </p>
+            <p>
+              4.实际平均分:为参与评价的学生在该环节的平均分;
+            </p>
+            <p>
+              5.目标达成评价值:∑(实际平均分/目标分值*权重);
+            </p>
+            <p>
+              6.整体课程目标达成评价值:为课程分目标达成评价值的最小值。
+            </p>
+          </div>
+        </el-popover>
+      </h2>
+    </div>
+    <div class="part-box part-box-pad">
+      <h4>课程考核成绩评价结果</h4>
+      <table class="table table-big">
+        <tr>
+          <th>课程目标</th>
+          <th>评价依据</th>
+          <th>评价环节</th>
+          <th>权重</th>
+          <th>目标分值</th>
+          <th>实际平均分</th>
+          <th>目标达成评价值</th>
+        </tr>
+
+        <template v-for="item in courseTargetList">
+          <tr v-for="(step, sind) in item.steps" :key="`${item.name}-${sind}`">
+            <td v-if="!sind" :rowspan="item.steps.length" style="width:240px">
+              {{ item.name }}
+            </td>
+            <td v-if="!sind" :rowspan="item.steps.length">
+              <p v-for="item in item.indicator.split('\n')" :key="item">
+                {{ item }}
+              </p>
+            </td>
+            <td style="width:140px">{{ step.name }}</td>
+            <td style="width:80px">{{ step.rate }}</td>
+            <td style="width:100px">{{ step.score }}</td>
+            <td style="width:100px">{{ step.aveScore }}</td>
+            <td v-if="!sind" :rowspan="item.steps.length" style="width:140px">
+              {{ item.getVal }}
+            </td>
+          </tr>
+        </template>
+        <tr>
+          <td colspan="6">课程总目标</td>
+          <td>{{ totalGetVal }}</td>
+        </tr>
+      </table>
+
+      <div class="chart-box" style="height:400px;margin-top:20px">
+        <v-chart
+          v-if="courseTargetListChartOption"
+          :option="courseTargetListChartOption"
+        ></v-chart>
+      </div>
+
+      <table class="table text-center table-big">
+        <tr>
+          <th rowspan="3">姓名</th>
+          <th rowspan="3">学号</th>
+          <th colspan="5">课程目标1</th>
+          <th colspan="5">课程目标2</th>
+          <th colspan="5">课程目标2</th>
+          <th rowspan="3">学生成绩</th>
+        </tr>
+        <tr>
+          <th colspan="3">期末考试(0.7)</th>
+          <th colspan="2">平时考试(0.3)</th>
+          <th colspan="3">期末考试(0.7)</th>
+          <th colspan="2">平时考试(0.3)</th>
+          <th colspan="3">期末考试(0.7)</th>
+          <th colspan="2">平时考试(0.3)</th>
+        </tr>
+        <tr>
+          <th>知识点1</th>
+          <th>知识点3</th>
+          <th>知识点4</th>
+          <th>平时作业</th>
+          <th>期中考试</th>
+          <th>知识点5</th>
+          <th>知识点6</th>
+          <th>知识点7</th>
+          <th>平时作业</th>
+          <th>期中考试</th>
+          <th>知识点8</th>
+          <th>知识点9</th>
+          <th>知识点10</th>
+          <th>平时作业</th>
+          <th>期中考试</th>
+        </tr>
+        <tr v-for="student in studentScores" :key="student.name">
+          <td>{{ student.name }}</td>
+          <td>{{ student.code }}</td>
+          <td v-for="n in student.scores" :key="n">
+            {{ n }}
+          </td>
+          <td>{{ student.totalScore }}</td>
+        </tr>
+        <tr>
+          <td colspan="2">平均分</td>
+          <td v-for="n in aveStudentScores" :key="n">{{ n }}</td>
+        </tr>
+        <tr>
+          <td colspan="2">课程目标达成度</td>
+          <td colspan="5">0.67</td>
+          <td colspan="5">0.75</td>
+          <td colspan="5">0.82</td>
+          <td></td>
+        </tr>
+        <tr>
+          <td colspan="2">课程达成度</td>
+          <td colspan="15">0.67</td>
+          <td></td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</template>
+
+<script>
+import { calcSum } from "../../../plugins/utils";
+export default {
+  name: "course-target-result",
+  data() {
+    return {
+      baseInfo: {
+        courseCode: "261062",
+        courseName: "高等数学",
+        courseType: "",
+        stdScore: undefined,
+        examType: "",
+        courseStartTime: "2022-2023学年第2学期",
+        teachClazz: "2019级生物科学2班",
+        teachHours: undefined,
+        studentCount: undefined,
+        commentCount: 45,
+        courseTarget: 0.7,
+        teachTeacher: "李老师",
+        commentManager: "",
+        commentUsers: "",
+        examName: "期末考试"
+      },
+      expectancyList: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
+      totalGetVal: 0.67,
+      courseTargetList: [
+        {
+          name: "课程目标1",
+          indicator:
+            "系统掌握高等数学中的基本概念、基本方法、基本技巧(A1)\n熟练掌握求极限的基本方法与技巧、判断函数的连续性(A2)\n熟练掌握求导数的基本方法与技巧(A3)\n熟练掌握求不定积分与定积分的基本方法与技巧(A4)\n掌握一阶及二阶微分方程的解法(A5)\n熟练掌握多元函数极限的求法、偏导数及全微分的求法,复合函数求导的基本方法与技巧(A6)\n熟练掌握多元函数积分学的基本方法与解题技巧(A7)\n掌握级数敛散性判别法,简单的幂级数求和函数及函数展开成幂级数(A8)",
+          demand: "",
+          commentGist: "",
+          getVal: 0.67,
+          steps: [
+            {
+              name: "平时作业",
+              rate: "10%",
+              score: 40,
+              aveScore: 25.93
+            },
+            {
+              name: "期中考查",
+              rate: "20%",
+              score: 5,
+              aveScore: 4.23
+            },
+            {
+              name: "期末考试",
+              rate: "70%",
+              score: 10,
+              aveScore: 7.82
+            }
+          ]
+        },
+        {
+          name: "课程目标2",
+          indicator:
+            "掌握数列极限、函数极限的基本概念、性质并会求极限(B1)\n微分中值定理的证明及其应用(B2)\n隐函数求导(B3)\n幂级数求和函数及函数展开成幂级数(B4)",
+          demand: "",
+          commentGist: "",
+          getVal: 0.75,
+          steps: [
+            {
+              name: "平时作业",
+              rate: "10%",
+              score: 40,
+              aveScore: 27.93
+            },
+            {
+              name: "期中考查",
+              rate: "20%",
+              score: 5,
+              aveScore: 4.23
+            },
+            {
+              name: "期末考试",
+              rate: "70%",
+              score: 10,
+              aveScore: 7.82
+            }
+          ]
+        },
+        {
+          name: "课程目标3",
+          indicator:
+            "掌握微分的应用、微分中值定理的应用、函数的图形与性态、求函数的极值与最值(C1)\n掌握定积分几何应用(C2)\n掌握多元函数微分学的应用(C3)\n熟练掌握二重积分(C4)",
+          demand: "",
+          commentGist: "",
+          getVal: 0.82,
+          steps: [
+            {
+              name: "平时作业",
+              rate: "10%",
+              score: 40,
+              aveScore: 32.93
+            },
+            {
+              name: "期中考查",
+              rate: "20%",
+              score: 5,
+              aveScore: 4.23
+            },
+            {
+              name: "期末考试",
+              rate: "70%",
+              score: 10,
+              aveScore: 8.82
+            }
+          ]
+        }
+      ],
+      commentMothodList: [
+        {
+          mainTypeName: "平时成绩",
+          subTypeName: "考勤",
+          rowspan: 3,
+          courseTargetList: []
+        },
+        {
+          mainTypeName: "平时成绩",
+          subTypeName: "平时作业",
+          rowspan: 0,
+          courseTargetList: []
+        },
+        {
+          mainTypeName: "平时成绩",
+          subTypeName: "其中考查",
+          rowspan: 0,
+          courseTargetList: []
+        },
+        {
+          mainTypeName: "期末成绩",
+          subTypeName: "期末考试",
+          rowspan: 1,
+          courseTargetList: []
+        }
+      ],
+      structs: [
+        {
+          subQuestionCount: 15,
+          score: 2
+        },
+        {
+          subQuestionCount: 5,
+          score: 2
+        },
+        {
+          subQuestionCount: 6,
+          score: 5
+        },
+        {
+          subQuestionCount: 3,
+          score: 10
+        }
+      ],
+      scores: [],
+      scoreDistribution: [
+        {
+          name: "不及格",
+          val: 17.5
+        },
+        {
+          name: "60-69",
+          val: 19.3
+        },
+        {
+          name: "70-79",
+          val: 20.7
+        },
+        {
+          name: "80-89",
+          val: 35.5
+        },
+        {
+          name: "90-100",
+          val: 7
+        }
+      ],
+      scoreDistributionChartOption: null,
+      courseTargetListChartOption: null,
+      studentScores: [],
+      aveStudentScores: []
+    };
+  },
+  mounted() {
+    this.initData();
+  },
+  methods: {
+    initData() {
+      this.commentMothodList = this.commentMothodList.map((item, iindex) => {
+        item.k = this.$randomCode();
+        item.courseTargetList = this.courseTargetList.map((elem, eindex) => {
+          return {
+            name: elem.name,
+            checked: iindex + eindex > 2
+          };
+        });
+        return item;
+      });
+      // structs
+      let scores = [];
+      let targetScore = {
+        name: "目标分值",
+        totalScore: 0,
+        scores: []
+      };
+      this.structs.forEach(item => {
+        for (let i = 0; i < item.subQuestionCount; i++) {
+          targetScore.scores.push(item.score);
+        }
+      });
+      scores.push(targetScore);
+
+      this.courseTargetList.forEach((item, iindex) => {
+        let ts = {
+          name: item.name,
+          totalScore: 0,
+          scores: []
+        };
+        this.structs.forEach(item => {
+          for (let i = 0; i < item.subQuestionCount; i++) {
+            const valid = iindex === i % 3;
+            ts.scores.push(valid ? item.score : 0);
+          }
+        });
+        scores.push(ts);
+      });
+      this.scores = scores;
+      this.scores.forEach(item => (item.totalScore = calcSum(item.scores)));
+
+      this.scoreDistributionChartOption = this.getScoreDistributionChartOption();
+      this.courseTargetListChartOption = this.getCourseTargetListChartOption();
+
+      // student score
+      const students = ["周晓", "张华", "李佳"];
+      this.studentScores = students.map((item, index) => {
+        let scores = [];
+        for (let i = 0; i < 15; i++) {
+          scores[i] = Math.ceil(Math.random() * 12);
+        }
+        return {
+          name: item,
+          code: "082001" + index,
+          scores,
+          totalScore: calcSum(scores)
+        };
+      });
+      let aveStudentScores = [];
+      let studentCount = this.studentScores.length;
+      for (let i = 0; i < 15; i++) {
+        const aveScore =
+          calcSum(this.studentScores.map(item => item.scores[i])) /
+          studentCount;
+        aveStudentScores.push(aveScore.toFixed(2) * 1);
+      }
+      const aveTotalScore =
+        calcSum(this.studentScores.map(item => item.totalScore)) / studentCount;
+      aveStudentScores.push(aveTotalScore.toFixed(2) * 1);
+      this.aveStudentScores = aveStudentScores;
+    },
+    getScoreDistributionChartOption() {
+      let options = {
+        color: ["#556dff", "#3A5AE5"],
+        title: {
+          text: "成绩分布图",
+          left: "center"
+        },
+        grid: {
+          left: 40,
+          top: 60,
+          right: 80,
+          bottom: 40,
+          containLabel: true
+        },
+        xAxis: {
+          type: "category",
+          name: "成绩(分)",
+          nameTextStyle: {
+            color: "#363D59"
+          },
+          data: this.scoreDistribution.map(item => item.name),
+          axisLabel: {
+            color: "#6F7482",
+            interval: 0,
+            fontSize: 12,
+            margin: 12
+          },
+          axisLine: {
+            show: true,
+            lineStyle: {
+              color: "#EFF0F5"
+            }
+          },
+          splitLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          axisPointer: {
+            type: "shadow"
+          }
+        },
+        yAxis: {
+          type: "value",
+          name: "百分比(%)",
+          nameTextStyle: {
+            color: "#363D59"
+          },
+          axisLabel: {
+            color: "#6F7482"
+          },
+          axisLine: {
+            lineStyle: {
+              color: "#EFF0F5"
+            }
+          },
+          splitLine: {
+            lineStyle: {
+              color: "#EFF0F5"
+            }
+          }
+        },
+        series: [
+          {
+            name: "占比",
+            type: "bar",
+            barWidth: 60,
+            data: this.scoreDistribution.map(item => item.val),
+            label: {
+              show: true,
+              formatter: "{c}%",
+              position: "top"
+            }
+          }
+        ]
+      };
+      return options;
+    },
+    getCourseTargetListChartOption() {
+      let options = {
+        color: ["#556dff", "#f59a23"],
+        title: {
+          text: "课程目标达成评价值",
+          left: "center"
+        },
+        grid: {
+          left: 40,
+          top: 40,
+          right: 80,
+          bottom: 30,
+          containLabel: true
+        },
+        legend: {
+          top: 0,
+          data: ["期望值", "达成值"],
+          itemWidth: 12,
+          itemHeight: 4,
+          itemGap: 22,
+          right: 40
+        },
+        xAxis: {
+          type: "category",
+          name: "课程目标",
+          nameTextStyle: {
+            color: "#363D59"
+          },
+          data: this.courseTargetList.map(item => item.name),
+          axisLabel: {
+            color: "#6F7482",
+            interval: 0,
+            fontSize: 12,
+            margin: 12
+          },
+          axisLine: {
+            show: true,
+            lineStyle: {
+              color: "#EFF0F5"
+            }
+          },
+          splitLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          axisPointer: {
+            type: "shadow"
+          }
+        },
+        yAxis: {
+          type: "value",
+          name: "期望值",
+          min: 0,
+          max: 1,
+          interval: 0.1,
+          nameTextStyle: {
+            color: "#363D59"
+          },
+          axisLabel: {
+            color: "#6F7482"
+          },
+          axisLine: {
+            lineStyle: {
+              color: "#EFF0F5"
+            }
+          },
+          splitLine: {
+            lineStyle: {
+              color: "#EFF0F5"
+            }
+          }
+        },
+        series: [
+          {
+            name: "达成值",
+            type: "bar",
+            barWidth: 60,
+            data: this.courseTargetList.map(item => item.getVal),
+            label: {
+              show: true,
+              position: "top"
+            }
+          },
+          {
+            name: "期望值",
+            type: "line",
+            symbol: "none",
+            data: this.courseTargetList.map(item => this.totalGetVal)
+          }
+        ]
+      };
+      return options;
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.table {
+  td,
+  th {
+    padding: 6px 8px;
+  }
+
+  &.text-center {
+    text-align: center;
+  }
+}
+.table-big {
+  td,
+  th {
+    padding: 12px;
+  }
+}
+</style>

+ 6 - 0
src/modules/college/router.js

@@ -16,6 +16,7 @@ import OwnerCourseExamOverview from "./course/OwnerCourseExamOverview.vue";
 import OwnerCourseExamAnalysis from "./course/owner-course-exam-analysis/OwnerCourseExamAnalysis.vue";
 import AssignScoreAction from "./course/assign-score-action/AssignScoreAction.vue";
 import AssignScoreActionTry from "./course/assign-score-action/AssignScoreActionTry.vue";
+import CourseTargetResult from "./course/CourseTargetResult.vue";
 
 export default [
   // cockpit
@@ -99,5 +100,10 @@ export default [
     meta: {
       relate: "AssignScoreAction"
     }
+  },
+  {
+    path: "/course/course-target-result",
+    name: "CourseTargetResult",
+    component: CourseTargetResult
   }
 ];