123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755 |
- <template>
- <el-container>
- <el-main class="el-main-padding">
- <el-row>
- <el-col :span="7">
- <el-form>
- <el-form-item label="考试">
- <el-select
- v-model="examId"
- filterable
- remote
- :remote-method="getExams"
- clearable
- placeholder="请选择考试"
- size="small"
- @clear="getExams"
- @change="changeExam"
- >
- <el-option
- v-for="item in examList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-form>
- </el-col>
- <el-col :span="7">
- <el-form>
- <el-form-item label="场次">
- <el-select
- v-model="examStageId"
- clearable
- :disabled="examStageDisabled4Search"
- :remote-method="queryExamStages4Search"
- remote
- :loading="queryExamStages4SearchLoading"
- :filterable="true"
- placeholder="请选择"
- size="small"
- @change="changeExamStage"
- >
- <el-option
- v-for="item in examStageList4Search"
- :key="item.id"
- :label="`${item.stageOrder} (${item.startTime}至${item.endTime})`"
- :value="item.id"
- ></el-option>
- </el-select>
- </el-form-item>
- </el-form>
- </el-col>
- <el-col :span="10">
- <el-form>
- <el-form-item label="考试数据同步状态">
- <el-progress
- :text-inside="true"
- :stroke-width="22"
- :percentage="examSyncPercentage"
- status="success"
- style="width: 200px; float: left; line-height: 38px"
- ></el-progress>
- <el-button
- size="small"
- type="primary"
- icon="el-icon-refresh"
- style="float: left; margin-left: 20px; margin-top: 4px"
- @click="refreshExamSyncPercentage"
- >刷新</el-button
- >
- </el-form-item>
- </el-form>
- </el-col>
- </el-row>
- <el-row :gutter="2">
- <el-col :span="10" class="chart-border">
- <div class="chart-header">考试进度情况</div>
- <div>
- <v-chart :options="pieOptions" />
- </div>
- </el-col>
- <el-col :span="14" class="chart-border">
- <div class="chart-header">课程完成进度TOP5</div>
- <div>
- <v-chart :options="lineOptions" />
- </div>
- </el-col>
- </el-row>
- <el-row style="margin-top: 10px">
- <el-col :span="24">
- <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
- <el-tab-pane label="学习中心完成进度" name="first">
- <el-row style="margin-top: 20px">
- <el-col :span="24">
- <el-form>
- <el-form-item label="学习中心">
- <el-select
- v-model="orgId"
- filterable
- remote
- :remote-method="getOrgs"
- clearable
- placeholder="请选择学习中心"
- size="small"
- @clear="getOrgs"
- @change="getOrgExamInfos"
- >
- <el-option
- v-for="item in orgList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- ></el-option>
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button
- v-show="!exportOrgLoading"
- type="primary"
- size="small"
- icon="el-icon-download"
- @click="exportOrg"
- >导出</el-button
- >
- <el-button
- v-show="exportOrgLoading"
- size="small"
- icon="el-icon-download"
- :loading="true"
- >导出数据中...</el-button
- >
- </el-form-item>
- </el-form>
- </el-col>
- <el-col :span="24">
- <el-table
- element-loading-text="数据加载中"
- :data="orgExamInfos"
- border
- >
- <el-table-column
- sortable
- label="学习中心代码"
- prop="orgCode"
- ></el-table-column>
- <el-table-column
- sortable
- label="学习中心名称"
- prop="orgName"
- ></el-table-column>
- <el-table-column
- sortable
- label="报考人数"
- prop="totalCount"
- ></el-table-column>
- <el-table-column
- sortable
- label="实考人数"
- prop="finishedCount"
- ></el-table-column>
- <el-table-column
- sortable
- :sort-method="sortByFinishedPercent"
- label="完成比率"
- prop="finishedPercent"
- ></el-table-column>
- </el-table>
- </el-col>
- </el-row>
- </el-tab-pane>
- <el-tab-pane label="课程完成进度" name="two">
- <el-row style="margin-top: 20px">
- <el-col :span="24">
- <el-form>
- <el-form-item label="课程">
- <el-select
- v-model="courseId"
- filterable
- remote
- :remote-method="getCourses"
- clearable
- placeholder="请选择课程"
- size="small"
- @clear="getCourses"
- @change="getCourseProgress"
- >
- <el-option
- v-for="item in courseList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- ></el-option>
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button
- v-show="!exportCourseLoading"
- type="primary"
- size="small"
- icon="el-icon-download"
- @click="exportCourse"
- >导出</el-button
- >
- <el-button
- v-show="exportCourseLoading"
- size="small"
- icon="el-icon-download"
- :loading="true"
- >导出数据中...</el-button
- >
- </el-form-item>
- </el-form>
- </el-col>
- <el-col :span="24">
- <el-table
- element-loading-text="数据加载中"
- :data="courseProgressList"
- border
- >
- <el-table-column
- sortable
- label="课程名称"
- prop="courseName"
- ></el-table-column>
- <el-table-column
- sortable
- label="课程代码"
- prop="courseCode"
- ></el-table-column>
- <el-table-column
- sortable
- label="报考人数"
- prop="allNum"
- ></el-table-column>
- <el-table-column
- sortable
- label="实考人数"
- prop="completedNum"
- ></el-table-column>
- <el-table-column
- sortable
- label="完成比率"
- prop="completedProportion"
- ></el-table-column>
- </el-table>
- </el-col>
- </el-row>
- </el-tab-pane>
- </el-tabs>
- </el-col>
- </el-row>
- </el-main>
- </el-container>
- </template>
- <script>
- import { mapState } from "vuex";
- import ECharts from "vue-echarts/components/ECharts";
- import "echarts/lib/component/legend";
- import "echarts/lib/component/legendScroll";
- import "echarts/lib/chart/pie";
- import "echarts/lib/component/polar";
- import "echarts/lib/component/tooltip";
- import "echarts/lib/component/title";
- import "echarts/lib/chart/bar";
- import "echarts/lib/chart/line";
- import { EXAM_WORK_API } from "@/constants/constants";
- export default {
- components: { "v-chart": ECharts },
- data() {
- return {
- examList: [],
- orgList: [],
- courseList: [],
- examId: "",
- examStageId: "",
- orgId: "",
- courseId: "",
- activeName: "first",
- orgExamInfos: [],
- courseProgressList: [],
- lineOptions: {},
- pieOptions: {},
- exportOrgLoading: false,
- exportCourseLoading: false,
- examSyncPercentage: 0,
- examStageDisabled4Search: true,
- queryExamStages4SearchLoading: false,
- examStageList4Search: [],
- currentExamType: null,
- };
- },
- computed: {
- ...mapState({ user: (state) => state.user }),
- },
- created() {
- this.getExams();
- this.getOrgs();
- },
- methods: {
- getExams(examName) {
- if (!examName) {
- examName = "";
- }
- this.$http
- .get("/api/ecs_exam_work/exam/queryByNameLike", {
- params: {
- enable: true,
- name: examName,
- examTypes: "ONLINE#OFFLINE#ONLINE_HOMEWORK",
- },
- })
- .then((response) => {
- this.examList = response.data;
- });
- },
- getOrgs(orgName) {
- if (!orgName) {
- orgName = "";
- }
- var rootOrgId = this.user.rootOrgId;
- this.$http
- .get("/api/ecs_core/org/query", {
- params: {
- name: orgName,
- rootOrgId: rootOrgId,
- enable: true,
- },
- })
- .then((response) => {
- this.orgList = response.data;
- });
- },
- handleClick(tab, event) {
- console.log(tab, event);
- },
- getOrgExamInfos() {
- this.$http
- .post(
- "/api/ecs_oe_admin/exam/student/statistic/by/org?examId=" +
- this.examId +
- "&examStageId=" +
- this.examStageId +
- "&orgId=" +
- this.orgId
- )
- .then((response) => {
- if (response.data && response.data.length > 0) {
- this.orgExamInfos = response.data;
- } else {
- this.orgExamInfos = [];
- }
- });
- },
- getCourseProgress() {
- this.$http
- .get("/api/ecs_oe_admin/exam/student/courseProgress/list", {
- params: {
- examId: this.examId,
- examStageId: this.examStageId,
- courseId: this.courseId,
- },
- })
- .then((response) => {
- if (response.data && response.data.length > 0) {
- this.courseProgressList = response.data;
- this.buildLine(response.data);
- } else {
- this.courseProgressList = [];
- this.lineOptions = {};
- }
- });
- },
- getCourses() {
- if (!this.examId) {
- return false;
- }
- this.$http
- .get("/api/ecs_oe_admin/exam/student/findCoursesByExamIdAndOrgId", {
- params: {
- examId: this.examId,
- examStageId: this.examStageId,
- orgId: this.orgId,
- },
- })
- .then((response) => {
- if (response.data && response.data.length > 0) {
- this.courseList = response.data;
- } else {
- this.courseList = [];
- }
- });
- },
- changeExam(examId) {
- this.examStageId = "";
- var exam = this.examList.filter((item) => {
- return item.id == examId;
- })[0];
- this.currentExamType = exam.examType;
- this.getPieData(this.currentExamType);
- this.getCourses();
- this.getOrgExamInfos();
- this.getCourseProgress();
- //场次联动
- if (this.examList.length > 0) {
- let examArr = this.examList.filter((p) => p.id == examId);
- if (examArr && examArr.length > 0) {
- let exam = examArr[0];
- if (
- exam.specialSettingsEnabled &&
- exam.specialSettingsType == "STAGE_BASED"
- ) {
- this.examStageDisabled4Search = false;
- this.queryExamStages4Search("");
- } else {
- this.examStageList4Search = [];
- this.examStageDisabled4Search = true;
- }
- }
- }
- },
- changeExamStage() {
- this.getPieData(this.currentExamType);
- this.getCourses();
- this.getOrgExamInfos();
- this.getCourseProgress();
- },
- getPieData(examType) {
- var completedWord =
- examType == "ONLINE" || examType == "ONLINE_HOMEWORK"
- ? "已完成:"
- : "已抽题:";
- var noCompletedWord =
- examType == "ONLINE" || examType == "ONLINE_HOMEWORK"
- ? "未完成:"
- : "未抽题:";
- if (!this.examId) {
- return;
- }
- this.$http
- .post(
- "/api/ecs_oe_admin/exam/student/statistic/by/finished?examId=" +
- this.examId +
- "&examStageId=" +
- this.examStageId
- )
- .then((response) => {
- var resp = response.data;
- var optionData = {
- title: "考试人次:" + (resp.finished + resp.unFinished),
- legendData: [
- noCompletedWord + resp.unFinished,
- completedWord + resp.finished,
- ],
- seriesData: [
- {
- name: noCompletedWord + resp.unFinished,
- value: resp.unFinished,
- },
- {
- name: completedWord + resp.finished,
- value: resp.finished,
- },
- ],
- };
- this.buildPieOptions(optionData);
- });
- },
- buildPieOptions(data) {
- var colors = ["#7CB5EC", "#FE8463"];
- this.pieOptions = {
- color: colors,
- title: {
- text: data.title,
- subtext: "",
- x: "left",
- },
- tooltip: {
- trigger: "item",
- formatter: "{b}人次<br/>占比:{d}%",
- },
- legend: {
- type: "scroll",
- orient: "vertical",
- right: 200,
- top: 30,
- data: data.legendData,
- },
- series: [
- {
- name: "",
- type: "pie",
- radius: "50%",
- center: ["35%", "60%"],
- data: data.seriesData,
- itemStyle: {
- emphasis: {
- shadowBlur: 10,
- shadowOffsetX: 0,
- shadowColor: "rgba(0, 0, 0, 0.5)",
- },
- },
- },
- ],
- };
- },
- buildLine(courseProgressList) {
- courseProgressList.sort(function (a, b) {
- if (b["completedProportion"] != a["completedProportion"]) {
- return b["completedProportion"] - a["completedProportion"];
- } else if (b["allNum"] != a["allNum"]) {
- return b["allNum"] - a["allNum"];
- } else {
- return b["completedNum"] - a["completedNum"];
- }
- });
- var campusCount = 5;
- var courseProgressDataList = [];
- //找出5个完成比例最高的
- if (courseProgressList.length >= campusCount) {
- courseProgressDataList = courseProgressList.slice(0, campusCount);
- } else {
- courseProgressDataList = courseProgressList;
- }
- var xAxisData = [];
- var seriesBar = {
- name: "计划数",
- type: "bar",
- data: [],
- };
- var seriesLine1 = {
- name: "完成数",
- type: "line",
- data: [],
- };
- var seriesLine2 = {
- name: "完成比(%)",
- type: "line",
- yAxisIndex: 1,
- data: [],
- };
- var yAxis_maxScale1 = 0;
- for (var i = 0; i < courseProgressDataList.length; i++) {
- xAxisData.push(courseProgressDataList[i].courseName);
- seriesBar.data.push(courseProgressDataList[i].allNum);
- seriesLine1.data.push(courseProgressDataList[i].completedNum);
- seriesLine2.data.push(courseProgressDataList[i].completedProportion);
- if (courseProgressDataList[i].allNum > yAxis_maxScale1) {
- yAxis_maxScale1 = courseProgressDataList[i].allNum;
- }
- }
- var optionData = {
- legendData: ["计划数", "完成数", "完成比(%)"],
- xAxis: { data: xAxisData },
- series: [seriesBar, seriesLine1, seriesLine2],
- yAxis_maxScale1,
- };
- this.buildLineOptions(optionData);
- },
- buildLineOptions(optionData) {
- var colors = ["#FE8463", "#66CCFF", "#675bba"];
- this.lineOptions = {
- color: colors,
- tooltip: {
- trigger: "axis",
- axisPointer: {
- type: "cross",
- crossStyle: {
- color: "#999",
- },
- },
- },
- toolbox: {
- feature: {
- dataView: { show: true, readOnly: false },
- magicType: { show: true, type: ["line", "bar"] },
- restore: { show: true },
- saveAsImage: { show: true },
- },
- },
- legend: {
- data: optionData.legendData,
- },
- xAxis: [
- {
- type: "category",
- data: optionData.xAxis.data,
- axisPointer: {
- type: "shadow",
- },
- },
- ],
- yAxis: [
- {
- type: "value",
- name: "人次",
- min: 0,
- max: optionData.yAxis_maxScale1,
- interval: 10000,
- axisLabel: {
- formatter: "{value} ",
- },
- },
- {
- type: "value",
- name: "完成比例",
- min: 0,
- max: 100,
- interval: 20,
- axisLabel: {
- formatter: "{value} %",
- },
- },
- ],
- series: optionData.series,
- };
- },
- sortByFinishedPercent(obj1, obj2) {
- let p1 = Number(obj1.finishedPercent);
- let p2 = Number(obj2.finishedPercent);
- return p1 - p2;
- },
- exportOrg() {
- this.exportOrgLoading = true;
- this.$http
- .get("/api/ecs_oe_admin/exam/student/statistic/by/org/export", {
- params: {
- examId: this.examId,
- examStageId: this.examStageId,
- orgId: this.orgId,
- },
- responseType: "arraybuffer",
- timeout: 20 * 60 * 1000, //限时20分钟
- })
- .then((response) => {
- if (response.data) {
- var blob = new Blob([response.data], {
- type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- });
- var url = URL.createObjectURL(blob);
- var a = document.createElement("a");
- a.href = url;
- a.download = "学习中心完成进度.xlsx";
- a.target = "_blank";
- a.click();
- URL.revokeObjectURL(url);
- }
- this.exportOrgLoading = false;
- });
- },
- exportCourse() {
- this.exportCourseLoading = true;
- this.$http
- .get("/api/ecs_oe_admin/exam/student/courseProgress/list/export", {
- params: {
- examId: this.examId,
- examStageId: this.examStageId,
- courseId: this.courseId,
- },
- responseType: "arraybuffer",
- timeout: 20 * 60 * 1000, //限时20分钟
- })
- .then((response) => {
- if (response.data) {
- var blob = new Blob([response.data], {
- type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
- });
- var url = URL.createObjectURL(blob);
- var a = document.createElement("a");
- a.href = url;
- a.download = "课程完成进度.xlsx";
- a.target = "_blank";
- a.click();
- URL.revokeObjectURL(url);
- }
- this.exportCourseLoading = false;
- });
- },
- refreshExamSyncPercentage() {
- if (!this.examId) {
- this.$notify({
- title: "警告",
- message: "请选择考试",
- type: "warning",
- duration: 2000,
- });
- return false;
- }
- this.$http
- .get("/api/ecs_oe_admin/examControl/getExamSyncPercentage", {
- params: { examId: this.examId },
- })
- .then((response) => {
- this.examSyncPercentage = response.data;
- })
- .catch((res) => {
- var errorMsg = "操作失败";
- if (res.response && res.response.data) {
- errorMsg = res.response.data.desc;
- }
- this.$notify({
- title: "提示",
- message: errorMsg,
- type: "error",
- });
- });
- },
- queryExamStages4Search(name) {
- this.queryExamStages(this.examId, name, "search");
- },
- queryExamStages(examId, name, where) {
- console.log("queryExams; name: " + name);
- let url =
- EXAM_WORK_API +
- "/examStage/queryByNameLike?examId=" +
- examId +
- "&enable=true&name=" +
- name;
- this.$httpWithMsg
- .get(url)
- .then((response) => {
- if ("search" == where) {
- this.queryExamStages4SearchLoading = false;
- this.examStageList4Search = response.data;
- }
- })
- .catch((response) => {
- console.log(response);
- if ("search" == where) {
- this.queryExamStages4SearchLoading = false;
- }
- });
- },
- },
- };
- </script>
- <style>
- .chart-border {
- border: 1px solid #ddd;
- }
- .chart-header {
- color: #333;
- font-size: 14px;
- background-color: #f5f5f5;
- border-color: #ddd;
- padding: 10px 15px;
- border-bottom: 1px solid transparent;
- border-top-left-radius: 3px;
- border-top-right-radius: 3px;
- }
- </style>
- <style scoped src="../style/common.css"></style>
|