Commit 3f3dad3d authored by 耿迪迪's avatar 耿迪迪

安全管理培训4-7

parent 06c32eac
package com.zehong.web.controller.train;
import com.zehong.common.core.controller.BaseController;
import com.zehong.common.core.domain.AjaxResult;
import com.zehong.common.core.page.TableDataInfo;
import com.zehong.common.utils.poi.ExcelUtil;
import com.zehong.system.domain.train.TrainCourseStat;
import com.zehong.system.domain.train.TrainCourseStatDetail;
import com.zehong.system.service.train.TTrainCourseStatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author geng
* 培训统计
*/
@RestController
@RequestMapping("/train/trainStat")
public class TTrainCourseStatController extends BaseController {
@Autowired
private TTrainCourseStatService tTrainCourseStatService;
/**
* 获取培训统计查询
* @param trainCourseStat 统计查询参数
* @return
*/
@GetMapping("/getTrainCourseStatData")
public TableDataInfo getTrainCourseStatData(TrainCourseStat trainCourseStat){
startPage();
List<TrainCourseStat> list = tTrainCourseStatService.getTrainCourseStatData(trainCourseStat);
return getDataTable(list);
}
/**
* 获取培训统计详情
* @param courseId 培训id
* @return
*/
@GetMapping("/getTrainCourseStatDetailData")
public TableDataInfo getTrainCourseStatDetailData(Long courseId){
startPage();
List<TrainCourseStatDetail> list = tTrainCourseStatService.getTrainCourseStatDetailData(courseId);
return getDataTable(list);
}
@GetMapping("/trainCourseStatDetailExport")
public AjaxResult trainCourseStatDetailExport(Long courseId) {
List<TrainCourseStatDetail> list = tTrainCourseStatService.getTrainCourseStatDetailData(courseId);
ExcelUtil<TrainCourseStatDetail> util = new ExcelUtil<>(TrainCourseStatDetail.class);
return util.exportExcel(list, "培训统计详情");
}
}
package com.zehong.system.domain.train;
import java.util.Date;
public class TrainCourseStat {
private Long courseId;
private String courseName;
private Date releaseTime;
private String planName;
private String maybeTestNum;
private String finishNum;
private Date releaseBeginTime;
private Date releaseEndTime;
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
private String deptName;
public String getDeptId() {
return deptId;
}
public void setDeptId(String deptId) {
this.deptId = deptId;
}
private String deptId;
public Long getCourseId() {
return courseId;
}
public void setCourseId(Long courseId) {
this.courseId = courseId;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public Date getReleaseTime() {
return releaseTime;
}
public void setReleaseTime(Date releaseTime) {
this.releaseTime = releaseTime;
}
public String getPlanName() {
return planName;
}
public void setPlanName(String planName) {
this.planName = planName;
}
public String getMaybeTestNum() {
return maybeTestNum;
}
public void setMaybeTestNum(String maybeTestNum) {
this.maybeTestNum = maybeTestNum;
}
public String getFinishNum() {
return finishNum;
}
public void setFinishNum(String finishNum) {
this.finishNum = finishNum;
}
public Date getReleaseBeginTime() {
return releaseBeginTime;
}
public void setReleaseBeginTime(Date releaseBeginTime) {
this.releaseBeginTime = releaseBeginTime;
}
public Date getReleaseEndTime() {
return releaseEndTime;
}
public void setReleaseEndTime(Date releaseEndTime) {
this.releaseEndTime = releaseEndTime;
}
}
package com.zehong.system.domain.train;
import com.zehong.common.annotation.Excel;
public class TrainCourseStatDetail {
private Long userCourseId;
@Excel(name = "培训人员")
private String nickName;
@Excel(name = "所属部门")
private String deptName;
@Excel(name = "培训时长")
private String finishDuration;
private Integer trainState;
@Excel(name = "是否完成")
private String isComplete;
public Long getUserCourseId() {
return userCourseId;
}
public void setUserCourseId(Long userCourseId) {
this.userCourseId = userCourseId;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getFinishDuration() {
return finishDuration;
}
public void setFinishDuration(String finishDuration) {
this.finishDuration = finishDuration;
}
public Integer getTrainState() {
return trainState;
}
public void setTrainState(Integer trainState) {
this.trainState = trainState;
}
public String getIsComplete() {
return isComplete;
}
public void setIsComplete(String isComplete) {
this.isComplete = isComplete;
}
}
package com.zehong.system.mapper.train;
import com.zehong.system.domain.train.TrainCourseStat;
import com.zehong.system.domain.train.TrainCourseStatDetail;
import java.util.List;
/**
* @author geng
* 培训课程统计
*/
public interface TTrainCourseStatMapper {
/**
* 获取培训统计查询
* @param trainCourseStat 统计查询参数
* @return
*/
List<TrainCourseStat> getTrainCourseStatData(TrainCourseStat trainCourseStat);
/**
* 获取培训统计详情
* @param courseId 培训id
* @return
*/
List<TrainCourseStatDetail> getTrainCourseStatDetailData(Long courseId);
}
package com.zehong.system.service.impl.train;
import com.zehong.system.domain.train.TrainCourseStat;
import com.zehong.system.domain.train.TrainCourseStatDetail;
import com.zehong.system.mapper.train.TTrainCourseStatMapper;
import com.zehong.system.service.train.TTrainCourseStatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author geng
* 培训统计
*/
@Service
public class TTrainCourseStatServiceImpl implements TTrainCourseStatService {
@Autowired
private TTrainCourseStatMapper tTrainCourseStatMapper;
/**
* 获取培训统计查询
* @param trainCourseStat 统计查询参数
* @return
*/
@Override
public List<TrainCourseStat> getTrainCourseStatData(TrainCourseStat trainCourseStat){
return tTrainCourseStatMapper.getTrainCourseStatData(trainCourseStat);
}
/**
* 获取培训统计详情
* @param courseId 培训id
* @return
*/
@Override
public List<TrainCourseStatDetail> getTrainCourseStatDetailData(Long courseId){
return tTrainCourseStatMapper.getTrainCourseStatDetailData(courseId);
}
}
package com.zehong.system.service.train;
import com.zehong.system.domain.train.TrainCourseStat;
import com.zehong.system.domain.train.TrainCourseStatDetail;
import java.util.List;
/**
* @author geng
* 培训统计
*/
public interface TTrainCourseStatService {
/**
* 获取培训统计查询
* @param trainCourseStat 统计查询参数
* @return
*/
List<TrainCourseStat> getTrainCourseStatData(TrainCourseStat trainCourseStat);
/**
* 获取培训统计详情
* @param courseId 培训id
* @return
*/
List<TrainCourseStatDetail> getTrainCourseStatDetailData(Long courseId);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zehong.system.mapper.train.TTrainCourseStatMapper">
<resultMap id="TrainCourseStatResult" type="TrainCourseStat">
<result property="courseId" column="course_id" />
<result property="courseName" column="course_name" />
<result property="releaseTime" column="release_time" />
<result property="planName" column="plan_name" />
<result property="maybeTestNum" column="maybeTestNum" />
<result property="finishNum" column="finishNum" />
<result property="deptName" column="dept_name" />
</resultMap>
<resultMap id="TrainCourseStatDetailResult" type="TrainCourseStatDetail">
<result property="userCourseId" column="user_course_id"></result>
<result property="nickName" column="nick_name" />
<result property="deptName" column="dept_name" />
<result property="finishDuration" column="finish_duration" />
<result property="trainState" column="train_state" />
<result property="isComplete" column="isComplete" />
</resultMap>
<select id="getTrainCourseStatData" parameterType="com.zehong.system.domain.train.TrainCourseStat" resultMap="TrainCourseStatResult">
SELECT
d.dept_name,
train.course_id,
train.course_name,
train.release_time,
plan.plan_name,
(SELECT count(1) FROM t_train_plan_post post WHERE plan_id = plan.plan_id)AS maybeTestNum,
(SELECT count(1) FROM t_train_user_course courseUse WHERE courseUse.course_id = train.course_id AND courseUse.train_state = '1')AS finishNum
FROM
t_train_course train
LEFT JOIN t_train_plan plan ON plan.plan_id = train.course_type
left join sys_dept d on train.deptid=d.dept_id
<where>
train.is_del = '0' and train.data_kind = 0
AND train.status = '1'
<if test="courseId != null "> and train.course_id = #{courseId}</if>
<if test="courseName !='' and courseName!= null">and train.course_name like concat('%', #{courseName}, '%')</if>
<if test="releaseBeginTime != null and releaseEndTime">and train.release_time BETWEEN #{releaseBeginTime} AND #{releaseEndTime} </if>
<if test="deptId != null "> and train.deptid = #{deptId}</if>
</where>
ORDER BY train.release_time DESC
</select>
<select id="getTrainCourseStatDetailData" parameterType="Long" resultMap="TrainCourseStatDetailResult">
SELECT
courseUse.user_course_id,
us.nick_name,
dept.dept_name,
SEC_TO_TIME(courseUse.finish_duration)AS finish_duration,
courseUse.train_state,
(
CASE courseUse.train_state
WHEN '0' THEN
'未完成'
WHEN '1' THEN
'完成'
END
) AS isComplete
FROM
t_train_user_course courseUse
LEFT JOIN sys_user us ON us.user_id = courseUse.user_id
LEFT JOIN sys_dept dept ON dept.dept_id = us.dept_id
WHERE courseUse.course_id = #{courseId}
</select>
</mapper>
import request from '@/utils/request'
// 获取培训统计查询
export function getTrainCourseStatData(query) {
return request({
url: '/train/trainStat/getTrainCourseStatData',
method: 'get',
params: query
})
}
// 获取培训统计详情
export function getTrainCourseStatDetailData(query) {
return request({
url: '/train/trainStat/getTrainCourseStatDetailData',
method: 'get',
params: query
})
}
// 培训统计详情导出
export function trainCourseStatDetailExport(query) {
return request({
url: '/train/trainStat/trainCourseStatDetailExport',
method: 'get',
params: query
})
}
......@@ -3,7 +3,7 @@
* @Date: 2022-12-19 15:23:58
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-02-01 17:24:30
* @FilePath: /danger-manage-web/src/views/educationPlanExam/textPaper/components/Lesson-table.vue
* @FilePath: /danger-manage-web/src/views/train/textPaper/components/Lesson-table.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
......
......@@ -3,7 +3,7 @@
* @Date: 2022-12-19 17:39:55
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-02-02 10:56:52
* @FilePath: /danger-manage-web/src/views/educationPlanExam/textPaper/components/ChangePapel.vue
* @FilePath: /danger-manage-web/src/views/train/textPaper/components/ChangePapel.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
......
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-20 20:14:18
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-02-03 15:59:38
* @FilePath: /danger-manage-web/src/views/myLessons/CheckLesson.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="check-lession flex">
<div class="top-title">
<div class="item allone">
<div class="text">{{ state != 2 ? "学习课程" : "查看课程" }}</div>
<div v-if="userlessonData.state!=3" class="gotime">{{minute}}:{{calculation(second)}}/{{parseInt(lessonData.duration/60)}}:{{calculation(lessonData.duration%60)}}</div>
<div v-if="userlessonData.state==3" style="background: red" class="gotime"> 已过期 </div>
</div>
<div class="bt flex fz14 border-bottom">
<div class="a">课程标题</div>
<div class="b">
<div>{{ lessonData.courseName }}</div>
</div>
</div>
<div class="bt flex fz14 border-bottom">
<div class="a">培训计划</div>
<div class="b">
<div>{{ lessonTypeName }}</div>
</div>
</div>
<div class="bt flex fz14 border-bottom">
<div class="a">课程内容</div>
<div class="b" v-html="lessonData.courseConent">
<!-- <div>安全生产规范</div>
<div>安全生产规范</div>
<div>安全生产规范</div>
<div>安全生产规范</div>
<div>安全生产规范</div> -->
</div>
</div>
<div class="bt flex fz14 video" >
<div class="a">视频文件</div>
<div class="b">
<div class="video" v-if="lessonData.video">
<video-player
class="video-player vjs-custom-skin"
ref="videoPlayer"
:playsinline="true"
:options="playerOptions"
></video-player>
</div>
<div v-else>未上传视频</div>
</div>
</div>
<div class="bt flex fz14" v-if="lessonData.enclosure">
<div class="a">学习附件</div>
<div class="b flex">
<div class="download flex">
<span>学习资料</span>
<el-button style="padding: 0; margin-left: 20px" type="text">
<a :href="lessonData.enclosure">下载</a>
</el-button>
<el-button style="padding: 0; margin-left: 20px" type="text">
<a @click="openXslx(lessonData.enclosure)">预览</a>
</el-button>
</div>
</div>
</div>
<div class="bt flex fz14" v-if="lessonData.video">
<div class="a">学习视频</div>
<div class="b flex">
<div class="download flex">
<span>学习视频</span>
<el-button style="padding: 0; margin-left: 20px" type="text">
<a @click="downLoad(lessonData.video, lessonData.courseName)"
>下载</a
>
</el-button>
</div>
</div>
</div>
<div v-if="state == 2&&lessonData.topicNum!=0" class="bt flex fz14">
<div class="a">考试结果</div>
<div style="color: #1d84ff" class="b flex">
已完成学习,课后测试得分{{ fenshu }},成绩合格!
</div>
</div>
<div class="btn-wrapper flex">
<!-- topicNum>0代表有考试题,没考试题不需要考试 -->
<el-button v-if="this.finish &&lessonData.topicNum>0 " @click="againQuesstion" type="primary">{{
state == 2 || state == 1 ? "重新考试" : "开始考试"
}}</el-button>
<el-button @click="$router.back()" type="primary" plain>取消</el-button>
</div>
</div>
<AnswerLesson
v-if="answerOpen"
:courseId="courseId"
:userCourseId="userCourseId"
:courseName="lessonData.courseName"
:visible.sync="answerOpen"
@jj="jj"
/>
<el-dialog :visible.sync="iframeVisible" width="80%">
<!--<div v-if="userlessonData.state!=3" class="gotime2">{{minute}}:{{calculation(second)}}/{{parseInt(lessonData.duration/60)}}:{{calculation(lessonData.duration%60)}}</div>-->
<iframe style="width: 100%; height: 600px" :src="ky"></iframe>
</el-dialog>
</div>
</template>
<script>
import { getLessonById,getUserLessonById ,changeUserLesson} from "@/api/train/lessonsProgram";
import { getPlanList } from "@/api/train/trainingProgram";
import AnswerLesson from "../components/AnswerLesson";
export default {
name: "CheckLesson",
components: {
AnswerLesson,
},
data() {
return {
finish:false,
minute:0,
second:0,
playerOptions: {
aspectRatio: "16:9",
},
dingshi:null,
// 课程类型
courseOptions: [],
lessonData: {},
userlessonData:{},
// 课程id
courseId: 0,
// 用户学习id
userCourseId: 0,
state: 0,
fenshu: 0,
answerOpen: false,
lessonTypeName: "",
iframeVisible: false,
ky: "https://view.xdocin.com/222-223-203-154-8082_o52uv3.htm",
};
},
created() {
this.saveId();
this.getPlanList();
this.getLessonById();
},
destroyed(){
console.log('销毁');
this.updateUserCourse();
clearInterval(this.dingshi);
},
methods: {
getPlanList() {
getPlanList().then((res) => {
this.courseOptions = res.data.map((item) => {
return {
planId: item.planId,
planName: item.planName,
};
});
this.lessonTypeName = this.courseOptions.find(
(item) => item.planId == this.lessonData?.courseType
).planName;
});
},
saveId() {
const { courseId, userCourseId, state, fenshu } = this.$route.query;
this.courseId = +courseId;
this.userCourseId = +userCourseId;
this.state = state;
this.fenshu = fenshu;
},
getLessonById() {
const { courseId, userCourseId } = this.$route.query;
getLessonById(courseId).then((res) => {
if (res.code == 200) {
this.lessonData = res.data;
console.log(this.lessonData);
this.changeVideo(this.lessonData.video);
}
});
getUserLessonById({"userCourseId":userCourseId}).then((res) => {
if (res.code == 200) {
this.userlessonData = res.data;
this.second = this.userlessonData.finishDuration%60;
this.minute = parseInt( this.userlessonData.finishDuration/60);
if(this.userlessonData.state!=3){
this.dingshi = setInterval(this.goTime,1000);
}
}
});
},
goTime(){
if(this.userlessonData.finishDuration>=this.lessonData.duration){
console.log("结束");
clearInterval(this.dingshi);
this.userlessonData.trainState=1;
this.userlessonData.finishDuration = this.lessonData.duration;
this.updateUserCourse();
}else {
this.userlessonData.finishDuration = this.userlessonData.finishDuration+1;
//console.log(this.userlessonData.finishDuration);
this.second = this.userlessonData.finishDuration%60;
this.minute = parseInt( this.userlessonData.finishDuration/60);
if(this.userlessonData.finishDuration%60==0){
this.updateUserCourse();
}
}
},
updateUserCourse(){
this.userlessonData.state = null;
changeUserLesson(this.userlessonData).then(response => {
if(this.userlessonData.finishDuration == this.lessonData.duration){
this.finish = true;
}
})
},
calculation(num){
if(num<10){
num = "0"+num;
}
return num;
},
changeVideo(src) {
this.playerOptions = {
// 视频播放
playbackRates: [0.5, 1.0, 1.5, 2.0], //可选择的播放速度
autoplay: false, //如果true,浏览器准备好时开始回放。
muted: false, // 默认情况下将会消除任何音频。
loop: false, // 视频一结束就重新开始。
preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
language: "zh-CN",
aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
sources: [
{
type: "",
src, //url地址
},
],
poster: "", //你的封面地址
// width: document.documentElement.clientWidth,
notSupportedMessage: "此视频暂无法播放,请稍后再试", //允许覆盖Video.js无法播放媒体源时显示的默认信息。
controlBar: {
timeDivider: true, //当前时间和持续时间的分隔符
durationDisplay: true, //显示持续时间
remainingTimeDisplay: false, //是否显示剩余时间功能
fullscreenToggle: true, //全屏按钮
},
};
},
againQuesstion() {
this.answerOpen = true;
},
jj(e) {
if (e.answer >= e.qualifiedNum) {
this.fenshu = Math.floor((e.answer / e.topicNum) * 100);
this.state = 2;
}
},
downLoad(url, name) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer"; // 返回类型blob
xhr.onload = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
let blob = this.response;
console.log(blob);
// 转换一个blob链接
// 注: URL.createObjectURL() 静态方法会创建一个 DOMString(DOMString 是一个UTF-16字符串),
// 其中包含一个表示参数中给出的对象的URL。这个URL的生命周期和创建它的窗口中的document绑定
let downLoadUrl = window.URL.createObjectURL(
new Blob([blob], {
type: "video/mp4",
})
);
// 视频的type是video/mp4,图片是image/jpeg
// 01.创建a标签
let a = document.createElement("a");
// 02.给a标签的属性download设定名称
a.download = name;
// 03.设置下载的文件名
a.href = downLoadUrl;
// 04.对a标签做一个隐藏处理
a.style.display = "none";
// 05.向文档中添加a标签
document.body.appendChild(a);
// 06.启动点击事件
a.click();
// 07.下载完毕删除此标签
a.remove();
}
};
xhr.send();
},
openXslx(url, name) {
// window.open(`https://view.xdocin.com/view?src=${url}`);
console.log(url)
this.ky=`https://view.xdocin.com/view?src=${url}`;
this.iframeVisible=true;
},
},
};
</script>
<style lang="scss" scoped>
.check-lession {
// width: 91.3%;
width: 100%;
height: calc(100vh - 50px);
overflow: auto;
justify-content: center;
.top-title {
padding-top: 14px;
padding-bottom: 14px;
width: 93.2%;
max-width: 1600px;
.item {
margin-bottom: 10px;
}
.bt {
padding-bottom: 10px;
margin-bottom: 10px;
width: 85%;
min-width: 1050px;
.a {
width: 70px;
color: #101010;
}
.b {
flex: 1;
color: #606266;
.video {
width: 870px;
height: 489px;
}
}
&.border-bottom {
border-bottom: 1px solid #bbbbbb;
&.viedo-wrapper {
border-bottom: none;
}
}
}
.btn-wrapper {
justify-content: center;
}
}
}
.allone{
display:flex;
flex-direction:row;
justify-content:flex-start;
}
.gotime{
background: #1c84c6;
width: 80px;
text-align: center;
line-height: 22px;
color: white;
margin-left: 40px;
border-radius: 10px;
}
.gotime2{
background: #1c84c6;
width: 80px;
text-align: center;
line-height: 22px;
color: white;
margin-left: 20px;
border-radius: 10px;
position: absolute;
top: 20px;
}
</style>
<template>
<el-dialog
class="answerLesson"
title="开始答题"
:visible.sync="visible"
width="57.5%"
:close-on-click-modal="false"
:close-on-press-escape="false"
:before-close="dialogCancel"
@closed="closeFinished"
destroy-on-close
>
<div ref="myBody" class="body" v-loading="loading">
<div class="text">
<div class="float">{{courseName}}</div>
</div>
<transition name="fade" mode="out-in">
<div :key="goodJobShow">
<template v-if="!goodJobShow">
<transition name="fade" mode="out-in">
<div class="question-wrapper" v-if="visible" :key="nowQuestion">
<div v-for="(item, index) in list" :key="item.id">
<template v-if="item.topicType === 1 || item.topicType === 3">
<Question
v-if="index === nowQuestion"
:questionObj="item"
:index="index"
:nowQuestion="nowQuestion"
:selectLetter="selectLetter"
@changeLetter="changeLetter"
/>
</template>
<template v-else>
<QuestionChoice
v-if="index === nowQuestion"
:questionObj="item"
:index="index"
:nowQuestion="nowQuestion"
:selectLetter="selectLetter"
@changeLetter="changeLetter"
/>
</template>
</div>
</div>
</transition>
<div class="select flex">
<div class="select-item flex">
<div
class="item"
:class="{
active:
answerArr.findIndex(
(item) => item.questionNum === index + 1
) >= 0 && activeBool(index),
activered:
answerArr.findIndex(
(item) => item.questionNum === index + 1
) >= 0 && !activeBool(index),
now: index === nowQuestion,
}"
v-for="(item, index) in list"
:key="item.id + 'a' + index"
@click="questionNumClick(index)"
>
{{ index + 1 }}
</div>
<div @click="nextBtnClick" class="btn">下一题</div>
</div>
</div>
</template>
<template v-else>
<div :style="{ height: startHeight }">
<GoodJob :goodJobData="goodJobData" />
</div>
</template>
</div>
</transition>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="closeFinished" v-if="goodJobShow"
>重新考试</el-button
>
<el-button type="primary" @click="dialogSubmitForm" v-else
>交卷</el-button
>
<el-button @click="dialogCancel">取消</el-button>
</div>
</el-dialog>
</template>
<script>
import Question from "./Question";
import QuestionChoice from "./QuestionChoice";
import GoodJob from "./GoodJob.vue";
import {
userQuestionList,
setAnswer,
} from "@/api/train/lessonsProgram";
export default {
name: "AnswerLesson",
props: {
visible: {
type: Boolean,
default: false,
},
userCourseId: {
type: [Number, String],
},
courseName:{
type: [String,String]
},
courseId: {
type: [Number, String],
},
},
components: {
Question,
QuestionChoice,
GoodJob,
},
data() {
return {
nowQuestion: 0,
startHeight: "0px",
goodJobShow: false,
goodJobData: {},
loading: false,
list: [
{
id: 19,
text: "j9",
question: ["adsf", "dfgsdfg", "adsfadsf", "dfasdfadsf"],
},
],
answerArr: [],
// 题目是否被答过,如果答过,就把值传回去,如果没有答过,就是空
selectLetter: [],
};
},
// watch: {
// visible(newValue) {
// if (newValue) {
// this.$nextTick(() => {
// this.saveBody();
// });
// }
// },
// },
created() {
userQuestionList({ courseId: this.courseId }).then((res) => {
console.log(res.data);
this.list = res.data.map((item) => {
return {
id: item.topicId,
text: item.topicTitle,
topicType: item.topicType,
question: JSON.parse(item.topicOption).map((item) => item.value),
};
});
});
},
methods: {
saveBody() {
this.startHeight = this.$refs.myBody.offsetHeight - 55 + "px";
},
dialogSubmitForm() {
// this.answerClear();
// this.$emit("update:visible", false);
this.saveBody();
const json = JSON.stringify(this.answerArr.map((item) => item.answer));
const answers = json.slice(1,json.length-1);
console.log(answers);
this.loading = true;
setAnswer({
userCourseId: this.userCourseId,
answers,
})
.then((res) => {
if (res.code == 200) {
console.log(res.data)
this.goodJobData = res.data;
this.goodJobShow = true;
}
})
.finally(() => {
this.loading = false;
// 是否作对
this.$emit("jj", this.goodJobData);
});
},
dialogCancel() {
this.$emit("update:visible", false);
},
// 关闭之后
closeFinished() {
this.answerClear();
this.goodJobShow = false;
},
answerClear() {
this.answerArr = [];
this.nowQuestion = 0;
},
// 点题目时
questionNumClick(index) {
// 是否是回答过的,数组中存在它,那它就是回答过的
const bool =
this.answerArr.findIndex((item) => item.questionNum === index + 1) >= 0;
// 或者下一题与当前题目是紧挨着的并且当前题目是答完的,相差为1就算是紧挨着的
const nowQuestionAnswerBool = this.nextQuestion(index);
if (bool || nowQuestionAnswerBool) {
this.nowQuestion = index;
}
// 赋值,如果答过的,就传回去,如果没答过,就是空 变成字符串是因为0位false
this.selectLetter = this.answerArr[this.nowQuestion]?.answer || [];
},
nextBtnClick() {
// 到头了,打完了
if (this.nowQuestion + 1 == this.list.length) return;
this.questionNumClick(this.nowQuestion + 1);
},
// 紧挨着且当前题目是打完的
nextQuestion(index) {
// 下一题相差1
// const nextIndexBool = index - this.nowQuestion == 1;
// 答案数组的长度,就是档当前达到了第几题,长度-1是因为题目是从0开始记录
const nextIndexBool = index - (this.answerArr.length - 1) == 1;
// 当前题已经回答过
const nowQuestionAnswerBool =
this.answerArr.findIndex(
(item) => item.questionNum === this.nowQuestion + 1
) >= 0;
return nextIndexBool && nowQuestionAnswerBool;
},
changeLetter(letter) {
console.log(letter);
const obj = {};
obj.questionNum = this.nowQuestion + 1;
obj.answer = letter;
// 数组中是否存在这个题目
const index = this.answerArr.findIndex(
(item) => item.questionNum === this.nowQuestion + 1
);
if (index < 0) {
// 如果不存在
// 推入
this.answerArr.push(obj);
} else {
// 如果存在
// 替换
this.answerArr.splice(index, 1, obj);
}
console.log(this.answerArr);
},
activeBool(index) {
return this.answerArr[index]?.answer.length > 0;
},
},
};
</script>
<style lang="scss" scoped>
.body {
width: 100%;
height: 100%;
padding-right: 50px;
padding-left: 60px;
.question-wrapper {
}
.text {
margin-bottom: 27px;
.float {
padding-right: 7px;
width: 411px;
height: 28px;
background: #1d84ff;
line-height: 28px;
color: #ffffff;
font-size: 14px;
text-align: right;
float: right;
}
&:after {
content: "";
display: block;
clear: both;
}
}
.select {
.select-item {
padding-top: 20px;
flex-wrap: wrap;
> div {
margin-bottom: 10px;
}
.item {
width: 28px;
height: 28px;
border: 1px solid #bbbbbb;
line-height: 28px;
font-size: 14px;
text-align: center;
margin-right: 18px;
box-sizing: border-box;
cursor: pointer;
&.active {
background: #afe8ab87;
border:none;
}
&.activered {
background: #b9112633;
border:none;
}
&.now {
background: #a3d3ff;
border: none;
}
}
.btn {
width: 84px;
height: 28px;
background: #e8f4ff;
border: 1px solid #a3d3ff;
color: #1d84ff;
text-align: center;
line-height: 28px;
font-size: 14px;
cursor: pointer;
&:hover {
background: rgba(29, 132, 255, 0.5);
color: #ffffff;
}
}
}
}
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-21 17:20:49
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-01-12 17:00:34
* @FilePath: /danger-manage-web/src/views/myLessons/components/GoodJob.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="goodjob-wrapper flex">
<div class="text flex">
<div class="text flex">
<template v-if="goodJobData.answer >= goodJobData.qualifiedNum">
<div class="icon"><i class="iconfont icon-smiling" /></div>
<div>
<!-- 恭喜你,做对{{ goodJobData.answer }}道题 -->
恭喜你,得分{{ goodJobData.answer }},成绩合格!
</div>
</template>
<template v-else>
<div class="icon"><i class="iconfont icon-nanguo" /></div>
<div>
继续努力,
<!-- 做对{{ goodJobData.answer }}道题 -->
得分{{ goodJobData.answer }},成绩不合格!
</div>
</template>
</div>
</div>
</div>
</template>
<script>
export default {
name: "",
props: {
goodJobData: {
type: Object,
},
},
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.goodjob-wrapper {
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
border-bottom: 1px solid #bbbbbb;
.text {
width: 100%;
height: 136px;
color: #1d84ff;
background: #f9f9f9 100%;
border-radius: 15px;
line-height: 136px;
font-size: 28px;
justify-content: center;
align-items: center;
.icon {
margin-right: 10px;
.iconfont {
color: #e2852a;
font-size: 40px !important;
}
}
}
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-20 14:17:00
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2022-09-28 13:05:49
* @FilePath: /danger-manage-web/src/views/myLessions/components/learnAfter.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="learnbrfore flex">
<transition name="fade" mode="out-in">
<div class="top flex" :key="currentPage">
<div
v-show="index < 9 * currentPage && index >= 9 * (currentPage - 1)"
v-for="(item, index) in afterList"
:key="index + ''"
class="learn-item"
>
<LearnItem
:state="state"
:itemData="item"
@examination="examination"
/>
</div>
</div>
</transition>
<div class="bottom flex">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-size="9"
:layout="total > 9 ? layout : layout2"
:total="afterList.length"
>
</el-pagination>
</div>
</div>
</template>
<script>
import LearnItem from "./LearnItem";
export default {
name: "learnbrfore",
components: {
LearnItem,
},
props: {
state: {
type: Object,
},
list: {
type: Array,
default: () => {
return [];
},
},
},
data() {
return {
// list: [
// { state: 2},
// { state: 2},
// { state: 2},
// { state: 2},
// { state: 2},
// { state: 2},
// { state: 2},
// { state: 2},
// { state: 2},
// ],
currentPage: 1,
total: 19,
layout: "prev, pager, next, jumper",
layout2: "prev, pager, next",
};
},
computed: {
afterList() {
return this.list.filter((item) => item.state == 2);
},
},
created() {
console.log("after");
},
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
},
examination(e) {
this.$emit("examination", e);
},
},
};
</script>
<style lang="scss" scoped>
.learnbrfore {
width: 100%;
height: 100%;
flex-direction: column;
.top {
width: 100%;
flex: 1;
padding: 2px;
box-sizing: border-box;
// justify-content: space-between;
flex-wrap: wrap;
.learn-item {
width: 32.5%;
height: 31.5%;
margin-right: 1.25%;
&:nth-child(3n) {
margin-right: 0px;
}
}
}
.bottom {
height: 12.7%;
max-height: 100px;
justify-content: center;
align-items: center;
}
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-20 14:17:00
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2022-09-28 09:37:40
* @FilePath: /danger-manage-web/src/views/myLessions/components/learnAfter.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="learnbrfore flex">
<transition name="fade" mode="out-in">
<div class="top flex" :key="currentPage">
<div
v-show="index < 9 * currentPage && index >= 9 * (currentPage - 1)"
v-for="(item, index) in beforeList"
:key="index + ''"
class="learn-item"
>
<LearnItem
:state="state"
:itemData="item"
@examination="examination"
/>
</div>
</div>
</transition>
<div class="bottom flex">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-size="9"
:layout="total > 9 ? layout : layout2"
:total="beforeList.length"
>
</el-pagination>
</div>
</div>
</template>
<script>
import LearnItem from "./LearnItem";
export default {
name: "learnbrfore",
components: {
LearnItem,
},
props: {
state: {
type: Object,
},
list: {
type: Array,
default: () => {
return [];
},
},
},
data() {
return {
// list: [
// { state: 0 },
// { state: 1 },
// { state: 0 },
// { state: 1 },
// { state: 0 },
// { state: 1 },
// { state: 1 },
// { state: 1 },
// { state: 0 },
// ],
currentPage: 1,
total: 19,
layout: "prev, pager, next, jumper",
layout2: "prev, pager, next",
};
},
computed: {
beforeList() {
return this.list.filter((item) => item.state != 2);
},
},
created() {
console.log("before");
},
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
},
examination(e) {
this.$emit("examination", e);
},
},
};
</script>
<style lang="scss" scoped>
.learnbrfore {
width: 100%;
height: 100%;
flex-direction: column;
.top {
width: 100%;
flex: 1;
padding: 2px;
box-sizing: border-box;
// justify-content: space-between;
flex-wrap: wrap;
.learn-item {
width: 32.5%;
height: 31.5%;
margin-right: 1.25%;
&:nth-child(3n) {
margin-right: 0px;
}
}
}
.bottom {
height: 12.7%;
max-height: 100px;
justify-content: center;
align-items: center;
}
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-20 14:29:26
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-01-03 15:10:43
* @FilePath: /danger-manage-web/src/views/myLessons/components/LearnItem.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="item flex">
<div class="title" style="text-align: center">{{ itemData.courseType||'-' }}</div>
<div class="allone" style="position:relative">
<!--<img v-if="itemData.dataKind==0" style="height: 18px" src="@/assets/img/ykao.png"/>-->
<!--<img v-if="itemData.dataKind==1" style="height: 18px" src="@/assets/img/skao.png"/>-->
<div class="content">{{itemData.dataKind==0?"培训课程":"随机考试"}}</div>
<div class="border"></div>
<div class="lesson zzz" style="width: 75%" :title="itemData.courseName"> {{ itemData.courseName }}</div>
</div>
<div class="time">发布时间:{{ itemData.createTime }}</div>
<div class="bottom flex">
<div v-if="itemData.state!=4 && !(itemData.state===3 && itemData.dataKind==='1')" @click="click" class="btn" :class="{ again: yesOrNo }">
{{ yesOrNo }}
</div>
</div>
<div
class="img"
:class="{
no: itemData.state === 1,
yes: itemData.state === 2,
ygq:itemData.state === 3,
wks:itemData.state === 4,
}"
>
{{ state[itemData.state] }}
</div>
<AnswerLesson
v-if="answerOpen"
:courseId="itemData.courseId"
:userCourseId="itemData.userCourseId"
:courseName = "itemData.courseName"
:visible.sync="answerOpen"
@jj="jj"
/>
</div>
</template>
<script>
import AnswerLesson from "./AnswerLesson";
export default {
name: "",
components: {
AnswerLesson,
},
props: {
itemData: {
type: Object,
default: () => {
return {
again: 2,
};
},
},
state: {
type: Object,
},
},
computed: {
yesOrNo() {
console.log(this.itemData)
if(this.itemData.dataKind==="0"){
if( this.itemData.state === 0){
return '开始学习'
}else if(this.itemData.state === 1){
return '查看课程'
}else if(this.itemData.state === 2){
return '查看课程'
}else if(this.itemData.state === 3){
return '开始学习'
}else if(this.itemData.state === 4){
return '还未开始'
}
}else{
if( this.itemData.state === 0){
return '开始考试'
}else if(this.itemData.state === 1){
return '重新考试'
}else if(this.itemData.state === 2){
return '重新考试'
}else if(this.itemData.state === 3){
return '开始学习'
}else if(this.itemData.state === 4){
return '还未开始'
}
}
},
},
data() {
return {
answerOpen:false
};
},
methods: {
jj(e) {
if (e.answer >= e.qualifiedNum) {
this.fenshu = Math.floor((e.answer / e.topicNum) * 100);
this.state = 2;
}
},
click() {
if(this.itemData.dataKind==='1'){
this.answerOpen = true;
return;
}
const { courseId, userCourseId, state, examinationResult, topicNum } =
this.itemData;
// if (!this.yesOrNo) {
// this.$router.push("myLessons/CheckLesson");
let fenshu;
if (examinationResult) {
fenshu = Math.floor((examinationResult / topicNum) * 100);
} else {
fenshu = 0;
}
this.$router.push({
path: "myLessons/CheckLesson",
query: { courseId, userCourseId, state, fenshu },
});
// } else {
// this.$emit("examination", { courseId, userCourseId });
// }
// $router.push("myLessons/CheckLesson");
},
},
};
</script>
<style lang="scss" scoped>
.item {
width: 100%;
height: 100%;
// background: red;
overflow: hidden;
padding-top: 15px;
padding-left: 18px;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.12);
border-radius: 5px;
flex-direction: column;
position: relative;
> div {
font-size: 14px;
}
.title {
color: #606266;
margin-bottom: 8%;
}
.lesson {
color: #1d84ff;
text-align: center;
margin-bottom: 3%;
}
.time {
text-align: center;
font-size: 12px;
color: #7b808a;
margin-bottom: 5%;
}
.bottom {
flex: 1;
justify-content: center;
.btn {
width: 110px;
height: 40px;
border-radius: 4px;
font-size: 14px;
text-align: center;
line-height: 40px;
color: #1d84ff;
border: 1px solid #a3d3ff;
background: #e8f4ff;
font-size: 14;
cursor: pointer;
&.again {
color: #ffffff;
border: 1px solid #a3d3ff;
background: #1d84ff 100%;
}
&:hover {
background: rgba(29, 132, 255, 0.5);
color: #ffffff;
}
}
}
.allone{
display:flex;
flex-direction:row;
justify-content:flex-start;
}
.img {
position: absolute;
width: 100px;
height: 20px;
background: #1d84ff;
// opacity: .2;
top: 3%;
right: -7%;
text-align: center;
line-height: 20px;
font-size: 10px;
color: #ffffff;
transform: rotateZ(40deg);
&.no {
background: #e2852a;
}
&.yes {
background: #3cc426 !important;
}
&.ygq {
background: red !important;
}
&.wks {
background: yellow !important;
}
}
}
.border {
width: 0;
height: 0;
border: 10px solid;
border-color: transparent transparent transparent #1d84ff;
}
.border:after {
content: '';
border-style: solid;
border-width: 10px;
border-color: transparent transparent transparent #fff;
position: absolute;
top: 0px;
left: 49px;
}
.content{
border: 1.5px solid #1d84ff;
height: 20px;
font-size: 10px;
color: #1d84ff;
line-height: 18px;
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-20 11:30:14
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2022-09-28 09:19:38
* @FilePath: /danger-manage-web/src/views/myLessons/components/Left.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="lession-left-wrapper flex">
<el-tabs class="top" v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="待学习" name="first"></el-tab-pane>
<el-tab-pane label="已学习" name="second"></el-tab-pane>
</el-tabs>
<div class="middle flex">
<transition name="fade-transform" mode="out-in">
<keep-alive>
<component :is="currentTabComponent" @examination="examination" :state="state" :list="list"></component>
</keep-alive>
</transition>
</div>
</div>
</template>
<script>
import LearnAfter from "./LearnAfter";
import LearnBefore from "./LearnBefore";
import {getUserLessons} from "@/api/train/lessonsProgram"
export default {
name: "lession-left",
components: {
// LearnAfter,
// LearnBefore,
},
data() {
return {
activeName: "first",
currentTabComponent: LearnBefore,
list:[],
state:{
"0":'未完成',
"1":'未通过',
"2":"已完成",
"3":"已过期",
"4":"未开始"
},
};
},
created(){
this.getUserLessons();
},
methods: {
getUserLessons(){
getUserLessons().then(res=>{
console.log(res.rows);
this.list = res.rows;
})
},
handleClick(tab) {
if (tab.paneName == "first") {
this.currentTabComponent = LearnBefore;
} else {
this.currentTabComponent = LearnAfter;
}
},
examination(e){
this.$emit('examination',e)
}
},
};
</script>
<style lang="scss" scoped>
.lession-left-wrapper {
padding: 5px 26px 0;
height: 100%;
width: 100%;
flex-direction: column;
.top {
// margin-bottom: 47px;
}
.middle {
flex: 1;
height: 100%;
width: 100%;
justify-content: space-between;
overflow: hidden;
}
// .bottom{
// max-height: 105px;
// height: 11%;
// }
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-21 11:00:14
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-01-11 16:44:43
* @FilePath: /danger-manage-web/src/views/myLessons/components/Question.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="question flex">
<div class="tips">{{ tipsArr[questionObj.topicType] }}</div>
<div
class="top"
:class="{ flex: alignItemsCenter }"
:style="{ alignItems: alignItemsCenter ? 'center' : '' }"
ref="top"
>
<div class="text" ref="text">
{{ questionObj.text }}
</div>
<div class="num">{{ nowQuestion + 1 }}</div>
</div>
<div class="middle">
<div
class="item flex"
v-for="(item, index) in questionObj.question"
:key="item + 'aas' + index"
>
<div class="letter">
{{ letters[index] }}
</div>
<div class="">
{{ item }}
</div>
</div>
</div>
<div class="bottom flex">
<div class="change-wrapper flex">
<div
class="change"
:class="{ active: letterActive.indexOf(index) >= 0 }"
@click="changeLetter(index)"
v-for="(item, index) in questionObj.question"
:key="item + 'a' + index"
>
{{ letters[index] }}
</div>
</div>
</div>
</div>
</template>
<script>
const letters = [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
];
export default {
name: "question",
props: {
questionObj: {
type: Object,
default: () => {
return {
text: "asdfasdf",
question: [
"沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师",
"沙发斯蒂芬大师",
"沙发斯蒂芬大师",
"沙发斯蒂芬大师",
"沙发斯蒂芬大师",
],
};
},
},
nowQuestion: {
type: Number,
},
index: {
type: Number,
},
// 从外面传进来的选项,选择过的才有,没选择过的没有
selectLetter: {
type: [String, Number, Array],
default: () => {
return [];
},
},
},
data() {
return {
alignItemsCenter: false,
// 如果传进来了,就是这个值,如果没有就是null,因为动画需要那个key的问题,会清空原始的盒子,所以要传一下值
letterActive: this.selectLetter,
letters,
tipsArr: {
1: "单选题",
2: "多选题",
3: "判断题",
},
};
},
mounted() {
// console.log('123')
// 每次都会更新,所以不需要watch 直接在这里面写 因为动画需要那个key的问题,会清空原始的盒子,所以要传一下值
this.textCenter();
},
watch: {
// 监听一下当前题目,调整一下位置
// nowQuestion(value) {
// console.log('nowQuestion变化',value)
// this.$nextTick(() => {
// this.textCenter();
// });
// },
},
methods: {
textCenter() {
let h1 = this.$refs.text?.offsetHeight;
let h2 = this.$refs.top?.offsetHeight;
// 如果text大于或者等于top,就出不居中,如果不小于top,就上下居中
if (h2 <= h1) {
this.alignItemsCenter = false;
} else {
this.alignItemsCenter = true;
}
},
changeLetter(index) {
this.letterActive = [index];
this.$emit("changeLetter", this.letterActive);
// this.$emit("changeLetter", this.letters[index]);
},
},
};
</script>
<style lang="scss" scoped>
.question {
// position: absolute;
// top: 0px;
// display: inline-block;
width: 100%;
height: 370px;
padding-bottom: 10px;
border-bottom: 1px solid #bbbbbb;
// background: red;
flex-direction: column;
position: relative;
.tips {
width: 80px;
height: 24px;
background: #1d84ff;
font-size: 14px;
color: #fff;
position: absolute;
top: -45px;
left: 0px;
text-align: center;
line-height: 24px;
}
.top {
background: #f9f9f9;
height: 54px;
padding: 0px 10px 0px 43px;
overflow-wrap: anywhere;
// align-items: center;
overflow-y: auto;
position: relative;
.text {
font-size: 14px;
text-indent: 2em;
}
.num {
position: absolute;
left: 0;
width: 48px;
height: 48px;
top: 4px;
background: #1d84ff;
border-radius: 50%;
text-align: center;
line-height: 48px;
font-size: 18px;
color: #ffffff;
}
}
.middle {
flex: 1;
// background: blue;
overflow-y: auto;
padding-left: 43px;
padding-right: 10px;
margin-bottom: 15px;
.item {
padding-top: 38px;
width: 100%;
overflow-wrap: anywhere;
font-size: 14px;
color: #101010;
.letter {
padding: 2px;
margin-right: 10px;
box-sizing: border-box;
}
}
}
.bottom {
max-height: 70px;
// background: black;
padding-left: 43px;
padding-right: 10px;
overflow-y: auto;
.change-wrapper {
width: 756px;
flex-wrap: wrap;
margin: 0 auto;
.change {
width: 90px;
height: 30px;
background: #e8f4ff;
color: #101010;
border: 1px solid #a3d3ff;
line-height: 30px;
text-align: center;
margin: 0 9px 5px;
border-radius: 4px;
cursor: pointer;
&.active {
background: #1d84ff;
color: #ffffff;
border: 1px solid #a3d3ff;
}
&:hover {
background: rgba(29, 132, 255, 0.5);
color: #ffffff;
}
}
}
}
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-21 11:00:14
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2023-01-11 14:59:40
* @FilePath: /danger-manage-web/src/views/myLessons/components/Question.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="question flex">
<div class="tips">{{ tipsArr[questionObj.topicType] }}</div>
<div
class="top"
:class="{ flex: alignItemsCenter }"
:style="{ alignItems: alignItemsCenter ? 'center' : '' }"
ref="top"
>
<div class="text" ref="text">
{{ questionObj.text }}
</div>
<div class="num">{{ nowQuestion + 1 }}</div>
</div>
<div class="middle">
<div
class="item flex"
v-for="(item, index) in questionObj.question"
:key="item + 'aas' + index"
>
<div class="letter">
{{ letters[index] }}
</div>
<div class="">
{{ item }}
</div>
</div>
</div>
<div class="bottom flex">
<div class="change-wrapper flex">
<div
class="change"
:class="{ active: letterActive.indexOf(index) >= 0 }"
@click="changeLetter(index)"
v-for="(item, index) in questionObj.question"
:key="item + 'a' + index"
>
{{ letters[index] }}
</div>
</div>
</div>
</div>
</template>
<script>
const letters = [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
];
export default {
name: "question",
props: {
questionObj: {
type: Object,
default: () => {
return {
text: "asdfasdf",
question: [
"沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师沙发斯蒂芬大师",
"沙发斯蒂芬大师",
"沙发斯蒂芬大师",
"沙发斯蒂芬大师",
"沙发斯蒂芬大师",
],
};
},
},
nowQuestion: {
type: Number,
},
index: {
type: Number,
},
// 从外面传进来的选项,选择过的才有,没选择过的没有
selectLetter: {
type: [String, Number, Array],
default: () => {
return [];
},
},
},
data() {
return {
alignItemsCenter: false,
// 如果传进来了,就是这个值,如果没有就是null,因为动画需要那个key的问题,会清空原始的盒子,所以要传一下值
letterActive: this.selectLetter,
letters,
tipsArr: {
1: "单选题",
2: "多选题",
3: "判断题",
},
};
},
mounted() {
// console.log('123')
// 每次都会更新,所以不需要watch 直接在这里面写 因为动画需要那个key的问题,会清空原始的盒子,所以要传一下值
this.textCenter();
},
watch: {
// 监听一下当前题目,调整一下位置
// nowQuestion(value) {
// console.log('nowQuestion变化',value)
// this.$nextTick(() => {
// this.textCenter();
// });
// },
},
methods: {
textCenter() {
let h1 = this.$refs.text?.offsetHeight;
let h2 = this.$refs.top?.offsetHeight;
// 如果text大于或者等于top,就出不居中,如果不小于top,就上下居中
if (h2 <= h1) {
this.alignItemsCenter = false;
} else {
this.alignItemsCenter = true;
}
},
changeLetter(index) {
// this.letterActive = index;
const ind = this.letterActive.indexOf(index);
if (ind < 0) {
this.letterActive.push(index);
} else {
this.letterActive.splice(ind, 1);
}
this.$emit("changeLetter", this.letterActive);
// this.$emit("changeLetter", this.letters[index]);
},
},
};
</script>
<style lang="scss" scoped>
.question {
// position: absolute;
// top: 0px;
// display: inline-block;
width: 100%;
height: 370px;
padding-bottom: 10px;
border-bottom: 1px solid #bbbbbb;
// background: red;
flex-direction: column;
position: relative;
.tips {
width: 80px;
height: 24px;
background: #1d84ff;
font-size: 14px;
color: #fff;
position: absolute;
top: -45px;
left: 0px;
text-align: center;
line-height: 24px;
}
.top {
background: #f9f9f9;
height: 54px;
padding: 0px 10px 0px 43px;
overflow-wrap: anywhere;
// align-items: center;
overflow-y: auto;
position: relative;
.text {
font-size: 14px;
text-indent: 2em;
}
.num {
position: absolute;
left: 0;
width: 48px;
height: 48px;
top: 4px;
background: #1d84ff;
border-radius: 50%;
text-align: center;
line-height: 48px;
font-size: 18px;
color: #ffffff;
}
}
.middle {
flex: 1;
// background: blue;
overflow-y: auto;
padding-left: 43px;
padding-right: 10px;
margin-bottom: 15px;
.item {
padding-top: 38px;
width: 100%;
overflow-wrap: anywhere;
font-size: 14px;
color: #101010;
.letter {
padding: 2px;
margin-right: 10px;
box-sizing: border-box;
}
}
}
.bottom {
max-height: 70px;
// background: black;
padding-left: 43px;
padding-right: 10px;
overflow-y: auto;
.change-wrapper {
width: 756px;
flex-wrap: wrap;
margin: 0 auto;
.change {
width: 90px;
height: 30px;
background: #e8f4ff;
color: #101010;
border: 1px solid #a3d3ff;
line-height: 30px;
text-align: center;
margin: 0 9px 5px;
border-radius: 4px;
cursor: pointer;
&.active {
background: #1d84ff;
color: #ffffff;
border: 1px solid #a3d3ff;
}
&:hover {
background: rgba(29, 132, 255, 0.5);
color: #ffffff;
}
}
}
}
}
</style>
<template>
<div class="lession-right-wrapper flex">
<div class="top flex">
<div class="title">通知</div>
<div class="content-wrapper flex">
<div v-for="item in []" :key="item + ''" class="content flex">
<div class="left zzz">
啥啊啥飒哈市罚款收到回复夹寒暑假电烤炉付货款静安荟SDK复活卡开始了东航飞机好看的发
</div>
<div class="right">2022-9-15</div>
</div>
</div>
</div>
<div class="bottom flex">
<div class="title">考试历史</div>
<div class="th flex">
<div class="left">学习课程</div>
<div class="middle">考试时间</div>
<div class="right">得分</div>
</div>
<div v-for="item in list" :key="item.courseId" class="td flex" style="">
<div class="left zzz">{{ item.courseName }}</div>
<div class="middle zzz" :title="item.examinationTime">
{{ item.examinationTime }}
</div>
<div class="right flex">
<div class="a">
<!-- <span
class="text"
:class="{ red: item.examinationResult < item.qualifiedNum }"
>{{
(item.examinationResult &&item.topicNum)? Math.floor((item.examinationResult / item.topicNum) * 100):0
}}</span
>/<span>100</span> -->
<span class="text">{{item.examinationResult}}</span>/<span>{{item.totalScore}}</span>
</div>
<div class="b flex">
<div style="width: 60px">
<el-progress
:percentage="
Math.floor((item.examinationResult / item.totalScore) * 100)
"
:show-text="false"
></el-progress>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "lession-right",
props: {
list: {
type: Array,
default: () => {
return [];
},
},
},
data() {
return {};
},
mounted(){
console.log(this.list)
},
methods: {},
};
</script>
<style lang="scss" scoped>
.lession-right-wrapper {
width: 100%;
height: 100%;
flex-direction: column;
> div {
border: 1px solid#BBBBBB;
border-radius: 5px;
}
.top {
width: 100%;
height: 32.7%;
margin-bottom: 23px;
padding: 30px 19px 25px 21px;
flex-direction: column;
overflow: hidden;
.title {
font-size: 14px;
color: #606266;
margin-bottom: 20px;
}
.content-wrapper {
flex: 1;
width: 100%;
overflow-y: auto;
&::-webkit-scrollbar {
width: 0 !important;
}
flex-direction: column;
justify-content: space-between;
.content {
justify-content: space-between;
width: 100%;
font-size: 14px;
color: #7b808a;
.left {
flex: 1;
max-width: 304px;
margin-right: 19px;
}
.right {
min-width: 70px;
}
}
}
}
.bottom {
flex: 1;
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
flex-direction: column;
.title {
margin-left: 21px;
font-size: 14px;
color: #606266;
margin-bottom: 20px;
}
.th {
width: 100%;
height: 50px;
background: #e8f4ff;
justify-content: space-between;
padding-left: 21px;
padding-right: 25px;
margin-bottom: 14px;
> div {
width: 33%;
line-height: 50px;
font-size: 14px;
color: #606266;
text-align: center;
&.left {
width: 40%;
}
&.middle {
width: 30%;
}
&.right {
width: 30%;
text-align: center;
}
}
}
.td {
width: 100%;
height: 40px;
justify-content: space-between;
padding-left: 21px;
padding-right: 25px;
> div {
line-height: 40px;
font-size: 14px;
color: #606266;
text-align: center;
&.left {
width: 40%;
}
&.middle {
width: 30%;
}
&.right {
width: 30%;
overflow: hidden;
justify-content: space-between;
.a {
// width: 20px;
// overflow: hidden;
margin-right: 5px;
text-align: right;
flex: 1;
.text {
color: #32be0f;
&.red {
color: #d11414;
}
}
}
.b {
align-items: center;
// flex: 1;
> div {
width: 100%;
}
}
}
}
}
}
}
</style>
<!--
* @Author: 纪泽龙 jizelong@qq.com
* @Date: 2022-09-20 11:19:55
* @LastEditors: 纪泽龙 jizelong@qq.com
* @LastEditTime: 2022-09-28 13:24:36
* @FilePath: /danger-manage-web/src/views/myLessons/idnex.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div class="myLessons-wrapper flex">
<div class="left">
<Left @examination="examination" />
</div>
<div class="right">
<Right :list="list" />
</div>
<AnswerLesson
v-if="answerOpen"
:courseId="courseId"
:userCourseId="userCourseId"
:courseName = "courseName"
:visible.sync="answerOpen"
/>
</div>
</template>
<script>
import { getUserLessons } from "@/api/train/lessonsProgram";
import Left from "./components/Left";
import Right from "./components/Right";
import AnswerLesson from "./components/AnswerLesson";
export default {
name: "myLessons",
components: {
Left,
Right,
AnswerLesson,
},
data() {
return {
answerOpen: false,
courseId: "",
userCourseId: "",
courseName:"",
list: [],
};
},
created() {
this.getUserLessons();
},
methods: {
getUserLessons() {
getUserLessons().then((res) => {
console.log(res.rows);
this.list = res.rows.filter(item=>item.state>0);
});
},
examination(e) {
this.courseId = e.courseId;
this.userCourseId = e.userCourseId;
this.courseName = e.courseName;
// this.answerOpen=true;
},
},
};
</script>
<style lang="scss" scoped>
.myLessons-wrapper {
width: 100%;
height: calc(100vh - 50px);
padding: 38px 18px 42px;
box-sizing: border-box;
> div {
}
.left {
width: 72%;
height: 100%;
max-height: 940px;
margin-right: 25px;
border: 1px solid#BBBBBB;
border-radius: 5px;
}
.right {
flex: 1;
width: 100%;
height: 100%;
}
}
</style>
<template>
<div class="testStat">
<el-form
:model="queryParams"
ref="queryForm"
:inline="true"
label-width="68px">
<el-form-item label="考试名称" prop="courseName">
<el-input
v-model="queryParams.courseName"
placeholder="请输入课程名称"
clearable
size="small"
/>
</el-form-item>
<el-form-item label="类型" prop="dataKind">
<el-select v-model="queryParams.dataKind">
<el-option label="培训考试" value="0" />
<el-option label="随机考试" value="1" />
</el-select>
</el-form-item>
<el-form-item label="发布时间" prop="releaseTimeBegin">
<el-date-picker
v-model="releaseTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="dateFormat">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="search"
>搜索</el-button
>
<el-button icon="el-icon-refresh" size="mini" @click="resetClick"
>重置</el-button
>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="testStatData">
<el-table-column label="序号" width='100' align="center" prop="courseNum"/>
<el-table-column label="考试名称" align="center" prop="courseName"/>
<el-table-column label="发布时间" align="center" prop="releaseTime"/>
<el-table-column label="类型" align="center" prop="dataKind">
<template slot-scope="scope">
<span v-if="scope.row.dataKind == '0'">培训考试</span>
<span v-else>随机考试</span>
</template>
</el-table-column>
<el-table-column label="应参加人数" align="center" prop="count"/>
<el-table-column label="实际考试人数" align="center" prop="test"/>
<el-table-column label="合格人数" align="center" prop="pass"/>
<!-- <el-table-column label="合格率" align="center" prop="rate">-->
<!-- <template slot-scope="scope">-->
<!-- {{scope.row.rate}}%-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template v-slot="{ row: { courseId ,courseName}}">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="courseDetail(courseId,courseName)"
>查看详情</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getTestList"
/>
<!--考试详情 -->
<el-dialog :title="'考试详情:'+courseName" :visible.sync="testStatDetailOpen" append-to-body :close-on-click-modal="false">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
:loading="exportLoading"
@click="handleExport"
style="position: relative;left: 16px;top: -17px;"
>导出</el-button>
<el-table v-loading="loading" :data="testStatDetailData">
<el-table-column label="序号" width='100' align="center" prop="detailNum"/>
<el-table-column label="考试人员" align="center" prop="staffName"/>
<el-table-column label="所属部门" align="center" prop="deptName">
<span slot-scope="scope" v-if="scope.row.deptName">{{scope.row.deptName}}</span>
<span v-else>-</span>
</el-table-column>
<el-table-column label="考试时间" align="center" prop="examinationTime">
<span slot-scope="scope" v-if="scope.row.examinationTime">{{scope.row.examinationTime}}</span>
<span v-else>-</span>
</el-table-column>
<el-table-column label="得分" align="center" prop="examinationResult">
<span slot-scope="scope" v-if="scope.row.examinationResult">{{scope.row.examinationResult}}</span>
<span v-else>-</span>
</el-table-column>
<el-table-column label="考试结果" align="center" prop="state">
<template slot-scope="scope">
<span v-if="scope.row.state == 0">未考试</span>
<span v-if="scope.row.state == 1">不合格</span>
<span v-if="scope.row.state == 2">合格</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="totalDetail > 0"
:total="totalDetail"
:page.sync="queryDetailParams.pageNum"
:limit.sync="queryDetailParams.pageSize"
@pagination="getTestStatDetails"
/>
</el-dialog>
</div>
</template>
<script>
import {statisticsTrainCourse,testPersonDetailByCourseId,exportDeviceInfo} from "@/api/train/lessonsProgram.js";
export default {
name: "testStat",
data(){
return{
// 遮罩层
loading: false,
// 总条数
total: 0,
releaseTime: "",
courseName:"",
queryParams:{
pageNum: 1,
pageSize: 10,
courseName: "",
dataKind: "",
releaseTimeBegin: "",
releaseTimeEnd: ""
},
// 导出遮罩层
exportLoading: false,
testStatData:[],
testStatDetailOpen: false,
testStatDetailData: [],
totalDetail: 0,
queryDetailParams:{
pageNum: 1,
pageSize: 10,
courseId: 0
}
}
},
created(){
this.getTestList();
},
methods: {
/** 导出按钮操作 */
handleExport() {
this.$confirm('是否确认导出所有考试详细数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.exportLoading = true;
return exportDeviceInfo(this.queryDetailParams);
}).then(response => {
this.download(response.msg);
this.exportLoading = false;
}).catch(() => {});
},
getTestList(){
console.log("this.queryParams:",this.queryParams)
statisticsTrainCourse(this.queryParams).then(res=>{
this.testStatData = res.rows.map((item, index) => {
return {
courseNum:
index +
1 +
(this.queryParams.pageNum - 1) * this.queryParams.pageSize,
...item,
};
});
this.total = res.total;
}) .finally(() => {
this.loading = false;
});
},
dateFormat(picker){
this.queryParams.releaseTimeBegin = picker[0];
this.queryParams.releaseTimeEnd = picker[1];
},
search(){
this.getTestList();
},
resetClick(){
this.releaseTime = "";
this.queryParams={
pageNum: 1,
pageSize: 10,
courseName: "",
dataKind: "",
releaseTimeBegin: "",
releaseTimeEnd: ""
};
this.getTestList();
},
courseDetail(courseId,courseName){
this.testStatDetailOpen = true;
this.courseName=courseName;
this.queryDetailParams.courseId=courseId;
this.getTestStatDetails();
},
getTestStatDetails(){
//this.queryDetailParams.courseId = courseId;
testPersonDetailByCourseId(this.queryDetailParams).then(res =>{
this.testStatDetailData = res.rows.map((item, index) => {
return {
detailNum:
index +
1 +
(this.queryParams.pageNum - 1) * this.queryParams.pageSize,
...item,
};
});
this.totalDetail = res.total;
}) .finally(() => {
this.loading = false;
});
}
}
}
</script>
<style scoped lang="scss">
.testStat{
margin: 10px;
}
</style>
<template>
<div style="margin: 10px">
<el-form
:model="queryParams"
ref="queryForm"
:inline="true"
label-width="68px">
<el-form-item label="培训部门" prop="deptId">
<treeselect v-model="queryParams.deptId" style="width: 220px;" :options="deptOptions" :show-count="true" placeholder="请选择培训部门" />
</el-form-item>
<el-form-item label="培训名称" prop="courseName">
<el-input
v-model="queryParams.courseName"
placeholder="请输入培训名称"
clearable
size="small"
/>
</el-form-item>
<el-form-item label="发布时间" prop="releaseTime">
<el-date-picker
v-model="releaseTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="dateFormat">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="search"
>搜索</el-button
>
<el-button icon="el-icon-refresh" size="mini" @click="resetClick"
>重置</el-button
>
</el-form-item>
</el-form>
<!-- 培训统计列表 -->
<el-table v-loading="loading" :data="trainCourseStatData">
<el-table-column label="序号" width='100' align="center" prop="courseNum"/>
<el-table-column label="培训部门" align="center" prop="deptName" width="120"/>
<el-table-column label="课程标题" align="center" prop="courseName"/>
<el-table-column label="培训计划" align="center" prop="planName"/>
<el-table-column label="应参加人数" align="center" prop="maybeTestNum" width="100"/>
<el-table-column label="实际完成人数" align="center" prop="finishNum" width="100"/>
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template v-slot="{ row: { courseId, courseName }}">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="trainCourseStatDetail(courseId,courseName)"
>查看详情</el-button>
</template>
</el-table-column>
</el-table>
<!-- 列表分页 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getTrainStatList"
/>
<!-- 详情 -->
<el-dialog :title="'培训详情:'+courseName" :visible.sync="trainStatDetailOpen" append-to-body :close-on-click-modal="false">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
:loading="exportLoading"
@click="handleExport"
style="position: relative;left: 16px;top: -17px;"
>导出</el-button>
<el-table v-loading="loading" :data="trainStatDetailData">
<el-table-column label="序号" width='100' align="center" prop="detailNum"/>
<el-table-column label="培训人员" align="center" prop="nickName"/>
<el-table-column label="所属部门" align="center" prop="deptName"/>
<el-table-column label="培训时长" align="center" prop="finishDuration"/>
<el-table-column label="是否完成" align="center" prop="isComplete"/>
</el-table>
<pagination
v-show="totalDetail > 0"
:total="totalDetail"
:page.sync="queryDetailParams.pageNum"
:limit.sync="queryDetailParams.pageSize"
@pagination="getTrainStatDetail"
/>
</el-dialog>
</div>
</template>
<script>
import {getTrainCourseStatData,getTrainCourseStatDetailData,trainCourseStatDetailExport} from "@/api/train/trainCourseStat";
import { treeselect } from "@/api/system/dept";
import Treeselect from "@riophae/vue-treeselect";
export default {
name: "trainCourseStat",
components: {
Treeselect
},
data() {
return {
queryParams: {
pageNum: 1,
pageSize: 10,
courseName:"",
releaseBeginTime: "",
releaseEndTime: ""
},
releaseTime: "",
trainCourseStatData: [],
// 遮罩层
loading: false,
// 总条数
total: 0,
totalDetail: 0,
queryDetailParams:{
pageNum: 1,
pageSize: 10,
courseId: ""
},
courseName: "",
trainStatDetailOpen: false,
trainStatDetailData: [],
exportLoading: false,
// 部门树选项
deptOptions: undefined,
}
},
created() {
this.getTrainStatList();
this.getTreeselect();
},
methods: {
/** 查询部门下拉树结构 */
getTreeselect() {
treeselect().then(response => {
console.log('部门树返回值')
this.deptOptions = response.data;
});
},
dateFormat(picker){
this.queryParams.releaseBeginTime = picker[0];
this.queryParams.releaseEndTime = picker[1];
},
search(){
this.getTrainStatList();
},
resetClick(){
this.releaseTime = "";
this.queryParams.releaseBeginTime = null;
this.queryParams.releaseEndTime = null;
this.queryParams={
pageNum: 1,
pageSize: 10,
courseName:"",
releaseBeginTime: "",
releaseEndTime: ""
};
this.getTrainStatList();
},
getTrainStatList(){
getTrainCourseStatData(this.queryParams).then(res =>{
this.trainCourseStatData = res.rows.map((item, index) => {
return {
courseNum:
index +
1 +
(this.queryParams.pageNum - 1) * this.queryParams.pageSize,
...item,
};
});
this.total = res.total;
})
},
trainCourseStatDetail(courseId,courseName){
this.queryDetailParams.courseId = courseId;
this.courseName = courseName;
this.queryDetailParams.pageNum = 1;
this.queryDetailParams.pageSize = 10;
this.getTrainStatDetail();
this.trainStatDetailOpen = true;
},
getTrainStatDetail(){
getTrainCourseStatDetailData(this.queryDetailParams).then(res =>{
this.trainStatDetailData = res.rows.map((item, index) => {
return {
detailNum:
index +
1 +
(this.queryDetailParams.pageNum - 1) * this.queryDetailParams.pageSize,
...item,
};
});
this.totalDetail = res.total;
})
},
handleExport(){
this.$confirm('是否确认导出所有培训详细数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.exportLoading = true;
return trainCourseStatDetailExport({"courseId":this.queryDetailParams.courseId});
}).then(response => {
this.download(response.msg);
this.exportLoading = false;
}).catch(() => {});
},
},
};
</script>
<style lang="scss" scoped>
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment