|
@@ -0,0 +1,936 @@
|
|
|
+<template>
|
|
|
+ <el-dialog
|
|
|
+ class="page-dialog"
|
|
|
+ :visible.sync="modalIsShow"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ :show-close="false"
|
|
|
+ append-to-body
|
|
|
+ fullscreen
|
|
|
+ @opened="initData"
|
|
|
+ >
|
|
|
+ <div slot="title" class="box-justify">
|
|
|
+ <div>
|
|
|
+ <span>{{ course.courseName }}</span>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <el-button type="primary" :loading="downloading" @click="toSave"
|
|
|
+ >保存报告</el-button
|
|
|
+ >
|
|
|
+ <el-button type="primary" :loading="downloading" @click="toExport"
|
|
|
+ >导出报告</el-button
|
|
|
+ >
|
|
|
+ <el-button type="danger" @click="cancel">退出</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="modalIsShow">
|
|
|
+ <!-- base info -->
|
|
|
+ <div class="page-head">
|
|
|
+ <h2>
|
|
|
+ <span>课程基本情况</span>
|
|
|
+ </h2>
|
|
|
+ </div>
|
|
|
+ <div class="part-box part-box-pad">
|
|
|
+ <table class="table table-tiny">
|
|
|
+ <colgroup>
|
|
|
+ <col width="100" />
|
|
|
+ <col />
|
|
|
+ <col width="100" />
|
|
|
+ <col />
|
|
|
+ <col width="110" />
|
|
|
+ <col />
|
|
|
+ <col width="100" />
|
|
|
+ <col />
|
|
|
+ </colgroup>
|
|
|
+ <tr>
|
|
|
+ <td class="td-bg">课程名称</td>
|
|
|
+ <td>{{ commonInfo.courseName }}</td>
|
|
|
+ <td class="td-bg">课程代码</td>
|
|
|
+ <td>{{ commonInfo.courseCode }}</td>
|
|
|
+ <td class="td-bg">课程英文名称</td>
|
|
|
+ <td>
|
|
|
+ <el-input
|
|
|
+ v-model.trim="courseBasicInfo.courseEnName"
|
|
|
+ placeholder="请填写"
|
|
|
+ size="small"
|
|
|
+ :maxlength="50"
|
|
|
+ ></el-input>
|
|
|
+ </td>
|
|
|
+ <td class="td-bg">学分</td>
|
|
|
+ <td>
|
|
|
+ <el-input-number
|
|
|
+ v-model="courseBasicInfo.credit"
|
|
|
+ placeholder="请录入学分"
|
|
|
+ size="small"
|
|
|
+ :min="0"
|
|
|
+ :max="999"
|
|
|
+ :controls="false"
|
|
|
+ style="width: 100px"
|
|
|
+ ></el-input-number>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td class="td-bg">课程性质</td>
|
|
|
+ <td>
|
|
|
+ <el-input
|
|
|
+ v-model.trim="courseBasicInfo.courseType"
|
|
|
+ placeholder="请填写"
|
|
|
+ size="small"
|
|
|
+ :maxlength="50"
|
|
|
+ ></el-input>
|
|
|
+ </td>
|
|
|
+ <td class="td-bg">开课学院</td>
|
|
|
+ <td>{{ courseBasicInfo.college }}</td>
|
|
|
+ <td class="td-bg">开课专业</td>
|
|
|
+ <td>{{ courseBasicInfo.profession }}</td>
|
|
|
+ <td class="td-bg">学时</td>
|
|
|
+ <td>
|
|
|
+ <el-input-number
|
|
|
+ v-model="courseBasicInfo.period"
|
|
|
+ placeholder="请填写"
|
|
|
+ :min="0"
|
|
|
+ :max="999"
|
|
|
+ :controls="false"
|
|
|
+ size="small"
|
|
|
+ style="width: 100px"
|
|
|
+ ></el-input-number>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td class="td-bg">开课班级</td>
|
|
|
+ <td>
|
|
|
+ <el-input
|
|
|
+ v-model.trim="courseBasicInfo.teachingObject"
|
|
|
+ placeholder="请填写"
|
|
|
+ size="small"
|
|
|
+ :maxlength="50"
|
|
|
+ ></el-input>
|
|
|
+ </td>
|
|
|
+ <td class="td-bg">开课学期</td>
|
|
|
+ <td>{{ courseBasicInfo.openTime }}</td>
|
|
|
+ <td class="td-bg">学生人数</td>
|
|
|
+ <td>{{ courseBasicInfo.participantCount }}</td>
|
|
|
+ <td class="td-bg">期望值</td>
|
|
|
+ <td>
|
|
|
+ {{ courseBasicInfo.courseDegree }}
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ <tr>
|
|
|
+ <td class="td-bg">任课老师</td>
|
|
|
+ <td>
|
|
|
+ <el-input
|
|
|
+ v-model.trim="courseBasicInfo.teacher"
|
|
|
+ placeholder="请填写"
|
|
|
+ size="small"
|
|
|
+ :maxlength="50"
|
|
|
+ ></el-input>
|
|
|
+ </td>
|
|
|
+ <td class="td-bg">评价人</td>
|
|
|
+ <td colspan="5">
|
|
|
+ <el-input
|
|
|
+ v-model.trim="courseBasicInfo.director"
|
|
|
+ placeholder="请填写评价负责人姓名"
|
|
|
+ size="small"
|
|
|
+ :maxlength="50"
|
|
|
+ ></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">
|
|
|
+ <el-table :data="questionInfoTable">
|
|
|
+ <el-table-column
|
|
|
+ label="试题号"
|
|
|
+ prop="name"
|
|
|
+ width="200"
|
|
|
+ align="center"
|
|
|
+ fixed="left"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ label="合计"
|
|
|
+ prop="totalScore"
|
|
|
+ width="60"
|
|
|
+ align="center"
|
|
|
+ fixed="left"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ v-for="struct in paperStructs"
|
|
|
+ :key="struct.mainNumber"
|
|
|
+ :label="struct.mainNumber"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ v-for="subNumber in struct.subNumbers"
|
|
|
+ :key="subNumber"
|
|
|
+ :label="subNumber"
|
|
|
+ :prop="`${struct.mainNumber}_${subNumber}`"
|
|
|
+ align="center"
|
|
|
+ min-width="50"
|
|
|
+ >
|
|
|
+ </el-table-column>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div class="chart-box" style="height: 300px; margin-top: 20px">
|
|
|
+ <v-chart
|
|
|
+ v-if="questionInfoChartOption"
|
|
|
+ :option="questionInfoChartOption"
|
|
|
+ ></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>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
+ </h2>
|
|
|
+ </div>
|
|
|
+ <div class="part-box part-box-pad">
|
|
|
+ <h4 class="part-title mb-2">课程考核成绩评价结果</h4>
|
|
|
+
|
|
|
+ <table class="table">
|
|
|
+ <tr class="td-bg">
|
|
|
+ <th>课程目标</th>
|
|
|
+ <th>评价依据</th>
|
|
|
+ <th>评价环节</th>
|
|
|
+ <th>权重</th>
|
|
|
+ <th>目标分值</th>
|
|
|
+ <th>实际平均分</th>
|
|
|
+ <th>目标达成评价值</th>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ <template v-for="item in courseTargetList">
|
|
|
+ <tr
|
|
|
+ v-for="(evaluation, eindex) in item.evaluationList"
|
|
|
+ :key="`${item.targetId}-${eindex}`"
|
|
|
+ >
|
|
|
+ <!-- 课程目标 -->
|
|
|
+ <td
|
|
|
+ v-if="!eindex"
|
|
|
+ :rowspan="item.evaluationList.length"
|
|
|
+ style="width: 240px"
|
|
|
+ >
|
|
|
+ {{ item.targetName }}
|
|
|
+ </td>
|
|
|
+ <!-- 评价依据 -->
|
|
|
+ <td v-if="!eindex" :rowspan="item.evaluationList.length">
|
|
|
+ <p
|
|
|
+ v-for="edesc in item.graduationRequirementPoint.split(',')"
|
|
|
+ :key="edesc"
|
|
|
+ >
|
|
|
+ {{ edesc }}
|
|
|
+ </p>
|
|
|
+ </td>
|
|
|
+ <!-- 评价环节 -->
|
|
|
+ <td style="width: 140px">{{ evaluation.evaluation }}</td>
|
|
|
+ <!-- 权重 -->
|
|
|
+ <td style="width: 80px">
|
|
|
+ {{ evaluation.targetWeight }}
|
|
|
+ </td>
|
|
|
+ <!-- 目标分值 -->
|
|
|
+ <td style="width: 100px">{{ evaluation.targetScore }}</td>
|
|
|
+ <!-- 实际平均分 -->
|
|
|
+ <td style="width: 100px">{{ evaluation.targetAvgScore }}</td>
|
|
|
+ <!-- 目标达成评价值 -->
|
|
|
+ <td
|
|
|
+ v-if="!eindex"
|
|
|
+ :rowspan="item.evaluationList.length"
|
|
|
+ style="width: 140px"
|
|
|
+ >
|
|
|
+ {{ item.evaluationValue }}
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </template>
|
|
|
+ <tr>
|
|
|
+ <td colspan="6">课程总目标</td>
|
|
|
+ <td>{{ courseTargetValue }}</td>
|
|
|
+ </tr>
|
|
|
+ </table>
|
|
|
+
|
|
|
+ <div class="chart-box" style="height: 400px; margin-top: 20px">
|
|
|
+ <v-chart
|
|
|
+ v-if="courseTargetListChartOption"
|
|
|
+ :option="courseTargetListChartOption"
|
|
|
+ ></v-chart>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h4 class="part-title mb-2">课程考核成绩评价明细结果</h4>
|
|
|
+
|
|
|
+ <el-table
|
|
|
+ :data="studentScoreTable"
|
|
|
+ :span-method="studentScoreSpanMethod"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ label="姓名"
|
|
|
+ prop="name"
|
|
|
+ min-width="120"
|
|
|
+ align="center"
|
|
|
+ fixed="left"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ label="学号"
|
|
|
+ prop="studentCode"
|
|
|
+ width="160"
|
|
|
+ align="center"
|
|
|
+ fixed="left"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ v-for="(target, tindex) in courseTargets"
|
|
|
+ :key="tindex"
|
|
|
+ :label="target.targetName"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ <el-table-column
|
|
|
+ v-if="target.finalDimensions.length"
|
|
|
+ :label="`期末成绩(${target.finalWeight}%)`"
|
|
|
+ :prop="`${target.targetId}-final`"
|
|
|
+ width="140"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ v-for="work in target.usualWorks"
|
|
|
+ :key="`${target.targetId}${work.evaluation}`"
|
|
|
+ :label="`${work.evaluation}(${work.targetWeight}%)`"
|
|
|
+ :prop="`${target.targetId}-usual-${work.evaluation}`"
|
|
|
+ min-width="100"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
+ </el-table-column>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ label="综合成绩"
|
|
|
+ prop="score"
|
|
|
+ align="center"
|
|
|
+ width="100"
|
|
|
+ ></el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <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>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div slot="footer"></div>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+// import { reportData } from "./data";
|
|
|
+import {
|
|
|
+ targetStatisticsDetail,
|
|
|
+ targetStatisticsReport,
|
|
|
+ targetStatisticsSave,
|
|
|
+ targetStatisticsChangeCheck,
|
|
|
+} from "../../api";
|
|
|
+import { downloadByApi } from "@/plugins/download";
|
|
|
+import { calcSum } from "@/plugins/utils";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "detail-target-statistics",
|
|
|
+ props: {
|
|
|
+ course: {
|
|
|
+ type: Object,
|
|
|
+ default() {
|
|
|
+ return {};
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ filters: {
|
|
|
+ percentFilter(val) {
|
|
|
+ const num = val || 0;
|
|
|
+ const perc = num % 10 ? 2 : 1;
|
|
|
+ return ((num || 0) / 100).toFixed(perc);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ modalIsShow: false,
|
|
|
+ expectancyList: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
|
|
|
+ modalForm: {},
|
|
|
+ commonInfo: {},
|
|
|
+ courseBasicInfo: {},
|
|
|
+ paperStructs: [],
|
|
|
+ questionInfoTable: [],
|
|
|
+ courseTargetList: [],
|
|
|
+ courseTargetValue: 0.67,
|
|
|
+ questionInfoChartOption: null,
|
|
|
+ courseTargetListChartOption: null,
|
|
|
+ courseTargets: [],
|
|
|
+ targetColumnCounts: [],
|
|
|
+ studentScoreTable: [],
|
|
|
+ downloading: false,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ cancel() {
|
|
|
+ this.modalIsShow = false;
|
|
|
+ },
|
|
|
+ open() {
|
|
|
+ this.modalIsShow = true;
|
|
|
+ },
|
|
|
+ resetData() {
|
|
|
+ this.commonInfo = {};
|
|
|
+ this.courseBasicInfo = {};
|
|
|
+ this.paperStructs = [];
|
|
|
+ this.questionInfoTable = [];
|
|
|
+ this.courseTargetList = [];
|
|
|
+ this.courseTargetValue = 0.67;
|
|
|
+ this.questionInfoChartOption = null;
|
|
|
+ this.courseTargetListChartOption = null;
|
|
|
+ this.courseTargets = [];
|
|
|
+ this.targetColumnCounts = [];
|
|
|
+ this.studentScoreTable = [];
|
|
|
+ this.downloading = false;
|
|
|
+ },
|
|
|
+ buildData(data) {
|
|
|
+ this.commonInfo = data.commonInfo;
|
|
|
+ this.courseBasicInfo = {
|
|
|
+ ...data.courseBasicInfo,
|
|
|
+ finishPoints: data.finishPoints,
|
|
|
+ requirementPoints: data.requirementPoints,
|
|
|
+ courseSuggest: data.courseSuggest,
|
|
|
+ };
|
|
|
+
|
|
|
+ this.courseTargetValue =
|
|
|
+ data.courseEvaluationResultInfo.targetEvaluationSumValue;
|
|
|
+ this.courseTargetList = data.courseEvaluationResultInfo.targetList.map(
|
|
|
+ (target) => {
|
|
|
+ target.normalTargetWeight = calcSum(
|
|
|
+ target.evaluationList.slice(0, -1).map((elem) => elem.targetWeight)
|
|
|
+ );
|
|
|
+ return target;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ const {
|
|
|
+ courseEvaluationSpreadInfo: { questionInfo, scoreList },
|
|
|
+ } = data;
|
|
|
+ this.parsePaperStructs(questionInfo);
|
|
|
+ this.parseQuestionInfoTable(questionInfo);
|
|
|
+ this.questionInfoChartOption = this.getQuestionInfoChartOption(scoreList);
|
|
|
+ this.courseTargetListChartOption = this.getCourseTargetListChartOption();
|
|
|
+
|
|
|
+ let examStudentList =
|
|
|
+ data.courseEvaluationResultDetailInfo.examStudentList;
|
|
|
+ examStudentList.pop();
|
|
|
+ examStudentList.splice(examStudentList.length - 2, 1);
|
|
|
+
|
|
|
+ this.parseCourseTargets(examStudentList);
|
|
|
+ this.parseStudentScoreTable(examStudentList);
|
|
|
+ },
|
|
|
+ async initData() {
|
|
|
+ this.resetData();
|
|
|
+
|
|
|
+ await this.checkChange();
|
|
|
+ const data = await targetStatisticsDetail({
|
|
|
+ cultureProgramId: this.course.cultureProgramId,
|
|
|
+ courseId: this.course.courseId,
|
|
|
+ });
|
|
|
+ this.buildData(data);
|
|
|
+ },
|
|
|
+ async checkChange() {
|
|
|
+ const res = await targetStatisticsChangeCheck({
|
|
|
+ cultureProgramId: this.course.cultureProgramId,
|
|
|
+ courseId: this.course.courseId,
|
|
|
+ report: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.courseTargetChange) {
|
|
|
+ this.$notify.warning("课程目标与已保存不一致,请重新设置权重!");
|
|
|
+ }
|
|
|
+ if (res.evaluationChange) {
|
|
|
+ this.$notify.warning(
|
|
|
+ "评价方式与已保存不一致,请重新设置权重及导入新的平时成绩!"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (res.targetScoreChange) {
|
|
|
+ this.$notify.warning(res.targetScoreChangeStr);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ parsePaperStructs(questionInfo) {
|
|
|
+ if (!questionInfo || !questionInfo.length) return;
|
|
|
+
|
|
|
+ const structMap = {};
|
|
|
+ questionInfo.forEach((item) => {
|
|
|
+ if (!structMap[item.mainNumber]) {
|
|
|
+ structMap[item.mainNumber] = [];
|
|
|
+ }
|
|
|
+ structMap[item.mainNumber].push(item.subNumber + "");
|
|
|
+ });
|
|
|
+ this.paperStructs = Object.keys(structMap).map((mainNumber) => {
|
|
|
+ return {
|
|
|
+ mainNumber,
|
|
|
+ subNumbers: structMap[mainNumber],
|
|
|
+ };
|
|
|
+ });
|
|
|
+ },
|
|
|
+ parseQuestionInfoTable(questionInfo) {
|
|
|
+ const targetMap = {};
|
|
|
+ const tData = {
|
|
|
+ name: "目标分值",
|
|
|
+ totalScore: calcSum(questionInfo.map((item) => item.score || 0)),
|
|
|
+ };
|
|
|
+ questionInfo.forEach((question) => {
|
|
|
+ const qno = `${question.mainNumber}_${question.subNumber}`;
|
|
|
+ tData[qno] = question.score;
|
|
|
+
|
|
|
+ question.targetList.forEach((target) => {
|
|
|
+ if (!targetMap[target.targetId]) {
|
|
|
+ targetMap[target.targetId] = {
|
|
|
+ name: target.targetName,
|
|
|
+ totalScore: 0,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target.dimensionList.length) {
|
|
|
+ targetMap[target.targetId][qno] = question.score;
|
|
|
+ targetMap[target.targetId].totalScore += question.score;
|
|
|
+ } else {
|
|
|
+ targetMap[target.targetId][qno] = "";
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ this.questionInfoTable = [tData, ...Object.values(targetMap)];
|
|
|
+ },
|
|
|
+ getQuestionInfoChartOption(scoreList) {
|
|
|
+ const scoreRange = scoreList.scoreRange.map((item) => {
|
|
|
+ return {
|
|
|
+ name: `${item.minScore}~${item.maxScore}`,
|
|
|
+ value: item.rate,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ scoreRange.unshift({
|
|
|
+ name: "不及格",
|
|
|
+ value: scoreList.failRate,
|
|
|
+ });
|
|
|
+
|
|
|
+ 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: scoreRange.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: scoreRange.map((item) => item.value),
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ formatter: "{c}%",
|
|
|
+ position: "top",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ return options;
|
|
|
+ },
|
|
|
+ getCourseTargetListChartOption() {
|
|
|
+ let options = {
|
|
|
+ color: ["#556dff", "#f59a23"],
|
|
|
+ title: {
|
|
|
+ text: "课程目标达成评价值",
|
|
|
+ left: "center",
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: 40,
|
|
|
+ top: 60,
|
|
|
+ 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.targetName),
|
|
|
+ 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.evaluationValue),
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ position: "top",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "期望值",
|
|
|
+ type: "line",
|
|
|
+ symbol: "none",
|
|
|
+ data: this.courseTargetList.map(
|
|
|
+ (item) => this.courseBasicInfo.courseDegree || 0
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ return options;
|
|
|
+ },
|
|
|
+ parseCourseTargets(examStudentList) {
|
|
|
+ if (!examStudentList || !examStudentList.length) return;
|
|
|
+
|
|
|
+ const targetList = examStudentList[0].targetList;
|
|
|
+ const targetVals = {};
|
|
|
+ this.courseTargetList.forEach((target) => {
|
|
|
+ targetVals[target.targetId] = target.evaluationValue;
|
|
|
+ });
|
|
|
+
|
|
|
+ let tColumnCounts = [];
|
|
|
+ this.courseTargets = targetList.map((target) => {
|
|
|
+ const ntarget = {
|
|
|
+ targetId: target.targetId,
|
|
|
+ targetName: target.targetName,
|
|
|
+ finalWeight: target.finalScore?.targetWeight,
|
|
|
+ usualWeight: 0,
|
|
|
+ evaluationValue: targetVals[target.targetId],
|
|
|
+ };
|
|
|
+ ntarget.usualWeight = calcSum(
|
|
|
+ (target.usualScore?.scoreList || []).map((item) => item.targetWeight)
|
|
|
+ );
|
|
|
+ ntarget.finalDimensions = target.finalScore ? ["期末成绩"] : [];
|
|
|
+ ntarget.usualWorks = (target.usualScore?.scoreList || []).map(
|
|
|
+ (item) => {
|
|
|
+ return {
|
|
|
+ evaluation: item.evaluation,
|
|
|
+ targetWeight: item.targetWeight,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ );
|
|
|
+ tColumnCounts.push(
|
|
|
+ ntarget.finalDimensions.length + ntarget.usualWorks.length
|
|
|
+ );
|
|
|
+ return ntarget;
|
|
|
+ });
|
|
|
+ // 只展示有期末成绩或平时成绩的目标
|
|
|
+ this.courseTargets = this.courseTargets.filter(
|
|
|
+ (item) => item.finalDimensions.length || item.usualWorks.length
|
|
|
+ );
|
|
|
+
|
|
|
+ let tCount = 0;
|
|
|
+ this.targetColumnCounts = tColumnCounts.map((item) => {
|
|
|
+ tCount += item;
|
|
|
+ return tCount;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getTargetFirseKey(target) {
|
|
|
+ if (target.finalDimensions.length) {
|
|
|
+ return `${target.targetId}-final`;
|
|
|
+ } else {
|
|
|
+ return `${target.targetId}-usual-${target.usualWorks[0].evaluation}`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ parseStudentScoreTable(examStudentList) {
|
|
|
+ if (!this.courseTargets.length) return;
|
|
|
+ const lastIndex = examStudentList.length - 1;
|
|
|
+ const studentScoreTable = examStudentList.map((student, sindex) => {
|
|
|
+ const nitem = {
|
|
|
+ name: student.name,
|
|
|
+ studentCode: student.studentCode,
|
|
|
+ score: student.score,
|
|
|
+ };
|
|
|
+
|
|
|
+ const finalScoreKey =
|
|
|
+ lastIndex === sindex ? "matrixAvgScore" : "targetScoreSum";
|
|
|
+ const workScoreKey = lastIndex === sindex ? "matrixAvgScore" : "score";
|
|
|
+
|
|
|
+ student.targetList.forEach((target, index) => {
|
|
|
+ nitem[`${target.targetId}-final`] =
|
|
|
+ target.finalScore && target.finalScore[finalScoreKey];
|
|
|
+
|
|
|
+ (target.usualScore?.scoreList || []).forEach((work) => {
|
|
|
+ nitem[`${target.targetId}-usual-${work.evaluation}`] =
|
|
|
+ work[workScoreKey];
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return nitem;
|
|
|
+ });
|
|
|
+
|
|
|
+ const targetData = {
|
|
|
+ name: "课程目标达成度",
|
|
|
+ score: "",
|
|
|
+ };
|
|
|
+ this.courseTargets.forEach((target) => {
|
|
|
+ targetData[this.getTargetFirseKey(target)] = target.evaluationValue;
|
|
|
+ });
|
|
|
+ studentScoreTable.push(targetData);
|
|
|
+
|
|
|
+ const fTarget = this.courseTargets[0];
|
|
|
+ const fKey = this.getTargetFirseKey(fTarget);
|
|
|
+ studentScoreTable.push({
|
|
|
+ name: "课程达成度",
|
|
|
+ [fKey]: this.courseTargetValue,
|
|
|
+ });
|
|
|
+ this.studentScoreTable = studentScoreTable;
|
|
|
+ },
|
|
|
+ studentScoreSpanMethod({ row, column, rowIndex, columnIndex }) {
|
|
|
+ const lineCount = this.studentScoreTable.length - 1;
|
|
|
+ const maxTargetColumnCount = this.targetColumnCounts.slice(-1)[0];
|
|
|
+ if (rowIndex === lineCount) {
|
|
|
+ if (columnIndex === 0) {
|
|
|
+ return [1, 2];
|
|
|
+ } else if (columnIndex === 2) {
|
|
|
+ return [1, maxTargetColumnCount + 1];
|
|
|
+ } else {
|
|
|
+ return [0, 0];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (rowIndex === lineCount - 1) {
|
|
|
+ const colsMap = {};
|
|
|
+ const targetColumns = [0, ...this.targetColumnCounts.slice(0, -1)];
|
|
|
+ targetColumns.map((item, index) => {
|
|
|
+ colsMap[item] = this.targetColumnCounts[index] - item;
|
|
|
+ });
|
|
|
+ if (columnIndex === 0) {
|
|
|
+ return [1, 2];
|
|
|
+ } else {
|
|
|
+ if (targetColumns.includes(columnIndex - 2)) {
|
|
|
+ return [1, colsMap[columnIndex - 2]];
|
|
|
+ } else if (columnIndex < maxTargetColumnCount + 2) {
|
|
|
+ return [0, 0];
|
|
|
+ } else {
|
|
|
+ return [1, 1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (rowIndex === lineCount - 2) {
|
|
|
+ if (columnIndex === 0) {
|
|
|
+ return [1, 2];
|
|
|
+ } else if (columnIndex === 1) {
|
|
|
+ return [0, 0];
|
|
|
+ } else {
|
|
|
+ return [1, 1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async toSave() {
|
|
|
+ if (this.downloading) return;
|
|
|
+ this.downloading = true;
|
|
|
+
|
|
|
+ const res = await targetStatisticsSave({
|
|
|
+ cultureProgramId: this.course.cultureProgramId,
|
|
|
+ courseId: this.course.courseId,
|
|
|
+ ...this.courseBasicInfo,
|
|
|
+ }).catch(() => {});
|
|
|
+ this.downloading = false;
|
|
|
+
|
|
|
+ if (!res) return;
|
|
|
+ this.$message.success("保存成功!");
|
|
|
+ this.initData();
|
|
|
+ },
|
|
|
+ async toExport() {
|
|
|
+ if (this.downloading) return;
|
|
|
+ this.downloading = true;
|
|
|
+
|
|
|
+ const res = await downloadByApi(() => {
|
|
|
+ const datas = {
|
|
|
+ cultureProgramId: this.course.cultureProgramId,
|
|
|
+ courseId: this.course.courseId,
|
|
|
+ };
|
|
|
+ return targetStatisticsReport(datas);
|
|
|
+ }).catch((e) => {
|
|
|
+ this.$message.error(e || "下载失败,请重新尝试!");
|
|
|
+ });
|
|
|
+ this.downloading = false;
|
|
|
+
|
|
|
+ if (!res) return;
|
|
|
+ this.$message.success("下载成功!");
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.td-bg {
|
|
|
+ color: #8b8fa1;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+</style>
|