You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

650 lines
23 KiB

<template>
<div>
<el-form :disabled="isDetail">
<el-card shadow="hover" class="m-b-20">
<div class="flex-between">
<el-page-header @back="goBack" :content="isDetail ? '查看' : (form.id ? '更新' : '创建') + '考核'"></el-page-header>
<div>
<el-button type="primary" @click="save(0)" v-show="!isDetail">{{ form.id ? "更新" : "创建" }}</el-button>
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgr20 m-b-20">
<div>
<p class="m-b-20">考核名称</p>
<el-input placeholder="请输入考核名称" v-model.trim="form.experimentalName" clearable maxlength="15"
class="inline-input"></el-input>
</div>
</el-card>
<el-card shadow="hover" class="m-b-20">
<div>
<p class="m-b-20">发布方式</p>
<el-radio-group v-model="form.type">
<el-radio :label="1">手动发布</el-radio>
<el-radio :label="2">定时发布</el-radio>
</el-radio-group>
</div>
</el-card>
<!-- 根据发布方式判断时间的显示 -->
<el-card shadow="hover" class="m-b-20">
<div>
<p class="m-b-20">考核时间</p>
<!-- 手动发布显示 -->
<div class="date-inputs" v-if="form.type == 1">
考核时长:
<el-input type="number" min="0" v-model.trim="duration.day" placeholder></el-input>
<el-input type="number" min="0" v-model.trim="duration.hour" placeholder></el-input>
小时
<el-input type="number" min="0" v-model.trim="duration.minute" placeholder></el-input>
</div>
<!-- 定时发布显示 -->
<div v-if="form.type == 2" class="addAssess">
<span class="mgr10">开始时间:</span>
<el-date-picker size="small" v-model="date" type="datetimerange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="pickerOptions"></el-date-picker>
</div>
</div>
</el-card>
<el-card shadow="hover" class="mgr20 m-b-20">
<div>
<p class="m-b-20">课程</p>
<div class="inline-input">
<el-select v-model="form.mallId" @change="initData">
<el-option v-for="item in curriculumList" :key="item.mallId" :label="item.curriculumName"
:value="item.mallId">
</el-option>
</el-select>
<!-- <el-select v-model="form.curriculumId" @change="initData">
<el-option
v-for="item in systemList"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-select> -->
</div>
</div>
</el-card>
<!-- 实训项目模块 -->
<el-card shadow="hover" class="m-b-20">
<div class="flex-between m-b-20">
<span>考核项目</span>
<div style="display: inline-flex;">
<div>
<el-input placeholder="请输入项目名称" prefix-icon="el-icon-search" v-model.trim="keyword" clearable></el-input>
</div>
<el-button style="margin-left: 5px" type="primary" round @click="toProject">自定义实验项目</el-button>
</div>
</div>
<!-- 实训项目表格 -->
<el-table :data="projectData" class="table" header-align="center">
<!-- 单选实训项目ID -->
<el-table-column width="60" label="选择" align="center">
<template slot-scope="scope">
<el-radio v-model="form.uuid" :label="scope.row.uuid">&nbsp;</el-radio>
</template>
</el-table-column>
<el-table-column prop="projectName" label="项目名称" align="center"></el-table-column>
<el-table-column prop="auth" label="项目权限" align="center">
<template slot-scope="scope">
{{ permissionsKeys[scope.row.permissions] }}
</template>
</el-table-column>
<!-- <el-table-column prop="createUser" label="创建人" align="center"></el-table-column> -->
<el-table-column prop="founder" label="创建人" align="center">
<template slot-scope="scope">
{{ scope.row.createUser }}
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button type="text" @click="showProject(scope.row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background :page-size="pageSize" @current-change="handleCurrentChange"
layout="total,prev, pager, next" :total="total"></el-pagination>
</div>
</el-card>
<el-card shadow="hover" class="mgr20 m-b-20">
<div>
<p class="m-b-20">考核发布</p>
<el-radio-group v-model="form.isSpecify">
<el-radio :label="1">指定范围</el-radio>
<el-radio :label="0">无指定范围</el-radio>
</el-radio-group>
</div>
<div v-show="form.isSpecify == 1" style="padding-top: 24px;">
<p class="m-b-20">班级名称</p>
<el-input placeholder="请输入班级名称" v-model.trim="filterClassName" class="inline-input m-b-20" clearable>
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
<div v-show="tagList.length" class="m-b-20">
<el-tag v-for="(tag, index) in tagList" :key="index" closable @close="handleCloseTag(tag)"
style="margin-right: 10px">
{{ tag.organizationName }}
</el-tag>
</div>
<div class="tree-con">
<student-tree ref="tree" node-key="id" show-checkbox highlight-current default-expand-all lazy
:load="loadTree" :default-checked-keys="defaultCheckedKeys"
:props="{ children: 'children', label: 'organizationName', isLeaf: 'leaf' }"
:filter-node-method="filterNode" @check="handleCheck">
</student-tree>
</div>
</div>
</el-card>
<!-- 邀请码 -->
<el-card v-if="form.isSpecify == 0" shadow="hover" class="m-b-20">
<div style="margin-bottom: 10px">
<p class="m-b-20">设置邀请码</p>
<el-radio-group v-model="form.isEnableCode">
<el-radio :label="1">是</el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</div>
<div v-if="form.isEnableCode == 1">
<el-input style="display: inline-block;width: auto;margin-right: 10px" type="number"
v-model.trim="form.invitationCode" maxlength="6" placeholder="请设置6个数字"></el-input>
<el-button type="text" @click="createInv">随机</el-button>
</div>
</el-card>
</el-form>
</div>
</template>
<script>
import Setting from '@/setting'
import Util from '@/libs/util'
import { mapState, mapActions } from "vuex";
import StudentTree from "@/components/student-tree/src/tree";
import qs from 'qs'
export default {
components: { StudentTree },
data () {
return {
token: Util.local.get(Setting.tokenKey),
founderKeys: {
0: "系统",
1: "老师"
},
cidList: [],
permissionsKeys: {
0: "练习",
1: "考核",
2: "竞赛"
},
isDetail: Boolean(this.$route.query.show),
form: {
id: this.$route.query.id ? this.$route.query.id : "",
experimentalName: "",
type: 1, // 发布类型(1、手动发布 2、定时发布)
experimentDuration: "0d0h0m",
curriculumId: "",
mallId: '',
projectId: '',
paperId: '',
isSpecify: 1, // 考核发布(1、指定范围 0、无指定范围)
isEnableCode: 0, //是否设置邀请码
invitationCode: "",
status: 0, // 状态(0、待开始 1、进行中 2、已结束)
classId: "",
stuInfo: []
},
date: "", // 实验时间
duration: {
day: "",
hour: "",
minute: ""
}, // 实验时长
startTime: "0000-00-00 00:00:00", //开始时间
stopTime: "0000-00-00 00:00:00", //结束时间
expNameRepeat: false, // 考核名称是否重复
curriculumList: [], // 课程列表
filterClassName: "", // 班级名称搜索
tagList: [], // 班级名称标签
defaultCheckedKeys: [], // 默认选中
allCheckedNodes: [], // 当前选中和半选节点
keyword: "", // 项目名称搜索
searchTimer: null,
surplusTime: "",
projectDataAll: [],
projectData: [],
pickerOptions: {
disabledDate: time => {
return time.getTime() < new Date().getTime() - 86400000;
}
},
page: 1,
pageSize: 5,
total: 0,
isToProject: false,
systemList: [],
submiting: false, // 新增编辑防抖标识
updateTime: 0
};
},
computed: {
...mapState("project", [
"assFields"
])
},
// 离开的时候判断是否有保存更改的信息,没有则拦截并提示
beforeRouteLeave (to, from, next) {
if (!this.isToProject && this.updateTime) {
this.$confirm(`您所更改的内容未更新,是否更新?`, '提示', {
type: 'warning',
closeOnClickModal: false
}).then(() => {
this.save(next)
}).catch(() => {
next()
})
} else {
next()
}
},
beforeDestroy () {
if (!this.isToProject) this.setAss({});
},
mounted () {
this.date = [Util.formatDate("yyyy-MM-dd hh:mm:ss", new Date(new Date().getTime() + 300000)), Util.formatDate("yyyy-MM-dd hh:mm:ss", new Date(new Date().getTime() + 300000))];
this.form.id && this.getData();
this.recoveryData();
this.getschoolCourse();
},
watch: {
// 监听信息是否有更改,有的话页面离开的时候要询问是否要保存
form: {
handler (val) {
this.updateTime++
},
deep: true
},
date: function (val) {
if (val[0] != "0000-00-00 00:00:00") {
this.startTime = Util.formatDate("yyyy-MM-dd hh:mm:ss", new Date(val[0]));
this.stopTime = Util.formatDate("yyyy-MM-dd hh:mm:ss", new Date(val[1]));
this.updateTime++
}
},
duration: {
handler (n, o) {
this.form.experimentDuration = `${n.day ? n.day : 0}d${n.hour ? n.hour : 0}h${n.minute ? n.minute : 0}m`;
this.updateTime++
},
deep: true
},
keyword: function (val) {
clearTimeout(this.searchTimer);
this.searchTimer = setTimeout(() => {
this.initData();
}, 500);
},
filterClassName (val) {
this.$refs.tree.filter(val);
}
},
methods: {
...mapActions("project", [
"setAss"
]),
handleCloseTag (tag) { // 关闭班级标签
this.allCheckedNodes = this.$refs.tree.getCheckedNodes().concat(this.$refs.tree.getHalfCheckedNodes());
let tagIndex = this.tagList.findIndex(i => i.id === tag.id);
this.tagList.splice(tagIndex, 1);
// 设置选中
let setKeys = [];
this.allCheckedNodes.forEach(i => {
if (i.level === 4 && i.parentId !== tag.id) setKeys.push(i.nodeKey);
});
this.$refs.tree.setCheckedKeys(setKeys);
this.allCheckedNodes = this.allCheckedNodes.filter(i => (i.level === 3 && i.id !== tag.id) || (i.level === 4 && i.parentId !== tag.id));
},
handleCheck (data, checked) { // 当复选框被点击的时候触发
// 全选和半选状态下的班级都显示在标签
let checkedClass = checked.checkedNodes.filter(i => i.level === 3);
let halfCheckedClass = checked.halfCheckedNodes.filter(i => i.level === 3);
this.tagList = [...checkedClass, ...halfCheckedClass].map(i => {
return { id: i.id, organizationName: i.organizationName };
});
// 缓存全选和半选状态下的所有节点
this.allCheckedNodes = [...checked.checkedNodes, ...checked.halfCheckedNodes];
},
filterNode (value, data) { // 对树节点进行过滤
if (!value) return true;
return data.organizationName.indexOf(value) !== -1;
},
loadTree (node, resolve) { // 懒加载所在班级树结构
let level = 1;
let parentId = "";
if (node.level === 0) {
this.treeNode = node;
this.treeResolve = resolve;
this.getTreeData(resolve, level, parentId);
} else if (node.level > 3) {
return resolve([]);
} else {
if (node.data && node.data.level && node.data.id) {
this.getTreeData(resolve, node.data.level + 1, node.data.id);
}
}
},
async getTreeData (resolve, level, parentId) { // 获取组织架构树数据
let { status, treeList } = await this.$post(`${this.api.stuOrganizationTree}?level=${level}&parentId=${parentId}`);
if (status === 200 && treeList.length) {
let result = [];
treeList.forEach(i => {
if (i.level === 4) {
i.nodeKey = `${i.parentId}-${i.id}`;
i.leaf = true;
} else {
i.nodeKey = `${i.id}-${new Date().getTime()}`;
i.leaf = false;
}
result.push(i);
});
this.$nextTick(() => {
// 编辑时,设置默认勾选
if (this.form.classInfo && this.form.classInfo.length) {
let keys = this.form.classInfo.map(i => {
return i.id;
});
this.defaultCheckedKeys = keys;
}
// 获取树结构选中和半选中状态下的数据
let nodes = this.$refs.tree.getCheckedNodes().concat(this.$refs.tree.getHalfCheckedNodes());
this.allCheckedNodes = nodes;
this.tagList = nodes.filter(i => i.level === 3);
});
return resolve(result);
} else {
return resolve([]);
}
},
getschoolCourse () { // 获取课程
this.$get(this.api.getSchoolEffectiveCourse).then(({ data }) => {
this.curriculumList = data;
if (this.curriculumList.length) {
if (!this.form.mallId) this.form.mallId = data[0].mallId
this.getProjectData()
}
this.$nextTick(() => {
this.updateTime = 0
})
}).catch(err => { });
},
getProjectData () {
const curItem = this.curriculumList.find(e => e.mallId === this.form.mallId)
let data = {
pageNum: this.page,
pageSize: this.pageSize,
cid: curItem.cid,
projectName: this.keyword,
systemId: curItem ? curItem.systemId : 1,
permissions: 1,
mallId: this.form.mallId
}
this.$post(this.api.getProjectOrExamPaperByAssessment, data).then(({ data }) => {
const list = data.records
list.forEach(e => {
e.uuid = e.projectId || e.paperId // 唯一标识
})
this.projectData = list
this.total = data.total
}).catch(err => { })
},
handlePage () {
let result = this.projectDataAll.slice((this.page - 1) * this.pageSize, this.page * this.pageSize);
this.projectData = result;
},
initData () {
this.page = 1;
this.getProjectData();
},
save (cb) { // 提交
if (this.submiting) return false
const { form } = this
if (!this.form.experimentalName) return Util.warningMsg("请填写考核名称");
if (this.expNameRepeat) return Util.warningMsg("考核名称重复,请重新输入");
if (this.form.type !== 1) {
if (new Date().getTime() > new Date(this.startTime).getTime()) return Util.warningMsg("开始时间不能早于当前时间");
let timestamp = new Date(new Date(this.stopTime).getTime() - new Date(this.startTime).getTime());
let minute = 1000 * 60;
let hour = minute * 60;
let day = hour * 24;
this.form.experimentDuration = `${Math.floor(timestamp / day)}d${Math.floor(timestamp % day / hour)}h${Math.floor(timestamp % day % hour / minute)}m`;
}
if (this.form.type == 1 && this.form.experimentDuration == "0d0h0m") return Util.warningMsg("请填写考核时长");
if (this.form.type == 2 && this.startTime == "0000-00-00 00:00:00") return Util.warningMsg("请填写考核时间");
if (this.form.type == 1) {
const { day, hour, minute } = this.duration
if (String(day).includes('.')) return Util.warningMsg('考核天数请填写整数')
if (day < 0) return Util.warningMsg('考核天数请勿填写负数')
if (String(hour).includes('.')) return Util.warningMsg('考核小时请填写整数')
if (hour < 0) return Util.warningMsg('考核小时请勿填写负数')
if (String(minute).includes('.')) return Util.warningMsg('考核分钟请填写整数')
if (minute < 0) return Util.warningMsg('考核分钟请勿填写负数')
}
if (!form.uuid) return Util.warningMsg("请选择考核项目");
const item = this.projectData.find(e => form.uuid === e.projectId || form.uuid === e.paperId)
if (item) form[item.projectId ? 'projectId' : 'paperId'] = form.uuid
if (this.form.isSpecify == 0 && this.form.isEnableCode == 1) {
if (!this.form.invitationCode) return Util.warningMsg("请设置邀请码");
if (!this.form.invitationCode || String(this.form.invitationCode).length < 6 || isNaN(this.form.invitationCode)) return Util.warningMsg("请输入6位纯数字邀请码");
}
this.form.startTime = this.form.type == 2 ? this.startTime : ''
this.form.stopTime = this.form.type == 2 ? this.stopTime : ''
let classId = [];
let stuInfo = [];
this.allCheckedNodes.forEach(i => {
if (i.level === 3) {
classId.push(i.id);
} else if (i.level === 4) {
stuInfo.push({ classId: i.parentId, stuAccountId: i.id });
}
});
if (this.isSpecify == 1 && !stuInfo.length) {
Util.warningMsg("请选择学生");
return;
} else {
this.form.classId = classId.toString();
this.form.stuInfo = stuInfo;
}
const curItem = this.curriculumList.find(e => e.mallId === this.form.mallId)
this.form.curriculumId = curItem.cid
this.submiting = true
if (this.form.id) {
this.$post(this.api.modifyAssessment, this.form).then(async res => {
this.updateTime = 0
Util.successMsg("修改成功");
cb ? cb() : this.backPage()
}).catch(err => {
this.submiting = false
});
} else {
this.$post(this.api.saveAssessment, this.form).then(res => {
this.updateTime = 0
Util.successMsg("创建成功");
cb ? cb() : this.$router.push('list')
}).catch(err => {
this.submiting = false
});
}
},
getData () { // 获取详情
this.$get(`${this.api.getDetailById}?id=${this.form.id}`).then(({ data }) => {
this.form = data;
this.startTime = data.startTime
this.stopTime = data.stopTime
this.formatDuration();
this.getschoolCourse();
}).catch(err => {
});
},
formatDuration () { // 格式化实验时长
let duration = this.form.experimentDuration.replace(/\D+/g, ",").split(",");
this.duration = {
day: duration[0],
hour: duration[1],
minute: duration[2]
};
this.date = [this.startTime, this.stopTime];
this.$nextTick(() => {
this.updateTime = 0
})
},
recoveryData () { // 恢复数据
if (JSON.stringify(this.assFields) != "{}") {
let info = this.assFields;
this.form = info.form;
this.duration = info.duration; // 实验时长
this.startTime = info.startTime; //开始时间
this.stopTime = info.startTime; //结束时间
this.expNameRepeat = info.expNameRepeat; // 考核名称是否重复
this.allCheckedNodes = info.allCheckedNodes; // 选中的树节点
this.formatDuration();
}
},
handleCacheData () { // 缓存数据,用于从项目管理页面返回时,数据回显
this.allCheckedNodes.forEach(i => {
if (i.level === 4) {
this.form.stuInfo.push({ classId: i.parentId, stuAccountId: i.id });
}
});
let data = {
form: this.form,
date: this.date, // 实验时间
duration: this.duration, // 实验时长
startTime: this.startTime, //开始时间
stopTime: this.startTime, //结束时间
expNameRepeat: this.expNameRepeat, // 考核名称是否重复
allCheckedNodes: this.allCheckedNodes // 选中的树节点
};
this.setAss(data)
this.isToProject = true
},
toProject () {
this.handleCacheData()
this.$router.push("/project/list?show=1")
},
showProject (row) {
this.handleCacheData()
if (row.paperId) {
// 理论试卷
let url = `${location.origin}/examination`
if (Setting.isDev) {
url = `http://192.168.31.125:8098/`
} else if (Setting.isPro) {
const { host } = location
url = `https://${host === 'dev.huorantech.cn' ? host : 'www.huorantech.cn'}/examination/`
}
url += `#/testPaper/preview?id=${row.paperId}&token=${this.token}`
localStorage.setItem('exam_token', this.token)
window.open(url)
} else {
// 实训
this.$router.push(`/project/add?projectId=${row.projectId}&show=1&ass=1`)
}
},
createInv () {
let result = "";
for (let i = 0; i < 6; i++) {
result += Math.floor(Math.random() * 10);
}
this.form.invitationCode = result;
},
handleCurrentChange (val) {
this.page = val;
this.getProjectData();
},
// 返回上一页
backPage () {
this.$router.push(this.$store.state.achievement.referrer)
},
goBack () {
// 更改了信息才需要提示
if (this.updateTime) {
this.$confirm(`编辑的内容未保存,是否保存?`, '提示', {
type: 'warning',
closeOnClickModal: false
}).then(() => {
this.save()
}).catch(() => {
this.updateTime = 0
this.backPage()
})
} else {
this.updateTime = 0
this.backPage()
}
}
}
};
</script>
<style lang="scss" scoped>
.inline-input {
width: 500px;
}
.date-inputs {
.el-input {
width: 100px;
}
}
.tree-con {
height: 400px;
max-height: 400px;
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 10px 10px 10px 40px;
overflow: auto;
/deep/ .el-tree-node__content {
height: 30px;
.el-tree-node__expand-icon {
padding: 2px;
color: #fff;
background-color: $main-color;
border-radius: 30px;
margin: 0 10px;
}
.el-tree-node__expand-icon.is-leaf {
background-color: transparent;
}
.el-icon-caret-right:before {
font-size: 14px;
}
.el-checkbox__inner {
width: 18px;
height: 18px;
border: 1px solid $main-color$main-color;
border-radius: 20px;
}
.el-checkbox__inner::after {
position: absolute;
top: 3px;
left: 6px;
}
.el-checkbox__input.is-indeterminate .el-checkbox__inner::before {
position: absolute;
top: 7px;
}
}
}
</style>