提交 75337078 authored 作者: 王鹏飞's avatar 王鹏飞

updates

上级 b9a7235c
...@@ -5,6 +5,8 @@ module.exports = { ...@@ -5,6 +5,8 @@ module.exports = {
extends: ['plugin:vue/essential', 'standard'], extends: ['plugin:vue/essential', 'standard'],
rules: { rules: {
'vue/comment-directive': 'off', 'vue/comment-directive': 'off',
'vue/multi-word-component-names': 'off',
'vue/no-mutating-props': 'off', // 暂时关闭
'space-before-function-paren': 'off' 'space-before-function-paren': 'off'
} }
} }
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="https://zws-imgs-pub.ezijing.com/pc/base/favicon.ico" /> <link rel="icon" href="https://zws-imgs-pub.ezijing.com/pc/base/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>金融数据合规管理系统-紫荆教育</title> <title></title>
<link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet"> <link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet" />
<script src="https://unpkg.com/video.js/dist/video.min.js"></script> <script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<!-- <script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script> --> <!-- <script src="https://unpkg.com/videojs-contrib-hls/dist/videojs-contrib-hls.js"></script> -->
</head> </head>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -10,28 +10,30 @@ ...@@ -10,28 +10,30 @@
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src" "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src"
}, },
"dependencies": { "dependencies": {
"axios": "^0.22.0", "axios": "^0.26.0",
"element-ui": "^2.15.6", "element-ui": "^2.15.6",
"query-string": "^7.0.1", "lodash": "^4.17.21",
"query-string": "^7.1.1",
"video.js": "^7.17.0",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-meta": "^2.4.0",
"vue-router": "^3.5.2", "vue-router": "^3.5.2",
"vue-video-player": "^5.0.2",
"vuex": "^3.6.2" "vuex": "^3.6.2"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-eslint": "^8.0.1", "ali-oss": "^6.17.1",
"ali-oss": "^6.16.0",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-standard": "^16.0.3", "eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.24.2", "eslint-plugin-import": "^2.25.4",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0", "eslint-plugin-promise": "^5.2.0",
"eslint-plugin-vue": "^7.19.1", "eslint-plugin-vue": "^8.4.1",
"sass": "1.42.1", "sass": "1.49.8",
"vite": "^2.6.5", "vite": "^2.8.4",
"vite-plugin-vue2": "^1.8.2", "vite-plugin-checker": "^0.4.2",
"vite-plugin-vue2": "^1.9.3",
"vue-template-compiler": "^2.6.14" "vue-template-compiler": "^2.6.14"
} }
} }
...@@ -3,3 +3,13 @@ ...@@ -3,3 +3,13 @@
<router-view /> <router-view />
</div> </div>
</template> </template>
<script>
export default {
metaInfo() {
return {
title: this.$store.state.appConfig.title
}
}
}
</script>
...@@ -29,23 +29,23 @@ export function uploadFile(data) { ...@@ -29,23 +29,23 @@ export function uploadFile(data) {
} }
// 获取所有权限 // 获取所有权限
// export function getPermissions() { // export function getPermissions() {
// return httpRequest.get('/api/lms-financial/school/permission/get-permissions') // return httpRequest.get('/api/zy/school/permission/get-permissions')
// } // }
/** /**
* 获取权限列表 * 获取权限列表
*/ */
export function getPermissions(params) { export function getPermissions(params) {
return httpRequest.get('/api/permissions/api/v1/user/permissions', { params }) return httpRequest.get('/api/zy/school/permission/get-permissions', { params })
} }
/** /**
* 获取课程列表 * 获取课程列表
*/ */
export function getCourseList(params) { export function getCourseList(params) {
return httpRequest.get('/api/lms-financial/school/course/list', { params }) return httpRequest.get('/api/zy/school/course/list', { params })
} }
/** /**
* 获取班级列表 * 获取班级列表
*/ */
export function getClassList() { export function getClassList() {
return httpRequest.get('/api/lms-financial/school/class/list', { params: { page: 'false' } }) return httpRequest.get('/api/zy/school/class/list', { params: { page: 'false' } })
} }
import httpRequest from '@/utils/axios'
/**
* 获取模拟考试试题
*/
export function getExamList(params) {
return httpRequest.get('/api/zy/v2/examination/examination-papers-list', { params })
}
/**
* 获取模拟考试试题
*/
export function getExamQuestion(params) {
return httpRequest.get(
'/api/zy/v2/examination/examination-papers',
{ params },
{ headers: { 'Content-Type': 'multipart/form-data' } }
)
}
/**
* 缓存模拟考试试题
*/
export function setCache(params) {
return httpRequest.post('/api/zy/v2/examination/examination-papers', params)
}
/**
* 获取考试的状态
*/
export function getExamStatus(params) {
return httpRequest.get('/api/zy/v2/examination/examination-papers-status', { params })
}
/**
* 模拟考试设置角色
*/
export function setRoles(params) {
return httpRequest.post('/api/zy/v2/examination/role', params)
}
/**
* 获取我的已做试题
*/
export function getMyQuestion(params) {
return httpRequest.get(
'/api/zy/v2/examination/my-question',
{ params },
{
headers: { 'Content-Type': 'multipart/form-data' }
}
)
}
/**
* 获取我的所有试题
*/
export function getAllQuestion(params) {
return httpRequest.get('/api/zy/v2/examination/my-question-all', { params })
}
/**
* 缓存错题集
*/
export function setMyCache(params) {
return httpRequest.post('/api/zy/v2/examination/cache-question', params)
}
/**
* 收藏试题
*/
export function addCollection(params) {
return httpRequest.post('/api/zy/v2/examination/add-collection', params)
}
/**
* 取消收藏试题
*/
export function deleteCollection(params) {
return httpRequest.post('/api/zy/v2/examination/delete-my-question', params)
}
/**
* 删除试题
*/
export function deleteQuestion(params) {
return httpRequest.post('/api/zy/v2/examination/delete-my-question', params)
}
/**
* 知识点题获取
*/
export function getCourseQuestion(params) {
return httpRequest.get('/api/zy/v2/examination/course-papers', { params })
}
/**
* 知识点题缓存
*/
export function setCourseCache(params) {
return httpRequest.post('/api/zy/v2/examination/course-papers', params)
}
/**
* 老师批阅
*/
export function getReviewDetails(params) {
return httpRequest.get('/api/zy/school/examination/sheet-details', { params })
}
/**
* 提交批阅
*/
export function submitReviewDetails(params) {
return httpRequest.post('/api/zy/school/examination/sheet-submit', params)
}
export default [
{
name: '金融产品数字化营销',
tenant: 'x1',
title: '学校管理系统-紫荆教育',
hosts: ['fd-admin', 'fd-admin2']
},
{
name: '金融数据合规管理',
tenant: 'financial',
title: '金融数据合规管理系统-紫荆教育',
logo: 'https://webapp-pub.ezijing.com/x-training-new/fd-logo2.png',
hosts: ['x-school', 'x-school2']
}
]
html * { /* html * {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
outline: none; outline: none;
-webkit-text-size-adjust: none; -webkit-text-size-adjust: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
} } */
body, body,
h1, h1,
h2, h2,
......
<template>
<el-dialog v-bind="$attrs" v-on="$listeners" width="600px">
<el-tabs v-model="activeName">
<el-tab-pane :label="`全部(${students.length})`" name="0">
<ul>
<li v-for="(student, index) in students" :key="index" @click="$emit('studentReview', student)">
{{ student.name }}
</li>
</ul>
</el-tab-pane>
<el-tab-pane :label="`未批阅(${unreviewedStudents.length})`" name="1">
<ul>
<li v-for="(student, index) in unreviewedStudents" :key="index" @click="$emit('studentReview', student)">
{{ student.name }}
</li>
</ul>
</el-tab-pane>
<el-tab-pane :label="`已批阅(${reviewedStudents.length})`" name="2">
<ul>
<li v-for="(student, index) in reviewedStudents" :key="index" @click="$emit('studentReview', student)">
{{ student.name }}
</li>
</ul>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script>
export default {
props: { students: { type: Array, default: () => [] } },
data() {
return {
activeName: '0'
}
},
computed: {
// 未批阅的学生
unreviewedStudents() {
return this.students.filter(item => item.status === 1)
},
// 已批阅的学生
reviewedStudents() {
return this.students.filter(item => item.status === 2)
}
}
}
</script>
<style lang="scss" scoped>
li {
max-width: 100px;
cursor: pointer;
padding: 5px;
&:hover {
color: red;
}
}
</style>
<template>
<div>
<video ref="videoPlayer" class="video-js"></video>
</div>
</template>
<script>
import videojs from 'video.js'
import 'video.js/dist/video-js.css'
export default {
name: 'VideoPlayer',
props: {
options: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
player: null
}
},
mounted() {
this.player = videojs(this.$refs.videoPlayer, this.options, function onPlayerReady() {
console.log('onPlayerReady', this)
})
},
beforeDestroy() {
if (this.player) {
this.player.dispose()
}
}
}
</script>
<template>
<div>
<div class="answer-box">
<div class="head" id="head-h">
<el-button icon="el-icon-arrow-left" circle @click="$emit('back')"></el-button>
<div class="title">{{ title }}</div>
<div class="right">
<div class="count" v-if="hasCountdown">{{ countdownText }}</div>
</div>
</div>
<div class="exam-main">
<div class="left">
<question-list
:data="currentQuestionGroup"
:page="currentGroupPage"
:index="currentQuestionIndex"
:disabled="disabled"
:hasResult="hasResult"
@change="handleChange"
>
<template #index>{{ currentGroupPage }}/{{ currentGroupCount }}</template>
<template v-slot:default="data">
<slot name="question-item" v-bind="data"></slot>
</template>
</question-list>
</div>
<div class="right">
<question-numbers
:status="status"
:page="currentGroupPage"
:data="currentQuestionGroup"
:list="numberGroups.length ? numberGroups : questionGroups"
@page-change="handlePageChange"
>
<slot name="students" v-bind="{ data: currentQuestionGroup }"></slot>
</question-numbers>
</div>
</div>
<div class="foot" id="foot-h">
<div class="exam-btn">
<div class="confirm" @click="showResult" v-if="hasShowResultBtn">确认答案</div>
<div :class="prevClass" @click="prev">上一题</div>
<div :class="nextClass" @click="next">下一题</div>
</div>
<div class="rigth-btn">
<div class="sign" v-if="hasCollect" @click="toggleCollect">
<div :class="firstQuestion.is_collection ? 'icon active' : 'icon'"></div>
<div class="txt">{{ firstQuestion.is_collection ? '已收藏' : '收藏' }}</div>
</div>
<div class="sign2" v-if="hasMark" @click="toggleMark">
<div :class="firstQuestion.sign ? 'icon active' : 'icon'"></div>
<div class="txt">{{ firstQuestion.sign ? '已标记' : '标记' }}</div>
</div>
<div class="del-btn" v-if="hasDeleteBtn" @click="$emit('delete', currentQuestionGroup)">删除</div>
<div class="end-exam-btn">
<div class="btn" v-if="hasSubmitBtn && !disabled" @click="submit">{{ submitButtonText }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as api from '@/api/exam.js'
import questionList from '@/components/exam/questionList.vue'
import questionNumbers from '@/components/exam/questionNumbers.vue'
export default {
components: { questionList, questionNumbers },
props: {
status: { type: Number, default: 1 }, // 1:答题;2:查看;3:批阅
title: { type: String },
hasMark: { type: Boolean, default: true }, // 标记
hasCollect: { type: Boolean, default: true }, // 收藏
hasSubmitBtn: { type: Boolean, default: true }, // 提交按钮
hasDeleteBtn: { type: Boolean, default: false }, // 删除按钮
hasShowResultBtn: { type: Boolean, default: false }, // 显示答案按钮
hasCountdown: { type: Boolean, default: true }, // 计时
submitButtonText: { type: String, default: '交卷' }, // 提交按钮显示的文字
data: { type: Object, default: () => {} }, // 模拟考试返回的数据,内部组装
groups: { type: Array, default: () => [] }, // 收藏、错题组装好的数据
groupPage: { type: Number, default: 1 }, // 大题当前页
groupPageSize: { type: Number, default: 0 }, // 大题一页的数量
groupPageCount: { type: Number, default: 0 }, // 大题总页数
numberGroups: { type: Array, default: () => [] } // 答题卡
},
data() {
return {
disabled: false, // 是否禁用输入框
hasResult: false, // 是否显示解析
duration: 0, // 答题所用时间
countdownTimer: null, // 倒计时计时器
countdownText: '', // 倒计时显示时间
questionGroups: this.groups, // 所有试题分组,一组一页
currentGroupPage: this.groupPage, // 大题页码
currentGroupCount: this.groupPageCount, // 大题总页数
isCountDownEnd: false
}
},
computed: {
// 当前页面试题组
currentQuestionGroup() {
return this.questionGroups[this.currentPage] || {}
},
// 当前页面的试题列表
currentQuestionList() {
return this.currentQuestionGroup.question_list || []
},
// 当前页面第一个试题
firstQuestion() {
return this.currentQuestionList[0] || {}
},
// 当前题号
currentQuestionIndex() {
return this.questionGroups.reduce((result, item, index) => {
if (index <= this.currentPage) {
result += item.question_list.length
}
return result
}, 0)
},
// 当前页码
currentPage() {
return (this.currentGroupPage - 1) % (this.groupPageSize || this.questionGroups.length)
},
// 上一题按钮的class
prevClass() {
return { active: this.currentGroupPage !== 1 }
},
// 下一题按钮的class
nextClass() {
return { active: this.currentGroupPage < this.currentGroupCount }
}
},
watch: {
data: {
immediate: true,
handler(data) {
data && this.dataInit(data)
}
},
groups: {
handler(groups) {
this.questionGroups = groups
}
},
groupPage(value) {
this.currentGroupPage = value
},
groupPageCount(value) {
this.currentGroupCount = value
},
currentPage() {
if (this.hasShowResultBtn) {
this.hasResult = this.currentQuestionGroup.hasResult
}
}
},
beforeDestroy() {
clearInterval(this.countdownTimer) // 停止倒计时
},
methods: {
// 倒计时
countDown(time) {
let sec = parseInt(time)
clearInterval(this.countdownTimer)
this.countdownTimer = setInterval(() => {
sec--
if (sec === 0) {
clearInterval(this.countdownTimer)
this.isCountDownEnd = true
this.$alert('考试时间结束,自动提交试卷', '', {
confirmButtonText: '确定',
callback: action => {
this.submit()
}
}) // 是否显示解析
return false
}
this.countdownText = this.secondToDate(sec) // 倒计时显示时间
this.duration++
this.$emit('timeupdate', this.duration, this.questionGroups)
}, 1000)
},
secondToDate(result) {
const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
const m =
Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60)
const s = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60)
if (h === 0) {
result = m + ':' + s
} else {
result = h + ':' + m + ':' + s
}
return result
},
// 显示答案
showResult() {
this.hasResult = true
this.questionGroups[this.currentPage].hasResult = true
this.$emit('primary', this.currentGroupPage, this.questionGroups)
},
// 上一大题
prev() {
if (this.currentGroupPage <= 1) return
this.currentGroupPage--
this.handlePageChange(this.currentGroupPage)
},
// 下一大题
next() {
if (this.currentGroupPage >= this.currentGroupCount) return
this.currentGroupPage++
this.handlePageChange(this.currentGroupPage)
},
// 答案改变
handleChange(data) {
if (this.numberGroups.length) {
this.updateNumberGroupsAnswer(data)
}
},
// 翻页
handlePageChange(index) {
this.currentGroupPage = index
this.$emit('page-change', this.currentGroupPage, this.currentQuestionGroup, this.questionGroups)
},
// 是否正确
updateNumberGroupsAnswer(data) {
this.numberGroups.forEach(group => {
const found = group.question_list.find(item => item.question_id === data.question_id)
if (found) {
found.answer = 3
}
})
},
// 收藏
toggleCollect() {
const ids = []
// 第一题的收藏状态
const isCollection = this.firstQuestion.is_collection
this.currentQuestionList.forEach(item => {
item.is_collection = !isCollection
ids.push(item.id || item.question_id)
})
isCollection
? api.deleteCollection({ type: 2, question_id: ids.join() })
: api.addCollection({ question_id: ids.join() })
},
// 标记
toggleMark() {
this.currentQuestionList.forEach(item => {
item.sign = !item.sign
})
},
// 提交
submit() {
this.$emit('submit', this.questionGroups)
},
// 数据初始化
dataInit(data) {
if (!data.questions) {
return
}
const isSubmited = ['1', '2'].includes(data.status)
this.disabled = isSubmited
this.hasResult = isSubmited && this.status !== 3
this.genQuestions(data)
this.currentGroupCount = this.questionGroups.length
if (this.$route.query.id) {
this.findGroupPageByQuestionId(this.$route.query.id)
}
// 答题倒计时
if (this.hasCountdown) {
this.countDown(this.data.remaining_times)
this.duration = this.data.duration || 0
}
},
// 组装试题数据
genQuestions(data) {
const { questions, answers = {}, score_items: scores = {} } = data
if (!questions) return []
this.questionGroups = questions.question_items.reduce((result, question) => {
if (question.question_list.length) {
question.question_list.forEach(list => {
list = list.map(item => {
let userAnswers = []
let sign = false
let scoreItem = {}
// 答案
if (answers) {
// 大题答案包含所有小题答案
const bigQuestionAnswer = answers[question.question_item_id]
if (bigQuestionAnswer) {
// 小题答案
const questionAnswer = bigQuestionAnswer[item.id] || {}
userAnswers = questionAnswer.answer || []
sign = questionAnswer.sign || false
}
}
// 分数与结果
if (scores) {
const bigQuestionScore = scores[question.question_item_id]
if (bigQuestionScore) {
// 小题分数
scoreItem = bigQuestionScore[item.id] || {}
scoreItem.user_score = scoreItem.score
if (userAnswers.length) {
scoreItem.answer = scoreItem.is_right ? 1 : 2
} else {
scoreItem.answer = 0
}
}
}
return {
...{ comment_visible: false, result_visible: false },
...scoreItem,
...item,
user_answer: userAnswers,
sign
}
})
result.push(Object.assign({}, question, { question_list: list }))
})
} else {
result.push(Object.assign({}, question, { question_list: [] }))
}
return result
}, [])
},
// 重置
reset() {
this.currentGroupPage = 1
},
// 通过小题ID查找大题页码
findGroupPageByQuestionId(id) {
this.questionGroups.forEach((item, index) => {
const findIndex = item.question_list.findIndex(data => data.id === id)
if (findIndex !== -1) {
this.currentGroupPage = index + 1
}
})
}
}
}
</script>
<style lang="scss" scoped>
.answer-box {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
overflow: hidden;
// background: #f9f9f9;
.head {
border-bottom: 1px solid #ccc;
height: 80px;
background: #ffffff;
display: flex;
align-items: center;
padding-left: 40px;
.title {
padding-left: 20px;
font-size: 24px;
font-weight: bold;
color: #222222;
line-height: 80px;
}
.right {
width: 260px;
margin-left: auto;
display: flex;
justify-content: space-around;
align-items: center;
.count {
font-size: 18px;
font-weight: bold;
color: #222222;
}
.time {
display: flex;
.icon {
width: 23px;
height: 23px;
// background: url(../../assets/images/tick.png);
background-size: 100% 100%;
}
.mun {
font-size: 18px;
font-weight: bold;
color: #222222;
line-height: 25px;
margin-left: 10px;
}
}
}
}
.exam-main {
flex: 1;
display: flex;
overflow: hidden;
.left {
background: #fff;
flex: 1;
padding: 10px 20px 0 53px;
overflow-y: scroll;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
.right {
border-left: 1px solid #ccc;
position: relative;
width: 220px;
background: #fff;
padding: 0 20px;
overflow-y: scroll;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
}
.foot {
border-top: 1px solid #ccc;
height: 60px;
background: #ffffff;
display: flex;
align-items: center;
.exam-btn {
display: flex;
padding-left: 40px;
cursor: pointer;
div {
width: 100px;
height: 40px;
border-radius: 4px;
border: 1px solid #cccccc;
font-size: 14px;
font-weight: bold;
color: #999999;
line-height: 40px;
text-align: center;
margin-right: 20px;
&.active {
background: #c01540;
border-radius: 4px;
color: #fff;
}
}
}
.rigth-btn {
display: flex;
margin-left: auto;
.del-btn {
margin-top: 10px;
width: 100px;
height: 40px;
border-radius: 4px;
border: 1px solid #cccccc;
line-height: 40px;
font-size: 14px;
font-weight: bold;
color: #999999;
text-align: center;
margin-right: 30px;
}
.end-exam-btn {
background: #fff;
height: 62px;
margin-top: -2px;
border-left: 1px solid #ccc;
width: 260px;
display: flex;
justify-content: center;
align-items: center;
.btn {
cursor: pointer;
width: 200px;
height: 40px;
background: #c01540;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
color: #fff;
line-height: 40px;
text-align: center;
}
}
.sign {
margin-right: 20px;
margin-top: 8px;
.icon {
margin: 0 auto;
width: 24px;
height: 24px;
background: url(@/assets/images/collection.png);
background-size: 100% 100%;
&.active {
background: url(@/assets/images/collection2.png);
background-size: 100% 100%;
}
}
.txt {
font-size: 14px;
color: #cccccc;
line-height: 20px;
margin-top: 2px;
}
}
.sign2 {
margin-right: 20px;
margin-top: 8px;
.icon {
margin: 0 auto;
width: 24px;
height: 24px;
background: url(@/assets/images/sign.png);
background-size: 100% 100%;
&.active {
background: url(@/assets/images/sign2.png);
background-size: 100% 100%;
}
}
.txt {
font-size: 14px;
color: #cccccc;
line-height: 20px;
margin-top: 2px;
}
}
}
}
}
</style>
<template>
<div class="question-list">
<div class="question-list-hd">
<h4 class="question-list-hd__title">{{ questionTypeText }}</h4>
<aside class="question-list-hd__aside"><slot name="index"></slot></aside>
</div>
<div class="question-list-bd">
<h2 class="question-list-title" v-if="conmonTitle" v-html="conmonTitle">
<!-- <span class="num">{{ page }}.</span> -->
<!-- {{ conmonTitle }} -->
</h2>
<question-list-item
v-for="(item, i) in data.question_list"
:data="item"
:question="data"
:page="data.question_list.length > 1 ? i + 1 : page"
:key="item.id"
v-bind="$attrs"
v-on="$listeners"
>
<slot v-bind="{ item, data }"></slot>
</question-list-item>
</div>
</div>
</template>
<script>
import QuestionListItem from './questionListItem.vue'
export default {
props: {
data: { type: Object, default: () => ({}) },
page: { type: Number, default: 0 } // 页码
},
components: { QuestionListItem },
computed: {
// 试题类型
questionTypeText() {
const map = { 1: '单选题', 2: '多选题', 3: '问答题', 5: '案例题', 6: '判断题', 7: '实操题', 8: '情景题' }
return map[this.data.question_type] || this.data.question_type
},
// 公共题干
conmonTitle() {
const [first = {}] = this.data.question_list || []
return first.common_content
}
}
}
</script>
<style lang="scss" scoped>
.question-list {
position: relative;
}
.question-list-hd {
// position: sticky;
// top: 0;
display: flex;
align-items: center;
height: 45px;
background-color: #fff;
}
.question-list-hd__title {
flex: 1;
font-size: 18px;
color: #222;
}
.question-list-hd__aside {
font-size: 18px;
color: #222;
}
.question-list-title {
margin: 20px 0 30px;
font-size: 18px;
color: #222;
.num {
font-size: 32px;
font-weight: bold;
color: #222;
line-height: 45px;
margin-top: 5px;
}
}
</style>
<template>
<div class="question-list-item">
<div class="question-list-item-hd">
<div class="question-list-item-hd__num">{{ page }}.</div>
<div class="question-list-item-hd__title" v-html="data.question_content"></div>
</div>
<div class="question-list-item-bd">
<!-- 单选 -->
<template v-if="[1, 6].includes(questionType)">
<el-radio-group v-model="data.user_answer[0]" :disabled="disabled" @change="handleChange">
<div class="question-option-item" v-for="item in currentOptions" :key="item.id">
<el-radio :label="item.id">
<div class="question-option-item__text" v-html="item.abc_option"></div>
</el-radio>
</div>
</el-radio-group>
</template>
<!-- 多选 -->
<template v-if="questionType === 2">
<el-checkbox-group v-model="data.user_answer" :disabled="disabled" @change="handleChange">
<div class="question-option-item" v-for="item in currentOptions" :key="item.id">
<el-checkbox :label="item.id">
<div class="question-option-item__text" v-html="item.abc_option"></div>
</el-checkbox>
</div>
</el-checkbox-group>
</template>
<!-- 简答题 -->
<template v-if="questionType === 3">
<el-input
type="textarea"
v-model="data.user_answer[0]"
placeholder="请输入答案内容"
:autosize="{ minRows: 4, maxRows: 6 }"
:disabled="disabled"
@blur="handleChange"
:maxlength="100"
:show-word-limit="true"
></el-input>
</template>
<template v-if="questionType === 3">
<slot></slot>
</template>
</div>
<div class="question-list-item-ft" v-if="hasResult">
<h3 class="question-list-item-ft__title">答案解析</h3>
<template v-if="questionType !== 3">
<div class="answer-item">
<div class="answer-item-label">正确答案:</div>
<div class="answer-item-content">{{ correctAnswerText }}</div>
</div>
<div class="answer-item">
<div class="answer-item-label">您的答案:</div>
<div class="answer-item-content">{{ submitAnswerText }}</div>
</div>
</template>
<template v-else>
<div class="answer-item" v-if="data.comment">
<div class="answer-item-label">老师点评:</div>
<div class="answer-item-content">{{ data.comment }}</div>
</div>
</template>
<div class="answer-item" v-if="data.question_analysis">
<div class="answer-item-label">解析:</div>
<div class="answer-item-content" v-html="data.question_analysis"></div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
page: { type: Number, default: 0 }, // 题号
data: { type: Object, default: () => ({}) }, // 小题
question: { type: Object, default: () => ({}) }, // 大题
disabled: { type: Boolean, default: false },
hasResult: { type: Boolean, default: false }
},
data() {
return {}
},
computed: {
questionType() {
// (1:单选题,2:多选题,3:问答题,5:案例题,6:判断题,7:实操题,8:情景题)
const questionType = parseInt(this.question.question_type)
const { answer_count: answerCount = 0 } = this.data
if ([5, 7, 8].includes(questionType)) {
if (answerCount >= 2) {
return 2
}
return answerCount || 3
} else {
return questionType
}
},
// 26个英文字母
A_Z() {
const result = []
for (let i = 0; i < 26; i++) {
result.push(String.fromCharCode(65 + i))
}
return result
},
// 处理后的options数据
currentOptions() {
if (!this.data.question_options) {
return []
}
return this.data.question_options.map((item, index) => {
// 英文字母 + 名称
item.abc = this.A_Z[index]
item.abc_option = `${this.A_Z[index]}. ${item.option}`
// 提交时的选中状态
item.checked = this.data.user_answer.includes(item.id)
// 处理正确的选中状态
const hasChecked = Object.prototype.hasOwnProperty.call(item, 'isRight')
const rightAnswer = this.data.question_answer || []
if (!hasChecked && rightAnswer) {
item.isRight = Array.isArray(rightAnswer) ? rightAnswer.includes(item.id) : rightAnswer === item.id
}
return item
})
},
// 正确答案显示的英文字母
correctAnswerText() {
const result = this.currentOptions.reduce((result, item) => {
item.isRight && result.push(item.abc)
return result
}, [])
return result.join('、')
},
// // 提交答案显示的英文字母
submitAnswerText() {
const result = this.currentOptions.reduce((result, item) => {
item.checked && result.push(item.abc)
return result
}, [])
return result.join('、')
}
},
methods: {
handleChange() {
this.$emit('change', this.data)
}
}
}
</script>
<style lang="scss" scoped>
.question-list-item {
margin-bottom: 40px;
}
.question-list-item-hd {
display: flex;
}
.question-list-item-hd__num {
font-size: 32px;
font-weight: bold;
color: #222;
line-height: 45px;
margin-top: 5px;
}
.question-list-item-hd__title {
margin-left: 5px;
padding-top: 18px;
font-size: 18px;
font-weight: bold;
color: #222;
line-height: 25px;
}
.question-option-item {
margin-top: 20px;
::v-deep .el-radio,
::v-deep .el-checkbox {
display: flex;
align-items: center;
}
}
.question-option-item__text {
display: inline-block;
font-size: 18px;
color: #222;
}
::v-deep .el-radio__inner,
::v-deep .el-checkbox__inner {
width: 18px;
height: 18px;
}
::v-deep .el-checkbox__inner::after {
width: 4px;
height: 9px;
left: 6px;
}
.question-list-item-ft {
margin-top: 20px;
}
.question-list-item-ft__title {
font-size: 18px;
font-weight: bold;
color: #222;
line-height: 25px;
}
.answer-item {
margin-top: 10px;
margin-left: 28px;
display: flex;
font-size: 18px;
color: #222;
line-height: 25px;
}
.answer-item-label {
white-space: nowrap;
}
.answer-item-content {
flex: 1;
overflow: hidden;
}
</style>
<template>
<div class="question-numbers">
<div class="question-num">
<div v-for="item in dataList" :key="item.question_item_id">
<div class="tit">{{ item.title }}</div>
<ul>
<li
v-for="(item, index) in item.question_list"
class="question-num-item"
:class="genClass(item)"
:key="index"
@click="handleClick(item)"
>
{{ index + 1 }}
</li>
</ul>
</div>
</div>
<slot></slot>
<ul class="question-num-tips">
<li v-for="(item, index) in questionNum" :key="index">
<div class="question-num-tips-item" :class="item.class"></div>
<div class="txt">{{ item.name }}</div>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
status: { type: Number, default: 1 }, // 1:答题;2:查看;3:批阅
page: { type: Number, default: 0 }, // 当前大题的页码
data: { type: Object, default: () => ({}) }, // 当前大题
list: { type: Array, default: () => [] } // 所有大题
},
data() {
return {
questionNumTips: {
1: [
{ class: 'is-info', name: '已答' },
{ class: 'is-default', name: '未答' },
{ class: 'is-success', name: '当前' },
{ class: 'is-mark', name: '标记' }
],
2: [
{ class: 'is-success', name: '答对' },
{ class: 'is-error', name: '答错' },
{ class: 'is-info', name: '未答' }
],
3: [
{ class: 'is-success', name: '已批阅' },
{ class: 'is-error', name: '未批阅' },
{ class: 'is-info', name: '未答' }
]
}
}
},
computed: {
dataList() {
const results = []
this.list.forEach((item, index) => {
const findIndex = results.findIndex(data => data.question_item_id === item.question_item_id)
const quesitonlist = item.question_list.map(item => {
return { ...item, big_num: index + 1 }
})
if (findIndex === -1) {
results.push({
title: item.title,
question_type: item.question_type,
question_item_id: item.question_item_id,
question_list: quesitonlist
})
} else {
results[findIndex].question_list = results[findIndex].question_list.concat(quesitonlist)
}
})
return results
},
questionNum() {
return this.questionNumTips[this.status]
}
},
methods: {
genClass(data) {
// answer(0:未做,1:正确,2:错误)
if (this.status === 1) {
return {
'is-info': data.user_answer ? data.user_answer.length : false, // 已做
'is-success': data.big_num === this.page, // 当前
'is-mark': data.sign // 标记
}
}
if (this.status === 2) {
return {
'is-success': data.answer === 1, // 答对
'is-error': data.answer === 2, // 答错
'is-info': data.answer === 0 // 未答
}
}
if (this.status === 3) {
return {
'is-success': data.checked_flag, // 已批阅
'is-error': !data.checked_flag, // 未批阅
'is-info': data.answer === 0 // 未做
}
}
},
handleClick(data) {
this.$emit('page-change', data.big_num, data)
}
}
}
</script>
<style lang="scss" scoped>
.question-numbers {
height: 100%;
display: flex;
flex-direction: column;
}
.question-num {
flex: 1;
padding-top: 20px;
.tit {
font-size: 12px;
color: #999999;
line-height: 17px;
margin-bottom: 10px;
}
ul {
display: flex;
list-style: none;
padding: 0;
margin: 0;
flex-wrap: wrap;
}
}
.question-num-item {
cursor: pointer;
position: relative;
border-radius: 50px;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 24px;
margin-right: 20px;
margin-bottom: 10px;
text-align: center;
border: 2px solid #ccc;
color: #666;
&:nth-child(5n) {
margin-right: 0;
}
}
.question-num-tips {
padding-bottom: 20px;
display: flex;
align-items: center;
justify-content: space-between;
.txt {
margin-top: 5px;
font-size: 12px;
color: #ccc;
line-height: 17px;
text-align: center;
}
}
.question-num-tips-item {
cursor: pointer;
position: relative;
border-radius: 50px;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 24px;
text-align: center;
border: 2px solid #ccc;
color: #666;
}
.is-default {
color: #666;
border: 2px solid #ccc;
}
.is-info {
color: #fff;
background-color: #999;
border: 2px solid #999;
}
.is-success {
color: #666;
border: 2px solid #0fc118;
}
.is-info.is-success {
color: #fff;
}
.is-error {
color: #666;
border: 2px solid #c01540;
}
.is-mark::after {
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #c01540;
border-radius: 50%;
}
</style>
<template>
<div>
<!-- stu1已答 stu2当前 stu3标记 -->
<div class="order-num" v-if="questionParams.card">
<template v-for="(item, index) in questionParams.card">
<div :key="index" v-if="item">
<div class="tit">{{ item.find(tit => { return tit.question_item_title }).question_item_title }}</div>
<ul>
<template v-for="(cItem, cIndex) in item">
<li
:key="cItem.q_order + '-' + cIndex"
@click="goQuestion(cItem.q_order)"
:class="$route.query.id ? isAnalysisClass(cItem) + ' analy' : isClass(cItem)"
>{{ cItem.q_order }}</li>
</template>
</ul>
</div>
</template>
</div>
<ul class="flag-tips" v-if="!this.$route.query.id">
<li>
<div class="circle1"></div>
<div class="txt">已答</div>
</li>
<li>
<div class="circle2"></div>
<div class="txt">未答</div>
</li>
<li>
<div class="circle3"></div>
<div class="txt">当前</div>
</li>
<li>
<div class="circle4"></div>
<div class="txt">标记</div>
</li>
</ul>
<ul class="tips-box" v-else>
<li>
<div class="circle1"></div>
<div class="txt">答对</div>
</li>
<li>
<div class="circle2"></div>
<div class="txt">答错</div>
</li>
<li>
<div class="circle3"></div>
<div class="txt">未答</div>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
questionParams: { type: Object, default: () => {} },
info: { type: Object, default: () => {} }
},
mounted() {
this.msgCenter.$on('monitoringChanges', this.monitoringChanges)
},
computed: {
changeQuestionIndex() {
return this.questionParams.answerRecord
},
isClass() {
return (cItem) => {
const currentAnswer = this.questionParams.answerRecord[cItem.question_item_id]
return this.questionParams.questionIndex + 1 === cItem.q_order
? currentAnswer
? currentAnswer[cItem.id]
? currentAnswer[cItem.id].answer
? currentAnswer[cItem.id].answer.length !== 0
? currentAnswer[cItem.id].sign
? 'stu1 stu2 stu3'
: 'stu1 stu2'
: currentAnswer[cItem.id].sign
? 'stu2 stu3'
: 'stu2'
: currentAnswer[cItem.id].sign
? 'stu2 stu3'
: 'stu2'
: 'stu2'
: 'stu2'
: currentAnswer
? currentAnswer[cItem.id]
? currentAnswer[cItem.id].answer
? currentAnswer[cItem.id].answer.length !== 0
? currentAnswer[cItem.id].sign
? 'stu1 stu3'
: 'stu1'
: currentAnswer[cItem.id].sign
? 'stu3'
: ''
: currentAnswer[cItem.id].sign
? 'stu3'
: ''
: ''
: ''
}
},
isAnalysisClass() {
return (cItem) => {
const findItems = this.questionParams.beforeData.answers[cItem.question_item_id]
const scoreItems = this.questionParams.beforeData.score_items[cItem.question_item_id][cItem.id]
return findItems
? findItems[cItem.id]
? findItems[cItem.id].answer
? findItems[cItem.id].answer.length
? scoreItems.is_right
? 'stu1'
: 'stu2'
: 'stu3'
: 'stu3'
: 'stu3'
: 'stu3'
}
}
},
methods: {
onSignHandle(stu) {
const id = this.questionParams.question
this.questionParams.answerRecord[id.question_item_id]
? this.questionParams.answerRecord[id.question_item_id][id.id]
? this.questionParams.answerRecord[id.question_item_id][id.id].sign = stu
: this.questionParams.answerRecord[id.question_item_id][id.id] = {
sign: stu
}
: this.questionParams.answerRecord[id.question_item_id] = {
[id.id]: { sign: stu }
}
this.$forceUpdate()
},
monitoringChanges() {
this.$forceUpdate()
},
goQuestion(n) {
this.questionParams.questionIndex = n - 1
}
},
watch: {
changeQuestionIndex(newV, oldV) {
this.$forceUpdate()
}
}
}
</script>
<style lang="scss" scoped>
.info{
display: flex;
align-items: center;
height: 100px;
.shape{
width: 60px;
height: 60px;
border-radius: 50%;
overflow: hidden;
}
img{
width: 75px;
// transform: scale(1);
display: block;
}
.right{
margin-left: 22px;
.name{
font-size: 18px;
color: #222222;
line-height: 25px;
}
.code{
font-size: 14px;
color: #222222;
line-height: 20px;
margin-top: 5px;
}
}
}
.order-num{
padding-top: 20px;
padding-bottom: 90px;
.tit{
font-size: 12px;
color: #999999;
line-height: 17px;
margin-bottom: 10px;
}
ul{
display: flex;
list-style: none;
padding: 0;
margin: 0;
flex-wrap: wrap;
li{
cursor: pointer;
position: relative;
border-radius: 50px;
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
font-size: 14px;
color: #666666;
line-height: 24px;
margin-right: 20px;
margin-bottom: 10px;
text-align: center;
&:nth-child(5n+5){
margin-right: 0;
}
&.analy{
&.stu1{
border: 2px solid #0FC118;
line-height: 22px;
background: #fff;
color: #999;
}
&.stu2{
border: 2px solid #C01540;
line-height: 22px;
background: #fff;
color: #999;
}
&.stu3{
color: #fff;
background: #999999;
&::after{
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: none;
border-radius: 50%;
}
}
}
&.stu1{
background: #999;
border: 1px solid #999;
color: #fff;
}
&.stu2{
width: 22px;
height: 22px;
line-height: 22px;
border: 2px solid #0FC118;
}
&.stu3{
&::after{
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #C01540;
border-radius: 50%;
}
}
}
}
}
.flag-tips{
width: 260px;
position: fixed;
bottom: 60px;
right:0;
display: flex;
justify-content: space-around;
padding: 15px 0 10px;
background: #fff;
margin: 0;
list-style: none;
li{
.circle1{
width: 24px;
height: 24px;
background: #EEEEEE;
border: 1px solid #CCCCCC;
border-radius: 50%;
}
.circle1{
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
border-radius: 50%;
}
.circle2{
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
border-radius: 50%;
}
.circle3{
width: 24px;
height: 24px;
border: 2px solid #0FC118;
border-radius: 50%;
}
.circle4{
position: relative;
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
border-radius: 50%;
&::after{
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #C01540;
border-radius: 50%;
}
}
.txt{
margin-top: 5px;
font-size: 12px;
color: #CCCCCC;
line-height: 17px;
}
}
}
.flag-tips{
width: 260px;
position: fixed;
bottom: 60px;
right:0;
display: flex;
justify-content: space-around;
padding: 15px 0 10px;
background: #fff;
margin: 0;
list-style: none;
li{
.circle1{
width: 24px;
height: 24px;
background: #999;
border: 1px solid #999;
border-radius: 50%;
}
.circle2{
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
border-radius: 50%;
}
.circle3{
width: 24px;
height: 24px;
border: 2px solid #0FC118;
background: rgba(15, 193, 24, 0.1);
border-radius: 50%;
}
.circle4{
position: relative;
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
border-radius: 50%;
&::after{
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #C01540;
border-radius: 50%;
}
}
.txt{
margin-top: 5px;
font-size: 12px;
color: #CCCCCC;
line-height: 17px;
}
}
}
.tips-box{
width: 260px;
position: fixed;
bottom: 60px;
right:0;
display: flex;
justify-content: space-around;
padding: 15px 0 10px;
background: #fff;
margin: 0;
list-style: none;
li{
&:nth-child(2){
// margin: 0 50px;
}
.circle1{
width: 24px;
height: 24px;
background: #fff;
border: 2px solid #0FC118;
border-radius: 50%;
box-sizing: border-box;
}
.circle2{
width: 24px;
height: 24px;
border: 2px solid #C01540;
border-radius: 50%;
box-sizing: border-box;
}
.circle3{
width: 24px;
height: 24px;
background: #999999;
border-radius: 50%;
}
.circle4{
position: relative;
width: 24px;
height: 24px;
border: 1px solid #CCCCCC;
border-radius: 50%;
&::after{
content: '';
position: absolute;
top: -1px;
right: -1px;
width: 4px;
height: 4px;
background: #C01540;
border-radius: 50%;
}
}
.txt{
margin-top: 5px;
font-size: 12px;
color: #CCCCCC;
line-height: 17px;
}
}
}
</style>
<template>
<div class="chart">
<svg width="148" height="148" viewbox="0 0 148 148" class="svg-rotate">
<circle cx="74" cy="74" r="70" stroke-width="7" stroke="#efefef" fill="none"></circle>
<circle cx="74" v-if="this.accuracy" cy="74" r="70" stroke-width="7" stroke="#4cce8c" fill="none" :stroke-dasharray="data" stroke-linecap="round"></circle>
</svg>
<div class="chart-txt">
<slot name="tips"></slot>
</div>
</div>
</template>
<script>
export default {
props: {
accuracy: { type: Number },
accuracScore: { type: Number }
},
data() {
return {
data: ''
}
},
mounted() {
const percent = this.accuracy / this.accuracScore
const perimeter = Math.PI * 2 * 70
this.data = perimeter * percent + ' ' + perimeter * (1 - percent)
}
}
</script>
<style lang="scss" scoped>
.chart{
position: relative;
width: auto;
.chart-txt{
position: absolute;
top: 50%;
left: 0;
width: 100%;
text-align: center;
transform:translateY(-50%);
.num{
color: #333;
font-size: 38px;
font-weight: bold;
}
.t{
color: #999;
font-size: 18px;
}
}
}
.svg-rotate{
transform:rotate(-90deg);
}
</style>
<template>
<div class="card-box">
<ul class="tips-box">
<li>
<div class="circle1"></div>
<div class="txt">答对</div>
</li>
<li>
<div class="circle2"></div>
<div class="txt">答错</div>
</li>
<li>
<div class="circle3"></div>
<div class="txt">未答</div>
</li>
<li>
<div class="circle4"></div>
<div class="txt">已评价</div>
</li>
<li>
<div class="circle5"></div>
<div class="txt">未评价</div>
</li>
</ul>
<div class="order-num">
<template v-for="item in order">
<div :key="item.id">
<div class="tit">{{ item.title }}</div>
<ul>
<template v-for="(cItem, index) in item.question_list">
<template v-if="cItem.question_options">
<li @click="goQuestion(cItem.id)" :class="`stu${cItem.cardStust}`" :key="cItem.id">{{ index + 1 }}</li>
</template>
<template v-else>
<li @click="goQuestion(cItem.id)" :class="`stu${cItem.cardStust}`" :key="cItem.id">{{ index + 1 }}</li>
</template>
</template>
</ul>
</div>
</template>
</div>
<slot name="btnBox"></slot>
</div>
</template>
<script>
export default {
props: {
data: { type: Object }
},
data() {
return {
changeQuestion: [],
questionList: [],
order: []
}
},
computed: {},
mounted() {
this.changeQuestion = this.setData()
},
methods: {
setData() {
const data = []
this.data.questions.question_items.forEach(list => {
list.question_list = list.question_list.reduce((a, b) => {
return a.concat(b)
}, [])
list.question_list.map(item => {
const isOptions = Array.isArray(item.question_options) ? item.question_options[0] : item.question_options
if (!isOptions) {
this.data.score_items[list.question_item_id][item.id].checked_flag
? (item.cardStust = 4)
: (item.cardStust = 5)
return item
} else {
const ans =
this.data.answers[list.question_item_id][item.id].answer ||
this.data.answers[list.question_item_id][item.id].answers
if (!ans.length) {
item.cardStust = 3
return item
} else {
this.data.score_items[list.question_item_id][item.id].is_right
? (item.cardStust = 1)
: (item.cardStust = 2)
return item
}
}
})
data.push(list)
})
this.order = data
},
goQuestion(id) {
this.$emit('goQuestion', id)
}
}
}
</script>
<style lang="scss" scoped>
.card-box {
position: relative;
height: 100%;
.tips-box {
display: flex;
justify-content: space-around;
padding: 15px 0 10px;
background: #fff;
margin: 0;
list-style: none;
border-bottom: 1px solid #ccc;
li {
width: 36px;
&:nth-child(2) {
// margin: 0 50px;
}
.circle1 {
width: 24px;
height: 24px;
background: #fff;
border: 2px solid #0fc118;
border-radius: 50%;
box-sizing: border-box;
}
.circle2 {
width: 24px;
height: 24px;
border: 2px solid #c01540;
border-radius: 50%;
box-sizing: border-box;
}
.circle3 {
width: 24px;
height: 24px;
background: #999999;
border-radius: 50%;
}
.circle4 {
width: 24px;
height: 24px;
background: blue;
border-radius: 50%;
margin: 0 auto;
}
.circle5 {
width: 24px;
height: 24px;
background: pink;
border-radius: 50%;
margin: 0 auto;
}
.txt {
margin-top: 5px;
font-size: 12px;
color: #cccccc;
line-height: 17px;
}
}
}
.order-num {
// height: 420px;
// overflow-y: scroll;
padding-left: 30px;
// scrollbar-width: none;
padding-bottom: 80px;
&::-webkit-scrollbar {
display: none;
}
// padding-bottom: 90px;
.tit {
font-size: 12px;
color: #999999;
line-height: 17px;
margin-bottom: 12px;
margin-top: 30px;
}
ul {
display: flex;
list-style: none;
padding: 0;
margin: 0;
flex-wrap: wrap;
li {
box-sizing: border-box;
cursor: pointer;
position: relative;
border-radius: 50px;
width: 24px;
height: 24px;
border: 1px solid #cccccc;
font-size: 12px;
color: #666666;
line-height: 24px;
margin-right: 20px;
margin-bottom: 10px;
text-align: center;
// &:nth-child(5n+5){
// margin-right: 0;
// }
&.stu1 {
border: 2px solid #0fc118;
line-height: 22px;
}
&.stu2 {
border: 2px solid #c01540;
line-height: 22px;
}
&.stu3 {
color: #fff;
background: #999999;
}
&.stu4 {
border: 2px solid blue;
line-height: 22px;
}
&.stu5 {
border: 2px solid pink;
line-height: 22px;
}
}
}
}
.btn-box {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
height: 60px;
background: #fff;
.btn {
width: 116px;
height: 40px;
text-align: center;
line-height: 40px;
border-radius: 4px;
cursor: pointer;
&:nth-child(1) {
border: 1px solid #cccccc;
font-size: 14px;
font-weight: bold;
color: #999999;
box-sizing: border-box;
}
&:nth-child(2) {
background: #c01540;
border-radius: 4px;
font-size: 14px;
font-weight: bold;
color: #ffffff;
margin-left: 30px;
}
}
}
}
</style>
...@@ -3,18 +3,18 @@ ...@@ -3,18 +3,18 @@
<nav class="nav"> <nav class="nav">
<el-menu :default-active="defaultActive" :router="true"> <el-menu :default-active="defaultActive" :router="true">
<template v-for="item in menuList"> <template v-for="item in menuList">
<el-submenu :index="item.path" :key="item.path" v-if="item.children"> <el-submenu :index="item.path" :key="item.path" v-if="item.children" v-has="item.tag">
<template #title><i :class="item.icon"></i>{{ item.name }}</template> <template #title><i :class="item.icon"></i>{{ item.name }}</template>
<el-menu-item <el-menu-item
:index="subitem.path" :index="subitem.path"
v-for="subitem in item.children" v-for="subitem in item.children"
:key="subitem.path" :key="subitem.path"
v-show="menuVisible(subitem.tag)" v-has="subitem.tag"
> >
{{ subitem.name }} {{ subitem.name }}
</el-menu-item> </el-menu-item>
</el-submenu> </el-submenu>
<el-menu-item :index="item.path" :key="item.path" v-else v-show="menuVisible(item.tag)"> <el-menu-item :index="item.path" :key="item.path" v-has="item.tag" v-else>
<i :class="item.icon"></i>{{ item.name }} <i :class="item.icon"></i>{{ item.name }}
</el-menu-item> </el-menu-item>
</template> </template>
...@@ -33,46 +33,48 @@ export default { ...@@ -33,46 +33,48 @@ export default {
name: '仪表台', name: '仪表台',
path: '/dashboard', path: '/dashboard',
icon: 'el-icon-data-board', icon: 'el-icon-data-board',
children: [ tag: 'menu_console',
{ name: '数据总览', path: '/dashboard', tag: 'console-index' } children: [{ name: '数据总览', path: '/dashboard', tag: 'menu_console_index' }]
]
}, },
{ {
tag: '',
name: '教务管理', name: '教务管理',
path: '/school/class', path: '/school/class',
icon: 'el-icon-user', icon: 'el-icon-help',
children: [ children: [
{ name: '班级管理', path: '/school/class', tag: 'class-list' }, { name: '班级管理', path: '/school/class', tag: 'menu_class' },
{ name: '课程管理', path: '/school/course', tag: 'course-list' }, { name: '课程管理', path: '/school/course', tag: 'menu_course' },
{ name: '考试管理', path: '/school/exam', tag: 'examination-list' }, { name: '考试管理', path: '/school/exam', tag: 'menu_examination' },
{ name: '证书管理', path: '/school/cert', tag: 'certificate-list' } { name: '考卷批阅', path: '/school/review/exam', tag: 'menu_examination_paper_review' },
{ name: '习题批阅', path: '/school/review/test', tag: 'menu_examination_exercise_review' },
{ name: '证书管理', path: '/school/cert', tag: 'menu_certificate' }
] ]
}, },
{ {
name: '人员管理', name: '人员管理',
path: '/personnel/teacher', path: '/personnel/teacher',
icon: 'el-icon-s-custom', icon: 'el-icon-user',
tag: 'menu_school',
children: [ children: [
{ name: '教工管理', path: '/personnel/teacher', tag: 'teacher-list' }, { name: '教工管理', path: '/personnel/teacher', tag: 'menu_school_teacher' },
{ name: '人员管理', path: '/personnel/student', tag: 'student-list' } { name: '学员管理', path: '/personnel/student', tag: 'menu_school_students' }
] ]
}, },
// {
// name: '系统管理',
// path: '/system/safe',
// icon: 'el-icon-setting',
// tag: 'menu_system',
// children: [{ name: '安全设置', path: '/system/safe', tag: '' }]
// },
{ {
name: '审核管理', name: '审核管理',
path: '/audit/my', path: '/audit/my',
icon: 'el-icon-s-check', icon: 'el-icon-coordinate',
tag: 'menu_lobby',
children: [ children: [
// { name: '事务类型', path: '/audit/type', tag: '' }, // { name: '事务类型', path: '/audit/type', tag: 'menu_' },
{ name: '我的审核', path: '/audit/my', tag: 'lobby-list' } { name: '我的审核', path: '/audit/my', tag: 'menu_lobby' }
] ]
},
{
name: '系统管理',
path: '/system/safe',
icon: 'el-icon-setting',
tag: 'menu_system',
children: [{ name: '安全设置', path: '/system/safe', tag: 'menu_system_safe' }]
} }
] ]
} }
...@@ -91,18 +93,6 @@ export default { ...@@ -91,18 +93,6 @@ export default {
return this.$route.path.includes(item.path) return this.$route.path.includes(item.path)
}) })
return found ? found.path : '' return found ? found.path : ''
},
// 菜单权限
menuPermissions() {
return this.$store.state.permissions
}
},
methods: {
menuVisible(tag) {
if (!tag) {
return true
}
return !!this.menuPermissions.find(item => item.tag === tag)
} }
} }
} }
......
<template> <template>
<header class="app-header"> <header class="app-header">
<div class="logo"> <div class="logo">
<router-link to="/"><img width="110px" src="https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo-white.svg" /></router-link> <router-link to="/">
<img src="https://webapp-pub.ezijing.com/x-training-new/fd-logo2.png" class="logos"> <img width="110px" src="https://zws-imgs-pub.ezijing.com/pc/base/ezijing-logo-white.svg" />
</router-link>
<template v-if="logoUrl">
<img :src="logoUrl" class="sub-logo" />
</template>
</div> </div>
<div class="app-header-right"> <div class="app-header-right">
<el-dropdown> <el-dropdown>
<div class="avatar"> <div class="avatar">
<img :src="user.avatar || 'https://zws-imgs-pub.ezijing.com/pc/base/logo.png'" /> <img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
</div> </div>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown" style="width: 280px">
<div class="user"> <div class="app-header-user">
<div class="user-name">{{ user.realname || user.nickname }}</div> <div class="app-header-user-avatar">
<el-button round size="medium" class="btn-logout" @click="logout">退出登录</el-button> <img :src="user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/avatar.svg'" />
</div>
<div class="app-header-user-main">
<h3>{{ user.realname || user.nickname }}</h3>
<p>{{ user.email || user.mobile }}</p>
</div>
<div class="app-header-user-buttons">
<el-button size="medium" round @click="logout">退出登录</el-button>
</div>
</div> </div>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
...@@ -26,6 +38,9 @@ export default { ...@@ -26,6 +38,9 @@ export default {
computed: { computed: {
user() { user() {
return this.$store.state.user return this.$store.state.user
},
logoUrl() {
return this.$store.state.appConfig?.logo
} }
}, },
methods: { methods: {
...@@ -49,24 +64,25 @@ export default { ...@@ -49,24 +64,25 @@ export default {
color: #fff; color: #fff;
.logo { .logo {
width: 120px;
height: 100%; height: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
.logos{ }
height: 60%; .sub-logo {
margin-left: 20px; height: 60%;
} margin-left: 20px;
} }
} }
.app-header-right { .app-header-right {
display: flex; display: flex;
align-items: center;
.avatar { .avatar {
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
margin-left: 20px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -74,15 +90,50 @@ export default { ...@@ -74,15 +90,50 @@ export default {
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
} }
&:hover {
background-color: rgba(60, 64, 67, 0.08);
}
} }
} }
.user { .app-header-user {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 16px; padding: 16px;
} }
.user-name { .app-header-user-avatar {
margin-bottom: 20px; margin-bottom: 6px;
width: 80px;
height: 80px;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.app-header-user-main {
h3 {
color: #202124;
font: 500 16px/22px Helvetica, Arial, sans-serif;
letter-spacing: 0.29px;
margin: 0;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
p {
color: #5f6368;
font: 400 14px/19px Helvetica, Arial, sans-serif;
letter-spacing: normal;
text-align: center;
text-overflow: ellipsis;
overflow: hidden;
}
} }
.btn-logout { .app-header-user-buttons {
width: 200px; padding-top: 16px;
} }
</style> </style>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="app-layout"> <div class="app-layout">
<app-header></app-header> <app-header></app-header>
<div class="app-layout-container"> <div class="app-layout-container">
<app-aside></app-aside> <app-aside v-if="sidebar"></app-aside>
<app-main></app-main> <app-main></app-main>
</div> </div>
</div> </div>
...@@ -15,6 +15,7 @@ import AppMain from './Main.vue' ...@@ -15,6 +15,7 @@ import AppMain from './Main.vue'
export default { export default {
name: 'AppLayout', name: 'AppLayout',
props: { sidebar: { type: Boolean, default: true } },
components: { AppHeader, AppAside, AppMain } components: { AppHeader, AppAside, AppMain }
} }
</script> </script>
......
...@@ -39,8 +39,8 @@ export default { ...@@ -39,8 +39,8 @@ export default {
this.dispatch('ElFormItem', 'el.form.blur', editor.getContent()) this.dispatch('ElFormItem', 'el.form.blur', editor.getContent())
}, },
dispatch(componentName, eventName, params) { dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root let parent = this.$parent || this.$root
var name = parent.$options.componentName let name = parent.$options.componentName
while (parent && (!name || name !== componentName)) { while (parent && (!name || name !== componentName)) {
parent = parent.$parent parent = parent.$parent
......
...@@ -144,8 +144,8 @@ export default { ...@@ -144,8 +144,8 @@ export default {
this.$emit('input', this.fileList) this.$emit('input', this.fileList)
}, },
dispatch(componentName, eventName, params) { dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root let parent = this.$parent || this.$root
var name = parent.$options.componentName let name = parent.$options.componentName
while (parent && (!name || name !== componentName)) { while (parent && (!name || name !== componentName)) {
parent = parent.$parent parent = parent.$parent
......
...@@ -3,7 +3,8 @@ import App from './App.vue' ...@@ -3,7 +3,8 @@ import App from './App.vue'
import router from './router' import router from './router'
import store from './store' import store from './store'
import modules from './modules' import modules from './modules'
import directives from '@/utils/directives'
import VueMeta from 'vue-meta'
// 公共css // 公共css
import './assets/css/base.css' import './assets/css/base.css'
// Element-UI // Element-UI
...@@ -13,8 +14,6 @@ import './assets/theme/style.scss' ...@@ -13,8 +14,6 @@ import './assets/theme/style.scss'
import AppCard from './components/base/AppCard.vue' import AppCard from './components/base/AppCard.vue'
import AppList from './components/base/AppList.vue' import AppList from './components/base/AppList.vue'
import beforeEnter from './utils/beforeEnter'
// 注册element-ui组件 // 注册element-ui组件
Vue.use(ElementUI, { size: 'small' }) Vue.use(ElementUI, { size: 'small' })
...@@ -22,11 +21,13 @@ Vue.use(ElementUI, { size: 'small' }) ...@@ -22,11 +21,13 @@ Vue.use(ElementUI, { size: 'small' })
Vue.component('AppCard', AppCard) Vue.component('AppCard', AppCard)
Vue.component('AppList', AppList) Vue.component('AppList', AppList)
// 注册指令
Vue.use(directives)
Vue.use(VueMeta)
// 注册模块 // 注册模块
modules({ router, store }) modules({ router, store })
router.beforeEach(beforeEnter)
new Vue({ new Vue({
store, store,
router, router,
......
...@@ -4,23 +4,23 @@ import httpRequest from '@/utils/axios' ...@@ -4,23 +4,23 @@ import httpRequest from '@/utils/axios'
* 获取审批列表 * 获取审批列表
*/ */
export function getAuditList(params) { export function getAuditList(params) {
return httpRequest.get('/api/lms-financial/school/lobby/list', { params }) return httpRequest.get('/api/zy/school/lobby/list', { params })
} }
/** /**
* 审批 * 审批
*/ */
export function auditApply(data) { export function auditApply(data) {
return httpRequest.post('/api/lms-financial/school/lobby/update', data) return httpRequest.post('/api/zy/school/lobby/update', data)
} }
/** /**
* 一键审批通过 * 一键审批通过
*/ */
export function multiPass(data) { export function multiPass(data) {
return httpRequest.post('/api/lms-financial/school/lobby/multi-pass', data) return httpRequest.post('/api/zy/school/lobby/multi-pass', data)
} }
/** /**
* 获取审批详情 * 获取审批详情
*/ */
export function getAuditDetails(params) { export function getAuditDetails(params) {
return httpRequest.get('/api/lms-financial/school/lobby/view', { params }) return httpRequest.get('/api/zy/school/lobby/view', { params })
} }
...@@ -4,9 +4,7 @@ ...@@ -4,9 +4,7 @@
<el-tab-pane name="0" :class="{ 'has-badge': total }"> <el-tab-pane name="0" :class="{ 'has-badge': total }">
<span slot="label"> <span slot="label">
<template v-if="total === 0">待办审批</template> <template v-if="total === 0">待办审批</template>
<el-badge v-else :value="total" :max="999" class="item" style="padding-right:10px;"> <el-badge v-else :value="total" :max="999" class="item" style="padding-right: 10px"> 待办审批 </el-badge>
待办审批
</el-badge>
</span> </span>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="1"> <el-tab-pane name="1">
...@@ -21,20 +19,32 @@ ...@@ -21,20 +19,32 @@
<app-class-select v-model="params.class_id" placeholder="请选择班级" /> <app-class-select v-model="params.class_id" placeholder="请选择班级" />
</template> </template>
<template v-slot:table-img="{ row }"> <template v-slot:table-img="{ row }">
<img :src="row.url" width="120" height="70"> <img :src="row.url" width="120" height="70" />
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<el-button v-if="btnView && tabActive !== '0'" type="primary" size="mini" plain @click="onDetails(row)">查看</el-button> <el-button v-if="btnView && tabActive !== '0'" type="primary" size="mini" plain @click="onDetails(row)"
<el-button v-if="btnAudit && tabActive === '0'" type="primary" size="mini" plain @click="onAudit(row)">办理</el-button> >查看</el-button
>
<el-button v-if="btnAudit && tabActive === '0'" type="primary" size="mini" plain @click="onAudit(row)"
>办理</el-button
>
</template> </template>
<template #footer> <template #footer>
<div v-if="tabActive === '0' && btnMultiPass"> <div v-if="tabActive === '0'" v-has="'menu_lobby_multi_pass'">
已选中 {{multipleSelection.length}} 已选中 {{ multipleSelection.length }}
<el-button style="margin-left:15px;" size="mini" :disabled="!multipleSelection.length" @click="fetchMultiPass">一键通过</el-button> <el-button style="margin-left: 15px" size="mini" :disabled="!multipleSelection.length" @click="fetchMultiPass"
>一键通过</el-button
>
</div> </div>
</template> </template>
</app-list> </app-list>
<dialog-audit v-if="isShowDialog" :info="info" :title="info ? '更新课程':'添加课程'" :visible.sync="isShowDialog" @success="handleSuccess" /> <dialog-audit
v-if="isShowDialog"
:info="info"
:title="info ? '更新课程' : '添加课程'"
:visible.sync="isShowDialog"
@success="handleSuccess"
/>
</app-card> </app-card>
</template> </template>
...@@ -61,13 +71,13 @@ export default { ...@@ -61,13 +71,13 @@ export default {
return this.$store.state.permissions return this.$store.state.permissions
}, },
btnMultiPass() { btnMultiPass() {
return !!this.permissions.find(item => item.tag === 'lobby-multiPass') return !!this.permissions.find(item => item.tag === 'menu_lobby_multi_pass')
}, },
btnAudit() { btnAudit() {
return !!this.permissions.find(item => item.tag === 'lobby-update') return !!this.permissions.find(item => item.tag === 'menu_lobby_update')
}, },
btnView() { btnView() {
return !!this.permissions.find(item => item.tag === 'lobby-view') return !!this.permissions.find(item => item.tag === 'menu_lobby_view')
}, },
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
...@@ -145,11 +155,11 @@ export default { ...@@ -145,11 +155,11 @@ export default {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-tabs__item.has-badge{ ::v-deep .el-tabs__item.has-badge {
padding-right:40px; padding-right: 40px;
} }
::v-deep .el-badge__content{ ::v-deep .el-badge__content {
top:50%; top: 50%;
// transform:translate(0, -50%) // transform:translate(0, -50%)
} }
</style> </style>
...@@ -5,4 +5,4 @@ import httpRequest from '@/utils/axios' ...@@ -5,4 +5,4 @@ import httpRequest from '@/utils/axios'
*/ */
export function getCourseList(params) { export function getCourseList(params) {
return httpRequest.get('/api/zy/v3-school/class/list', { params }) return httpRequest.get('/api/zy/v3-school/class/list', { params })
} }
\ No newline at end of file
...@@ -4,13 +4,13 @@ import httpRequest from '@/utils/axios' ...@@ -4,13 +4,13 @@ import httpRequest from '@/utils/axios'
* 获取控制台数据 * 获取控制台数据
*/ */
export function getDashboardList(params) { export function getDashboardList(params) {
return httpRequest.get('/api/lms-financial/school/console/index', { params }) return httpRequest.get('/api/zy/school/console/index', { params })
} }
/** /**
* 获取控制台数据 * 获取控制台数据
*/ */
export function getStudentList(params) { export function getStudentList(params) {
return httpRequest.get('/api/lms-financial/school/student/list', { params }) return httpRequest.get('/api/zy/school/student/list', { params })
} }
/** /**
* 导出学员列表 * 导出学员列表
...@@ -18,7 +18,7 @@ export function getStudentList(params) { ...@@ -18,7 +18,7 @@ export function getStudentList(params) {
*/ */
export function exportStudentList(params) { export function exportStudentList(params) {
return httpRequest({ return httpRequest({
url: '/api/lms-financial/school/student/download', url: '/api/zy/school/student/download',
method: 'get', method: 'get',
params, params,
responseType: 'blob' responseType: 'blob'
......
...@@ -7,34 +7,54 @@ ...@@ -7,34 +7,54 @@
<el-tag v-else type="info">Inactive</el-tag> <el-tag v-else type="info">Inactive</el-tag>
</div> </div>
<div class="cont"> <div class="cont">
<h5>{{item.class_name}}</h5> <h5>{{ item.class_name }}</h5>
<p>{{item.created_time}}</p> <p>{{ item.created_time }}</p>
</div> </div>
<div class="count"> <div class="count">
<el-progress :percentage="item.progress" color="#67c23a"></el-progress> <el-progress :percentage="item.progress" color="#67c23a"></el-progress>
<span><i class="el-icon-user-solid"></i>{{item.student_count}}</span> <span><i class="el-icon-user-solid"></i>{{ item.student_count }}</span>
</div> </div>
</div> </div>
</app-card> </app-card>
<app-card title="数据汇总"> <app-card title="数据汇总">
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template> <template>
<div v-if="btnExport" style="border-top:1px solid #f3f3f3;padding:15px 0;"> <div style="border-top: 1px solid #f3f3f3; padding: 15px 0">
<el-button type="primary" icon="el-icon-plus" @click="exportAll">导出Excel</el-button> <el-button type="primary" icon="el-icon-plus" @click="exportAll">导出Excel</el-button>
<span style="color:#666;font-size:14px;margin-left:15px;">导出当前搜索结果</span> <span style="color: #666; font-size: 14px; margin-left: 15px">导出当前搜索结果</span>
</div> </div>
</template> </template>
<template v-slot:filter-progress_min="{ params }"> <template v-slot:filter-progress_min="{ params }">
<el-input v-model="params.progress_min" style="width:69px;" onkeyup="this.value = this.value.replace(/[^\d.]/g,'');" /><p class="percent-sign">%</p><p class="separator">-</p> <el-input
v-model="params.progress_min"
style="width: 69px"
onkeyup="this.value = this.value.replace(/[^\d.]/g,'');"
/>
<p class="percent-sign">%</p>
<p class="separator">-</p>
</template> </template>
<template v-slot:filter-progress_max="{ params }"> <template v-slot:filter-progress_max="{ params }">
<el-input v-model="params.progress_max" style="width:69px;" onkeyup="this.value = this.value.replace(/[^\d.]/g,'');" /><p class="percent-sign">%</p> <el-input
v-model="params.progress_max"
style="width: 69px"
onkeyup="this.value = this.value.replace(/[^\d.]/g,'');"
/>
<p class="percent-sign">%</p>
</template> </template>
<template v-slot:filter-score="{ params }"> <template v-slot:filter-score="{ params }">
<el-input v-model="params.score_min" style="width:78px;margin-right:10px;" onkeyup="this.value = this.value.replace(/[^\d.]/g,'');" /><p class="separator">-</p> <el-input
v-model="params.score_min"
style="width: 78px; margin-right: 10px"
onkeyup="this.value = this.value.replace(/[^\d.]/g,'');"
/>
<p class="separator">-</p>
</template> </template>
<template v-slot:filter-score_max="{ params }"> <template v-slot:filter-score_max="{ params }">
<el-input v-model="params.score_max" style="width:78px;" onkeyup="this.value = this.value.replace(/[^\d.]/g,'');" /> <el-input
v-model="params.score_max"
style="width: 78px"
onkeyup="this.value = this.value.replace(/[^\d.]/g,'');"
/>
</template> </template>
<template v-slot:filter-cert="{ params }"> <template v-slot:filter-cert="{ params }">
<el-select v-model="params.has_certificate" placeholder="请选择"> <el-select v-model="params.has_certificate" placeholder="请选择">
...@@ -43,7 +63,7 @@ ...@@ -43,7 +63,7 @@
</el-select> </el-select>
</template> </template>
<template v-slot:table-img="{ row }"> <template v-slot:table-img="{ row }">
<img :src="row.url" width="120" height="70"> <img :src="row.url" width="120" height="70" />
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -60,18 +80,23 @@ export default { ...@@ -60,18 +80,23 @@ export default {
} }
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnExport() {
return !!this.permissions.find(item => item.tag === 'student-download')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
remote: { remote: {
httpRequest: getStudentList, httpRequest: getStudentList,
params: { personal_name: '', telephone: '', email: '', class_name: '', study_times: '', progress_min: '', progress_max: '', score_min: '', score_max: '', has_certificate: '' } params: {
personal_name: '',
telephone: '',
email: '',
class_name: '',
study_times: '',
progress_min: '',
progress_max: '',
score_min: '',
score_max: '',
has_certificate: ''
}
}, },
filters: [ filters: [
{ type: 'input', label: '学员姓名', placeholder: '学员姓名', prop: 'personal_name' }, { type: 'input', label: '学员姓名', placeholder: '学员姓名', prop: 'personal_name' },
...@@ -131,55 +156,56 @@ export default { ...@@ -131,55 +156,56 @@ export default {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.app-card{ .app-card {
padding:15px 0 20px; padding: 15px 0 20px;
::v-deep .app-card-hd{ ::v-deep .app-card-hd {
padding:0 20px; padding: 0 20px;
border-bottom:1px solid #ececec; border-bottom: 1px solid #ececec;
} }
::v-deep .app-card-bd{ ::v-deep .app-card-bd {
padding:20px; padding: 20px;
} }
} }
::v-deep .table-list-filter{ ::v-deep .table-list-filter {
.filter-buttons{ .filter-buttons {
margin-left:110px; margin-left: 110px;
} }
.el-input{ .el-input {
width:194px; width: 194px;
} }
.percent-sign, .separator{ .percent-sign,
display:inline-block; .separator {
width:16px; display: inline-block;
width: 16px;
} }
.separator{ .separator {
text-align:center; text-align: center;
} }
} }
.class-cont{ .class-cont {
.item{ .item {
display: flex; display: flex;
align-items:center; align-items: center;
padding:8px 0; padding: 8px 0;
.status{ .status {
width:20%; width: 20%;
} }
.cont{ .cont {
width:50%; width: 50%;
color:#363636; color: #363636;
p{ p {
color:#666; color: #666;
font-size:12px; font-size: 12px;
} }
} }
.count{ .count {
width:30%; width: 30%;
font-size:14px; font-size: 14px;
color:#777; color: #777;
display: flex; display: flex;
align-items:center; align-items: center;
::v-deep .el-progress{ ::v-deep .el-progress {
width:80%; width: 80%;
} }
} }
} }
......
...@@ -7,6 +7,12 @@ const routes = [ ...@@ -7,6 +7,12 @@ const routes = [
name: 'browser', name: 'browser',
path: '/browser', path: '/browser',
component: () => import('./views/browser.vue') component: () => import('./views/browser.vue')
},
{
path: '/choose',
component: () => import('@/components/layout/Index.vue'),
props: { sidebar: false },
children: [{ path: '', component: () => import('./views/Choose.vue') }]
} }
] ]
......
...@@ -261,7 +261,10 @@ ...@@ -261,7 +261,10 @@
</g> </g>
</svg> </svg>
<p class="tips">很抱歉,你暂时无权限访问...</p> <p class="tips">很抱歉,你暂时无权限访问...</p>
<a :href="loginUrl"><el-button round type="primary">重新登录</el-button></a> <div>
<router-link to="/"><el-button round type="default">返回首页</el-button></router-link>
<a :href="loginUrl" style="margin-left: 20px"><el-button round type="primary">重新登录</el-button></a>
</div>
</div> </div>
</template> </template>
......
<template>
<div class="choose-list">
<el-card class="choose-item" v-for="item in projects" :key="item.id" @click.native="handleClick(item)">
<h2>{{ item.name }}</h2>
</el-card>
</div>
</template>
<script>
export default {
computed: {
projects() {
return this.$store.state.appConfigList || []
}
},
methods: {
handleClick(item) {
// 设置App配置
this.$store.commit('setAppConfig', item)
// 重新获取权限
this.$store.dispatch('getPermissions')
this.$router.push({ path: '/' })
}
}
}
</script>
<style lang="scss" scoped>
.choose-list {
display: flex;
flex-wrap: wrap;
}
.choose-item {
margin: 10px;
cursor: pointer;
}
</style>
...@@ -4,11 +4,11 @@ import httpRequest from '@/utils/axios' ...@@ -4,11 +4,11 @@ import httpRequest from '@/utils/axios'
* 获取课程列表 * 获取课程列表
*/ */
export function getCertList(params) { export function getCertList(params) {
return httpRequest.get('/api/lms-financial/school/certificate/list', { params }) return httpRequest.get('/api/zy/school/certificate/list', { params })
} }
/** /**
* 获取课程列表 * 获取课程列表
*/ */
export function getCertDetails(params) { export function getCertDetails(params) {
return httpRequest.get('/api/lms-financial/school/certificate/view', { params }) return httpRequest.get('/api/zy/school/certificate/view', { params })
} }
...@@ -18,8 +18,9 @@ export default { ...@@ -18,8 +18,9 @@ export default {
} }
} }
</script> </script>
<style scoped> <style scoped>
video{ video {
width:100%; width: 100%;
} }
</style> </style>
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<app-card class="base-info" :title="$route.query.name"> <app-card class="base-info" :title="$route.query.name">
<p v-if="list.length === 0">还未取得证书</p> <p v-if="list.length === 0">还未取得证书</p>
<template v-else> <template v-else>
<div style="margin:20px;" v-for="item in list" :key="item.id"> <div style="margin: 20px" v-for="item in list" :key="item.id">
<img :src="item.url" /> <img :src="item.url" />
</div> </div>
</template> </template>
...@@ -33,29 +33,29 @@ export default { ...@@ -33,29 +33,29 @@ export default {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-card{ .app-card {
padding:15px 0 20px; padding: 15px 0 20px;
::v-deep .app-card-hd{ ::v-deep .app-card-hd {
padding:0 20px; padding: 0 20px;
border-bottom:1px solid #ececec; border-bottom: 1px solid #ececec;
} }
::v-deep .app-card-bd{ ::v-deep .app-card-bd {
padding:20px; padding: 20px;
} }
} }
.base-info{ .base-info {
::v-deep .app-card-bd{ ::v-deep .app-card-bd {
.title{ .title {
margin-bottom:20px; margin-bottom: 20px;
padding-bottom:14px; padding-bottom: 14px;
border-bottom:1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
i{ i {
font-size:24px; font-size: 24px;
color: #3276fc; color: #3276fc;
} }
} }
img{ img {
width:100%; width: 100%;
} }
} }
} }
......
...@@ -14,10 +14,13 @@ ...@@ -14,10 +14,13 @@
</el-select> </el-select>
</template> </template>
<template v-slot:table-img="{ row }"> <template v-slot:table-img="{ row }">
<img :src="row.url" width="120" height="70"> <img :src="row.url" width="120" height="70" />
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link v-if="btnView" :to="{ path: '/school/cert/details', query: { id: row.student_id, name: row.personal_name } }"> <router-link
:to="{ path: '/school/cert/details', query: { id: row.student_id, name: row.personal_name } }"
v-has="'menu_certificate_view'"
>
<el-button type="primary" size="mini" plain>查看</el-button> <el-button type="primary" size="mini" plain>查看</el-button>
</router-link> </router-link>
</template> </template>
...@@ -39,12 +42,6 @@ export default { ...@@ -39,12 +42,6 @@ export default {
AppClassSelect AppClassSelect
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnView() {
return !!this.permissions.find(item => item.tag === 'certificate-view')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
...@@ -96,8 +93,7 @@ export default { ...@@ -96,8 +93,7 @@ export default {
this.delTeach(row) this.delTeach(row)
}) })
}, },
delTeach(row) { delTeach(row) {}
}
} }
} }
</script> </script>
...@@ -4,77 +4,77 @@ import httpRequest from '@/utils/axios' ...@@ -4,77 +4,77 @@ import httpRequest from '@/utils/axios'
* 获取班级列表 * 获取班级列表
*/ */
export function getClassList(params) { export function getClassList(params) {
return httpRequest.get('/api/lms-financial/school/class/list', { params }) return httpRequest.get('/api/zy/school/class/list', { params })
} }
/** /**
* 获取班级详情 * 获取班级详情
*/ */
export function getClassDetail(params) { export function getClassDetail(params) {
return httpRequest.get('/api/lms-financial/school/class/view', { params }) return httpRequest.get('/api/zy/school/class/view', { params })
} }
/** /**
* 创建班级 * 创建班级
*/ */
export function createClass(data) { export function createClass(data) {
return httpRequest.post('/api/lms-financial/school/class/add', data) return httpRequest.post('/api/zy/school/class/add', data)
} }
/** /**
* 班级更新 * 班级更新
*/ */
export function updateClass(data) { export function updateClass(data) {
return httpRequest.post('/api/lms-financial/school/class/update', data) return httpRequest.post('/api/zy/school/class/update', data)
} }
/** /**
* 删除班级 * 删除班级
*/ */
export function deleteClass(data) { export function deleteClass(data) {
return httpRequest.post('/api/lms-financial/school/class/delete', data) return httpRequest.post('/api/zy/school/class/delete', data)
} }
/** /**
* 获取添加课程列表 * 获取添加课程列表
*/ */
export function getAddCourseList(params) { export function getAddCourseList(params) {
return httpRequest.get('/api/lms-financial/school/class/add-course', { params }) return httpRequest.get('/api/zy/school/class/add-course', { params })
} }
/** /**
* 添加(删除)课程 * 添加(删除)课程
*/ */
export function addCourse(data) { export function addCourse(data) {
return httpRequest.post('/api/lms-financial/school/class/add-course', data) return httpRequest.post('/api/zy/school/class/add-course', data)
} }
/** /**
* 添加(删除)课程 * 添加(删除)课程
*/ */
export function updateCourse(data) { export function updateCourse(data) {
return httpRequest.post('/api/lms-financial/school/class/update-course', data) return httpRequest.post('/api/zy/school/class/update-course', data)
} }
/** /**
* 获取添加教师列表 * 获取添加教师列表
*/ */
export function addTeacher(params) { export function addTeacher(params) {
return httpRequest.get('/api/lms-financial/school/class/add-teacher', { params }) return httpRequest.get('/api/zy/school/class/add-teacher', { params })
} }
/** /**
* 添加教师 * 添加教师
*/ */
export function addTeachers(data) { export function addTeachers(data) {
return httpRequest.post('/api/lms-financial/school/class/add-teacher', data) return httpRequest.post('/api/zy/school/class/add-teacher', data)
} }
/** /**
* 获取添加学员列表 * 获取添加学员列表
*/ */
export function addStudent(params) { export function addStudent(params) {
return httpRequest.get('/api/lms-financial/school/class/add-student', { params }) return httpRequest.get('/api/zy/school/class/add-student', { params })
} }
/** /**
* 添加学员 * 添加学员
*/ */
export function addStudents(data) { export function addStudents(data) {
return httpRequest.post('/api/lms-financial/school/class/add-student', data) return httpRequest.post('/api/zy/school/class/add-student', data)
} }
/** /**
* 学员导入 * 学员导入
...@@ -82,7 +82,7 @@ export function addStudents(data) { ...@@ -82,7 +82,7 @@ export function addStudents(data) {
export function importStudents(data) { export function importStudents(data) {
return httpRequest({ return httpRequest({
url: '/api/lms-financial/school/class/import-student', url: '/api/zy/school/class/import-student',
method: 'post', method: 'post',
headers: { 'Content-Type': 'multipart/form-data' }, headers: { 'Content-Type': 'multipart/form-data' },
timeout: 900000, timeout: 900000,
......
<template> <template>
<el-form :model="form" label-width="120px"> <el-form :model="form" label-width="72px">
<el-form-item label="班级名称" prop="class_name"> <el-form-item label="班级名称" prop="class_name">
<el-input v-model="form.class_name" disabled /> <el-input v-model="form.class_name" disabled />
</el-form-item> </el-form-item>
......
<template> <template>
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template #header-aside> <!-- <template #header-aside>
<el-button type="primary" icon="el-icon-plus" @click="handleAdd" v-if="btnAdd">添加</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleAdd">添加</el-button>
</template> </template> -->
<template v-slot:table-img="{ row }"> <template v-slot:table-img="{ row }">
<img v-if="row.curriculum" :src="row.curriculum.course_picture" width="120" height="70"> <img v-if="row.curriculum" :src="row.curriculum.course_picture" width="120" height="70" />
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link :to="{ path: '/school/course/details', query: { id: row.id } }"> <router-link :to="{ path: '/school/course/details', query: { id: row.id } }">
<el-button type="primary" size="mini" plain style="margin-right: 10px">查看</el-button> <el-button type="primary" size="mini" plain>查看</el-button>
</router-link> </router-link>
<el-button @click="onEdit(row)" type="primary" size="mini" plain v-if="btnUpdate">更新</el-button> <!-- <el-button @click="onEdit(row)" type="primary" size="mini" plain>更新</el-button>
<el-button @click="onRemove(row)" type="danger" size="mini" plain v-if="btnAdd">删除</el-button> <el-button @click="onRemove(row)" type="danger" size="mini" plain>删除</el-button> -->
</template> </template>
<AddCourse v-if="isShowDialog" :info="info" :title="info ? '更新课程':'添加课程'" :visible.sync="isShowDialog" @success="success" /> <AddCourse
v-if="isShowDialog"
:info="info"
:title="info ? '更新课程' : '添加课程'"
:visible.sync="isShowDialog"
@success="success"
/>
</app-list> </app-list>
</template> </template>
...@@ -40,36 +46,21 @@ export default { ...@@ -40,36 +46,21 @@ export default {
} }
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnAdd() {
return !!this.permissions.find(item => item.tag === 'class-addCourse')
},
btnUpdate() {
return !!this.permissions.find(item => item.tag === 'class-updateCourse')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
data: this.detail.course.list, data: this.detail.course.list,
// data: [
// { id: '111', url: 'https://webapp-pub.ezijing.com/www/h5/images/college-i1.png', name: '资产配置原理', start_time: '2022-01-01', end_time: '2022-12-31' },
// { id: '222', url: 'https://webapp-pub.ezijing.com/www/h5/images/college-i2.png', name: '金融市场与实践', start_time: '2022-01-01', end_time: '2022-12-31' },
// { id: '333', url: 'https://webapp-pub.ezijing.com/www/h5/images/college-i3.png', name: '家族财富传承', start_time: '2022-01-01', end_time: '2022-12-31' }
// ],
columns: [ columns: [
{ label: '课程图片', align: 'center', slots: 'table-img' }, { label: '课程图片', width: '140', slots: 'table-img' },
{ label: '课程名称', align: 'center', prop: 'course_name' }, { label: '课程名称', prop: 'course_name' },
{ label: '开课时间', align: 'center', prop: 'start_time' }, // { label: '开课时间', align: 'center', prop: 'start_time' },
{ label: '结课时间', align: 'center', prop: 'end_time' }, // { label: '结课时间', align: 'center', prop: 'end_time' },
{ label: '操作', slots: 'table-x', align: 'center', width: '220', fixed: 'right' } { label: '操作', slots: 'table-x', align: 'center', width: '120', fixed: 'right' }
] ]
} }
} }
}, },
created() { created() {},
},
methods: { methods: {
success() { success() {
this.$parent.$parent.getDetail() this.$parent.$parent.getDetail()
......
...@@ -2,11 +2,20 @@ ...@@ -2,11 +2,20 @@
<!-- 学员 --> <!-- 学员 -->
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template #header-aside> <template #header-aside>
<el-button type="primary" icon="el-icon-plus" @click="addStudent" v-if="btnAdd">添加</el-button> <el-button type="primary" icon="el-icon-plus" @click="addStudent" v-has="'menu_class_add_student'"
<el-button type="primary" icon="el-icon-upload2" style="margin-left: 20px" @click="importStudent" v-if="btnImport">导入</el-button> >添加</el-button
>
<el-button
type="primary"
icon="el-icon-upload2"
style="margin-left: 20px"
@click="importStudent"
v-has="'menu_class_import_student'"
>导入</el-button
>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<el-button @click="onRemove(row)" type="danger" size="mini" plain v-if="btnAdd">删除</el-button> <el-button @click="onRemove(row)" type="danger" size="mini" plain>删除</el-button>
</template> </template>
<AddStudent v-if="isShowDialog" :visible.sync="isShowDialog" @success="success" /> <AddStudent v-if="isShowDialog" :visible.sync="isShowDialog" @success="success" />
</app-list> </app-list>
...@@ -33,15 +42,6 @@ export default { ...@@ -33,15 +42,6 @@ export default {
} }
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnAdd() {
return !!this.permissions.find(item => item.tag === 'class-addStudent')
},
btnImport() {
return !!this.permissions.find(item => item.tag === 'class-importStudent')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
......
<template> <template>
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template #header-aside> <template #header-aside>
<el-button type="primary" icon="el-icon-plus" @click="addTeacher" v-if="btnAdd">添加</el-button> <el-button type="primary" icon="el-icon-plus" @click="addTeacher" v-has="'menu_class_add_teacher'"
>添加</el-button
>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<el-button @click="onRemove(row)" type="danger" size="mini" plain v-if="btnAdd">删除</el-button> <el-button @click="onRemove(row)" type="danger" size="mini" plain>删除</el-button>
</template> </template>
<AddTeacher v-if="isShowDialog" :visible.sync="isShowDialog" @success="success" /> <AddTeacher v-if="isShowDialog" :visible.sync="isShowDialog" @success="success" />
</app-list> </app-list>
...@@ -32,12 +34,6 @@ export default { ...@@ -32,12 +34,6 @@ export default {
} }
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnAdd() {
return !!this.permissions.find(item => item.tag === 'class-addTeacher')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
......
<template> <template>
<app-card> <app-card>
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template> <template #header-aside>
<el-row style="margin-bottom: 20px"> <el-button type="primary" icon="el-icon-plus" @click="onCreate" v-has="'menu_class_add'">新建</el-button>
<el-button type="primary" icon="el-icon-plus" @click="onCreate">新建</el-button>
</el-row>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link v-if="btnManage" :to="{ path: 'class/view', query: { id: row.id } }"> <router-link :to="{ path: 'class/view', query: { id: row.id } }" v-has="'menu_class_view'">
<el-button type="primary" style="margin-left: 10px" size="mini" plain>管理</el-button> <el-button type="primary" style="margin-left: 10px" size="mini" plain>管理</el-button>
</router-link> </router-link>
<router-link v-if="btnUpdate" :to="{ path: 'class/update', query: { id: row.id } }"> <router-link :to="{ path: 'class/update', query: { id: row.id } }" v-has="'menu_class_update'">
<el-button type="success" style="margin-left: 10px" size="mini" plain>更新</el-button> <el-button type="success" style="margin-left: 10px" size="mini" plain>更新</el-button>
</router-link> </router-link>
<el-button v-if="btnDelete" type="danger" @click="onRemove(row)" style="margin-left: 10px" size="mini" plain>删除</el-button> <el-button
type="danger"
style="margin-left: 10px"
size="mini"
plain
@click="onRemove(row)"
v-has="'menu_class_delete'"
>删除</el-button
>
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -30,21 +36,6 @@ export default { ...@@ -30,21 +36,6 @@ export default {
} }
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnCreate() {
return !!this.permissions.find(item => item.tag === 'class-add')
},
btnManage() {
return !!this.permissions.find(item => item.tag === 'class-view')
},
btnUpdate() {
return !!this.permissions.find(item => item.tag === 'class-update')
},
btnDelete() {
return !!this.permissions.find(item => item.tag === 'class-delete')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
......
...@@ -67,7 +67,7 @@ export default { ...@@ -67,7 +67,7 @@ export default {
}, },
methods: { methods: {
cancel() { cancel() {
this.$router.push('/class') this.$router.push('/school/class')
}, },
// 获取班级详情信息 // 获取班级详情信息
getDetail() { getDetail() {
...@@ -90,14 +90,14 @@ export default { ...@@ -90,14 +90,14 @@ export default {
create() { create() {
createClass(this.form).then(res => { createClass(this.form).then(res => {
this.$message.success('创建成功') this.$message.success('创建成功')
this.$router.push('/class') this.$router.push('/school/class')
}) })
}, },
// 编辑班级 // 编辑班级
edit() { edit() {
updateClass(Object.assign({ id: this.id }, this.form)).then(res => { updateClass(Object.assign({ id: this.id }, this.form)).then(res => {
this.$message.success('更新成功') this.$message.success('更新成功')
this.$router.push('/class') this.$router.push('/school/class')
}) })
} }
} }
......
...@@ -4,17 +4,23 @@ import httpRequest from '@/utils/axios' ...@@ -4,17 +4,23 @@ import httpRequest from '@/utils/axios'
* 获取课程列表 * 获取课程列表
*/ */
export function getCourseList(params) { export function getCourseList(params) {
return httpRequest.get('/api/lms-financial/school/course/list', { params }) return httpRequest.get('/api/zy/school/course/list', { params })
} }
/** /**
* 获取课程详情 * 获取课程详情
*/ */
export function getCourseDetails(params) { export function getCourseDetails(params) {
return httpRequest.get('/api/lms-financial/school/course/view', { params }) return httpRequest.get('/api/zy/school/course/view', { params })
} }
/** /**
* 获取视频地址 * 获取视频地址
*/ */
export function getVideoUrl(data) { export function getVideoUrl(data) {
return httpRequest.post('/api/lms-financial/school/course/aliyun-video-streaming', data) return httpRequest.post('/api/zy/school/course/aliyun-video-streaming', data)
}
/**
* 更新课程
*/
export function updateCourse(data) {
return httpRequest.post('/api/zy/school/course/update', data)
} }
<template>
<el-dialog :title="title" :close-on-click-modal="false" v-bind="$attrs" v-on="$listeners" width="400px">
<el-form ref="form" :model="form" :rules="rules">
<el-form-item label="权重" prop="sort">
<el-input-number v-model="form.sort" placeholder="请输入内容" size="small" :step-strictly="true" />
</el-form-item>
</el-form>
<template #footer>
<el-button type="text" @click="onCancel">取消</el-button>&nbsp;&nbsp;
<el-button type="primary" size="medium" @click="onPrimary">保存</el-button>
</template>
</el-dialog>
</template>
<script>
// lodash
import { updateCourse } from '../api.js'
import { pick } from 'lodash'
export default {
props: {
isEdit: { type: Boolean, default: false },
data: { type: Object, default: () => ({}) }
},
data() {
return {
form: { sort: '0' },
rules: {
sort: { required: true, message: '请输入权重', trigger: 'change' }
}
}
},
watch: {
data: {
immediate: true,
handler(data) {
this.form = Object.assign({}, this.form, data)
}
}
},
computed: {
title() {
return this.isEdit ? '更新课程' : '创建课程'
}
},
methods: {
// 取消
onCancel() {
this.$emit('update:visible', false)
},
// 确定
onPrimary() {
this.$refs.form.validate().then(() => {
const params = pick(this.form, ['id', 'sort'])
this.isEdit ? this.edit(params) : this.create(params)
})
},
// 创建课程
create(params) {
updateCourse(params).then(res => {
this.$message.success('创建成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
},
// 编辑权限
edit(params) {
updateCourse(params).then(res => {
this.$message.success('修改成功')
this.$emit('update:visible', false)
this.$emit('success', res.data)
})
}
}
}
</script>
<style></style>
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
<div> <div>
<app-card class="base-info" :title="info.course_name"> <app-card class="base-info" :title="info.course_name">
<div class="left"> <div class="left">
<img :src="info.course_picture"> <img :src="info.course_picture" />
</div> </div>
<div class="right"> <div class="right">
<h1>{{info.course_name}}</h1> <h1>{{ info.course_name }}</h1>
<div v-html="info.course_introducation"></div> <div v-html="info.course_introducation"></div>
</div> </div>
</app-card> </app-card>
...@@ -13,14 +13,18 @@ ...@@ -13,14 +13,18 @@
<el-collapse v-model="active" accordion> <el-collapse v-model="active" accordion>
<el-collapse-item v-for="(item, index) in list" :key="index" :name="index"> <el-collapse-item v-for="(item, index) in list" :key="index" :name="index">
<template slot="title"> <template slot="title">
<div class="course-title">{{item.name}}</div> <div class="course-title">{{ item.name }}</div>
</template> </template>
<div class="item" v-for="(it, idx) in item.children" :key="idx"> <div class="item" v-for="(it, idx) in item.children" :key="idx">
<i v-if="btnView && it.type === 2" class="el-icon-video-play" @click="fetchVideoUrl(it)"></i> <template v-if="it.type === 2">
<p><span @click="fetchVideoUrl(it)">{{it.name}}</span></p> <i class="el-icon-video-play" @click="fetchVideoUrl(it)" v-has="'menu_course_video'"></i>
</template>
<p>
<span @click="fetchVideoUrl(it)">{{ it.name }}</span>
</p>
<div class="time" v-if="it.type === 2"> <div class="time" v-if="it.type === 2">
<span class="text">时长</span> <span class="text">时长</span>
<el-tag size="mini">{{it.video.video_length | formatSeconds}}</el-tag> <el-tag size="mini">{{ it.video.video_length | formatSeconds }}</el-tag>
</div> </div>
</div> </div>
</el-collapse-item> </el-collapse-item>
...@@ -41,7 +45,12 @@ export default { ...@@ -41,7 +45,12 @@ export default {
{ {
title: '第一章 导论', title: '第一章 导论',
courseList: [ courseList: [
{ title: '1.张伟:了解金融市场', type: 'video', time: '07:14', url: 'https://webapp-pub.ezijing.com/upload/cms-admin/012236a48c7852c89ef436bc8c046186.mp4' }, {
title: '1.张伟:了解金融市场',
type: 'video',
time: '07:14',
url: 'https://webapp-pub.ezijing.com/upload/cms-admin/012236a48c7852c89ef436bc8c046186.mp4'
},
{ title: '2.张伟:了解金融市场(下)', type: 'video', time: '07:46' }, { title: '2.张伟:了解金融市场(下)', type: 'video', time: '07:46' },
{ title: '3.金融市场和金融体系的定义', type: 'video', time: '04:57' }, { title: '3.金融市场和金融体系的定义', type: 'video', time: '04:57' },
{ title: '4.金融市场参与者(上)', type: 'video', time: '11:14' } { title: '4.金融市场参与者(上)', type: 'video', time: '11:14' }
...@@ -66,8 +75,9 @@ export default { ...@@ -66,8 +75,9 @@ export default {
formatSeconds(value) { formatSeconds(value) {
const result = parseInt(value) const result = parseInt(value)
const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600) const h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
const m = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60)) const m =
const s = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60)) Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60)
const s = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60)
let res = '' let res = ''
if (h !== '00') res += `${h}h:` if (h !== '00') res += `${h}h:`
res += `${m}:` res += `${m}:`
...@@ -81,7 +91,7 @@ export default { ...@@ -81,7 +91,7 @@ export default {
return this.$store.state.permissions return this.$store.state.permissions
}, },
btnView() { btnView() {
return !!this.permissions.find(item => item.tag === 'course-video') return !!this.permissions.find(item => item.tag === 'menu_course_video')
} }
}, },
created() { created() {
...@@ -113,7 +123,6 @@ export default { ...@@ -113,7 +123,6 @@ export default {
id: this.$route.query.id || '' id: this.$route.query.id || ''
} }
getCourseDetails(params).then(res => { getCourseDetails(params).then(res => {
console.log(res)
this.info = res.data.info this.info = res.data.info
this.list = res.data.chapters this.list = res.data.chapters
}) })
...@@ -122,89 +131,90 @@ export default { ...@@ -122,89 +131,90 @@ export default {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-card{ .app-card {
padding:15px 0 20px; padding: 15px 0 20px;
::v-deep .app-card-hd{ ::v-deep .app-card-hd {
padding:0 20px; padding: 0 20px;
border-bottom:1px solid #ececec; border-bottom: 1px solid #ececec;
} }
::v-deep .app-card-bd{ ::v-deep .app-card-bd {
padding:20px; padding: 20px;
} }
} }
.base-info{ .base-info {
::v-deep .app-card-bd{ ::v-deep .app-card-bd {
display:flex; display: flex;
.left{ .left {
width:40%; width: 40%;
img{ img {
width:100%; width: 100%;
border: 1px solid #ddd; border: 1px solid #ddd;
padding:4px; padding: 4px;
border-radius: 4px; border-radius: 4px;
} }
} }
.right{ .right {
flex:1; flex: 1;
padding:30px; padding: 30px;
h1{ h1 {
font-size:30px; font-size: 30px;
line-height:50px; line-height: 50px;
color:#333; color: #333;
padding-bottom:20px; padding-bottom: 20px;
} }
p{ p {
font-size:14px; font-size: 14px;
line-height:24px; line-height: 24px;
color:#666; color: #666;
text-indent:2em; text-indent: 2em;
} }
} }
} }
} }
.content{ .content {
.el-collapse{ .el-collapse {
border:none; border: none;
.el-collapse-item{ .el-collapse-item {
border:1px solid #ececec; border: 1px solid #ececec;
border-radius:6px; border-radius: 6px;
margin-bottom:15px; margin-bottom: 15px;
overflow:hidden; overflow: hidden;
::v-deep .el-collapse-item__header, ::v-deep .el-collapse-item__wrap{ ::v-deep .el-collapse-item__header,
border:none; ::v-deep .el-collapse-item__wrap {
padding:0 20px; border: none;
font-size:14px; padding: 0 20px;
font-size: 14px;
} }
::v-deep .el-collapse-item__header{ ::v-deep .el-collapse-item__header {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
::v-deep .el-collapse-item__header.is-active{ ::v-deep .el-collapse-item__header.is-active {
border-bottom:1px solid #ececec; border-bottom: 1px solid #ececec;
} }
::v-deep .el-collapse-item__wrap .item{ ::v-deep .el-collapse-item__wrap .item {
display:flex; display: flex;
align-items:center; align-items: center;
padding:6px 0; padding: 6px 0;
border-bottom:1px solid #f3f3f3; border-bottom: 1px solid #f3f3f3;
cursor:pointer; cursor: pointer;
i{ i {
width:30px; width: 30px;
font-size:20px; font-size: 20px;
} }
i:hover{ i:hover {
color:#3276fc color: #3276fc;
} }
p{ p {
flex:1; flex: 1;
font-size:14px; font-size: 14px;
line-height:44px; line-height: 44px;
} }
.time{ .time {
width:60px; width: 60px;
text-align:center; text-align: center;
.text{ .text {
line-height:20px; line-height: 20px;
height:20px; height: 20px;
} }
} }
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<app-course-select v-model="params.course_id" placeholder="请选择课程" /> <app-course-select v-model="params.course_id" placeholder="请选择课程" />
</template> </template>
<template v-slot:table-img="{ row }"> <template v-slot:table-img="{ row }">
<img v-if="row.curriculum" :src="row.curriculum.course_picture" width="120" height="70"> <img v-if="row.curriculum" :src="row.curriculum.course_picture" width="120" height="70" />
</template> </template>
<template v-slot:table-desc="{ row }"> <template v-slot:table-desc="{ row }">
<el-popover placement="top-start" width="500" trigger="hover"> <el-popover placement="top-start" width="500" trigger="hover">
...@@ -14,11 +14,16 @@ ...@@ -14,11 +14,16 @@
</el-popover> </el-popover>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link v-if="btnView" :to="{ path: '/school/course/details', query: { id: row.id } }"> <router-link :to="{ path: '/school/course/details', query: { id: row.id } }" v-has="'menu_course_view'">
<el-button type="primary" size="mini" plain>查看</el-button> <el-button type="primary" size="mini" plain>查看</el-button>
</router-link> </router-link>
<el-button @click="handleUpdate(row)" type="success" size="mini" plain style="margin-left: 10px"
>更新</el-button
>
</template> </template>
</app-list> </app-list>
<!-- 更新 -->
<editform :visible.sync="visible" :isEdit="true" :data="editRaw" @success="handleSuccess" v-if="visible"></editform>
</app-card> </app-card>
</template> </template>
...@@ -26,71 +31,48 @@ ...@@ -26,71 +31,48 @@
import AppCourseSelect from '@/components/base/AppCourseSelect.vue' import AppCourseSelect from '@/components/base/AppCourseSelect.vue'
import { getCourseList } from '../api' import { getCourseList } from '../api'
export default { export default {
components: {
AppCourseSelect,
Editform: () => import('../components/Editform.vue')
},
data() { data() {
return { return {
isShowDialog: false, visible: false,
info: {} editRaw: {} // 编辑的数据
} }
}, },
components: {
AppCourseSelect
},
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnView() {
return !!this.permissions.find(item => item.tag === 'course-view')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
remote: { remote: { httpRequest: getCourseList, params: { course_name: '' } },
httpRequest: getCourseList, filters: [{ type: 'input', placeholder: '课程名称', prop: 'course_name' }],
params: { course_name: '' }
},
filters: [
{ type: 'input', placeholder: '课程名称', prop: 'course_name' }
],
columns: [ columns: [
{ label: '课程图片', align: 'center', slots: 'table-img' }, { label: '课程图片', width: '140', slots: 'table-img' },
{ label: '课程名称', align: 'center', prop: 'course_name' }, { label: '课程名称', prop: 'course_name' },
{ label: '课程描述', align: 'center', slots: 'table-desc' }, { label: '课程描述', slots: 'table-desc' },
{ label: '操作', slots: 'table-x', align: 'center', width: '220', fixed: 'right' } { label: '权重', prop: 'sort', align: 'center' },
{ label: '操作', slots: 'table-x', align: 'center', width: '160', fixed: 'right' }
] ]
} }
} }
}, },
methods: { methods: {
handleAdd() { // 编辑
this.isShowDialog = true handleUpdate(row) {
this.info = null this.isEdit = true
}, this.editRaw = row
onDetails(row) { this.visible = true
console.log(row)
},
onEdit(row) {
this.isShowDialog = true
this.info = row
},
// 删除课程
onRemove(row) {
this.$confirm('你确定要删除此项吗', '确认提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 调用删除接口
this.delTeach(row)
})
}, },
delTeach(row) { // 更新成功刷新列表
handleSuccess() {
this.$refs.list.refetch()
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.table-desc{ .table-desc {
max-height:70px; max-height: 70px;
} }
</style> </style>
...@@ -4,11 +4,11 @@ import httpRequest from '@/utils/axios' ...@@ -4,11 +4,11 @@ import httpRequest from '@/utils/axios'
* 获取课程列表 * 获取课程列表
*/ */
export function getExamList(params) { export function getExamList(params) {
return httpRequest.get('/api/lms-financial/school/examination/list', { params }) return httpRequest.get('/api/zy/school/examination/list', { params })
} }
/** /**
* 获取课程列表 * 获取课程列表
*/ */
export function getExamineeList(params) { export function getExamineeList(params) {
return httpRequest.get('/api/lms-financial/school/examination/sheet-list', { params }) return httpRequest.get('/api/zy/school/examination/sheet-list', { params })
} }
...@@ -19,7 +19,7 @@ export default { ...@@ -19,7 +19,7 @@ export default {
} }
</script> </script>
<style scoped> <style scoped>
video{ video {
width:100%; width: 100%;
} }
</style> </style>
\ No newline at end of file
<template> <template>
<app-card> <app-card>
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template v-slot:table-time="{ row }"> <template v-slot:table-time="{ row }"> {{ row.start_time }} - {{ row.end_time }} </template>
{{row.start_time}} - {{row.end_time}}
</template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link v-if="btnView" :to="{ path: '/school/exam/details', query: { id: row.id, title: row.paper_title } }"> <router-link
:to="{ path: '/school/exam/details', query: { id: row.id, title: row.paper_title } }"
v-has="'menu_examination_sheet_list'"
>
<el-button type="primary" size="mini" plain>查看</el-button> <el-button type="primary" size="mini" plain>查看</el-button>
</router-link> </router-link>
</template> </template>
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
<script> <script>
import { getExamList } from '../api' import { getExamList } from '../api'
const statusMap = { 0: '未设置', 1: '进行中', 2: '已完成' } // const statusMap = { 0: '未设置', 1: '进行中', 2: '已完成' }
export default { export default {
data() { data() {
return { return {
...@@ -23,12 +24,6 @@ export default { ...@@ -23,12 +24,6 @@ export default {
} }
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnView() {
return !!this.permissions.find(item => item.tag === 'examination-sheetList')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
...@@ -37,23 +32,21 @@ export default { ...@@ -37,23 +32,21 @@ export default {
params: {} params: {}
}, },
columns: [ columns: [
{ label: '考试名称', align: 'center', prop: 'paper_title' }, { label: '考试名称', prop: 'paper_title' },
{ // {
prop: 'status', // prop: 'status',
label: '考试有效期', // label: '考试有效期',
align: 'center', // computed({ row }) {
computed({ row }) { // // return statusMap[row.status]
// return statusMap[row.status] // return '进行中'
return '进行中' // }
} // },
},
// { label: '考试日期', align: 'center', slots: 'table-time' }, // { label: '考试日期', align: 'center', slots: 'table-time' },
{ label: '操作', slots: 'table-x', align: 'center', width: '220', fixed: 'right' } { label: '操作', slots: 'table-x', align: 'center', width: '120', fixed: 'right' }
] ]
} }
} }
}, },
methods: { methods: {}
}
} }
</script> </script>
import httpRequest from '@/utils/axios'
/**
* 获取考卷批阅列表
*/
export function getExamReivewList(params) {
return httpRequest.get('/api/zy/school/examination/examination-list', { params })
}
/**
* 老师批阅
*/
export function getReviewDetails(params) {
return httpRequest.get('/api/zy/school/examination/sheet-details', { params })
}
/**
* 提交批阅
*/
export function submitReviewDetails(params) {
return httpRequest.post('/api/zy/school/examination/sheet-submit', params)
}
const routes = [
{
path: '/',
component: () => import('@/components/layout/index.vue'),
children: [{ path: '/school/review/exam', component: () => import('./views/Index.vue') }]
},
{ path: '/school/review/exam/review', component: () => import('./views/Review.vue') }
]
export { routes }
<template>
<app-card>
<app-list v-bind="tableOptions" ref="list" @row-click="handleRowClick">
<template v-slot:table-name="{ row }">
<el-link type="primary">{{ row.paper_title }}</el-link>
</template>
</app-list>
<review-students
@studentReview="studentReview"
:visible.sync="visible"
:students="currentClickRow.students"
></review-students>
</app-card>
</template>
<script>
import { getExamReivewList } from '../api.js'
import ReviewStudents from '@/components/ReviewStudents.vue'
export default {
components: { ReviewStudents },
data() {
return {
visible: false,
currentClickRow: {}
}
},
computed: {
// 列表配置
tableOptions() {
return {
remote: {
httpRequest: getExamReivewList,
params: { class_name: '', paper_title: '' }
},
filters: [
{ type: 'input', prop: 'class_name', placeholder: '班级名称' },
{ type: 'input', prop: 'paper_title', placeholder: '考卷名称' }
],
columns: [
{ label: '考卷名称', prop: 'paper_title', slots: 'table-name' },
{ label: '班级名称', prop: 'class_name', align: 'center' },
{ label: '未批阅学生数量', prop: 'commit_num', align: 'center' }
]
}
}
},
methods: {
handleRowClick(row) {
this.currentClickRow = row
window.localStorage.examStudentsList = JSON.stringify(row.students)
this.visible = true
},
studentReview(data) {
this.$router.push({
path: '/school/review/exam/review',
query: { sheet_id: data.sheet_id, stu_id: data.id }
})
}
}
}
</script>
<template>
<div>
<exam-card
title="批阅考卷"
:status="3"
:hasSubmitBtn="false"
:hasCountdown="false"
:hasCollect="false"
:hasMark="false"
:data="data"
@back="handleBack"
ref="exam"
v-if="Object.keys(data).length"
>
<template v-slot:question-item="{ item, data }">
<div class="review-box">
<div class="review-btn">
<el-button type="primary" @click="item.comment_visible = true">点评</el-button>
</div>
<div class="review-card" v-if="item.comment_visible || item.checked_flag">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>本题{{ item.score }}</span>
<div class="score">
<span>学生得分:</span>
<el-input
type="number"
:disabled="item.checked_flag"
v-model="item.user_score"
placeholder="请输入分数"
size="mini"
style="width: 80px"
@input="handleScoreInput(item)"
></el-input>
</div>
</div>
<div class="textarea">
<el-input
:disabled="item.checked_flag"
type="textarea"
:rows="5"
placeholder="请输入本题点评"
max="2"
resize="none"
v-model="item.comment"
:maxlength="100"
:show-word-limit="true"
>
</el-input>
</div>
<div class="submit-btn">
<el-button type="primary" @click="submitComment(item, data)" v-if="!item.checked_flag">
提交点评
</el-button>
</div>
</el-card>
</div>
</div>
</template>
<template v-slot:students>
<div class="stu-list">
<div class="title">
<span>学生列表</span>
<el-select v-model="selectValue" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</div>
<ul>
<li
:class="item.sheet_id === sheetId ? 'active' : ''"
v-for="(item, index) in currentStudentList"
:key="index"
@click="selectStudent(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
</exam-card>
</div>
</template>
<script>
import * as api from '../api.js'
import ExamCard from '@/components/exam/examCard.vue'
export default {
components: { ExamCard },
data() {
return {
data: {},
selectValue: 0,
studentList: [],
sheetId: this.$route.query.sheet_id,
options: [
{ value: 0, label: '全部' },
{ value: 1, label: '未批阅' },
{ value: 2, label: '已批阅' }
]
}
},
computed: {
examId() {
return this.$route.query.exam_id
},
currentStudentList() {
if (this.selectValue === 0) {
return this.studentList
} else {
return this.studentList.filter(item => item.status === this.selectValue)
}
}
},
created() {
// 获取考卷
this.getTopic()
},
mounted() {
this.studentList = JSON.parse(window.localStorage.examStudentsList)
},
methods: {
handleScoreInput(item) {
item.user_score = parseInt(item.user_score.replace(/[^\d]+/g, ''))
if (item.user_score > item.score) {
item.user_score = item.score
}
},
selectStudent(item) {
this.sheetId = item.sheet_id
this.getTopic()
this.$refs.exam.reset()
},
// 获取考卷
getTopic() {
api.getReviewDetails({ sheet_id: this.sheetId }).then(response => {
this.data = JSON.parse(response.data).sheet
})
},
// 返回
handleBack() {
this.$router.push('/school/review/exam')
},
// 提交批阅
submitComment(item, data) {
if (item.comment === '') {
this.$message('请输入点评内容')
return false
}
if (item.user_score === '') {
this.$message('请输入分数')
return false
}
if (parseInt(item.user_score) > item.score) {
this.$message('请填写正确分值')
return false
}
const param = {
sheet_id: this.sheetId,
question_item_id: data.question_item_id,
question_id: item.id,
comment: item.comment,
score: item.user_score
}
this.$confirm('确认评价后将不得再次修改', '请确认', {
confirmButtonText: '点评',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
api.submitReviewDetails(param).then(response => {
item.checked_flag = true
this.$message('批阅成功')
if (response.status === 2) {
this.updateStudentStatus(response.status)
}
})
})
},
updateStudentStatus(stauts) {
const index = this.studentList.findIndex(item => item.sheet_id === this.sheetId)
if (index !== -1) {
this.studentList[index].status = stauts
}
window.localStorage.setItem('examStudentsList', JSON.stringify(this.studentList))
}
}
}
</script>
<style lang="scss" scoped>
.review-btn {
display: flex;
justify-content: right;
padding: 20px 0;
}
.score {
float: right;
display: flex;
align-items: center;
}
.submit-btn {
display: flex;
justify-content: center;
padding-top: 20px;
}
.stu-list {
.title {
// text-align: center;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
::v-deep {
.el-select {
width: 120px;
}
}
}
ul {
padding-bottom: 80px;
li {
padding: 3px 0;
&.active {
color: #c01540;
}
}
}
}
</style>
import httpRequest from '@/utils/axios'
/**
* 获取习题批阅列表
*/
export function getTestReivewList(params) {
return httpRequest.get('/api/zy/school/examination/chapter-examination-list', { params })
}
/**
* 老师批阅
*/
export function getReviewDetails(params) {
return httpRequest.get('/api/zy/school/examination/sheet-details', { params })
}
/**
* 提交批阅
*/
export function submitReviewDetails(params) {
return httpRequest.post('/api/zy/school/examination/sheet-submit', params)
}
const routes = [
{
path: '/',
component: () => import('@/components/layout/index.vue'),
children: [{ path: '/school/review/test', component: () => import('./views/Index.vue') }]
},
{ path: '/school/review/test/review', component: () => import('./views/Review.vue') }
]
export { routes }
<template>
<app-card>
<app-list v-bind="tableOptions" ref="list" @row-click="handleRowClick">
<template v-slot:table-name="{ row }">
<el-link type="primary">{{ row.paper_title }}</el-link>
</template>
</app-list>
<review-students
@studentReview="studentReview"
:visible.sync="visible"
:students="currentClickRow.students"
></review-students>
</app-card>
</template>
<script>
import { getTestReivewList } from '../api.js'
import ReviewStudents from '@/components/ReviewStudents.vue'
export default {
components: { ReviewStudents },
data() {
return {
visible: false,
currentClickRow: {},
all_courses: [],
courseId: ''
}
},
computed: {
// 列表配置
tableOptions() {
return {
remote: {
httpRequest: getTestReivewList,
params: { course_id: this.courseId, chapter_id: '' },
beforeRequest: this.beforeRequest,
callback: this.callback
},
filters: [
{
type: 'select',
prop: 'course_id',
placeholder: '选择课程',
options: this.all_courses,
labelKey: 'course_name',
valueKey: 'id'
},
{
type: 'select',
prop: 'chapter_id',
placeholder: '选择章节',
options: this.chapters,
labelKey: 'chapter_name',
valueKey: 'id'
}
],
columns: [
{ label: '考卷名称', prop: 'paper_title', slots: 'table-name' },
{ label: '班级名称', prop: 'class_name', align: 'center' },
{ label: '未批阅学生数量', prop: 'commit_num', align: 'center' }
]
}
},
chapters() {
const found = this.all_courses.find(item => item.id === this.courseId)
return found ? found.chapters : []
}
},
methods: {
handleRowClick(row) {
this.currentClickRow = row
window.localStorage.testStudentsList = JSON.stringify(row.students)
this.visible = true
},
studentReview(data) {
this.$router.push({
path: '/school/review/test/review',
query: { sheet_id: data.sheet_id, stu_id: data.id }
})
},
beforeRequest(params) {
this.courseId = params.course_id
return params
},
callback(data) {
if (!this.all_courses.length) {
this.all_courses = data.all_courses
}
return data.list
}
}
}
</script>
<template>
<div>
<exam-card
title="批阅考卷"
:status="3"
:hasSubmitBtn="false"
:hasCountdown="false"
:hasCollect="false"
:hasMark="false"
:data="data"
@back="handleBack"
ref="exam"
v-if="Object.keys(data).length"
>
<template v-slot:question-item="{ item, data }">
<div class="review-box">
<div class="review-btn">
<el-button type="primary" @click="item.comment_visible = true">点评</el-button>
</div>
<div class="review-card" v-if="item.comment_visible || item.checked_flag">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>本题{{ item.score }}</span>
<div class="score">
<span>学生得分:</span>
<el-input
type="number"
:disabled="item.checked_flag"
:max="item.score"
v-model="item.user_score"
placeholder="请输入分数"
size="mini"
style="width: 80px"
@input="handleScoreInput(item)"
></el-input>
</div>
</div>
<div class="textarea">
<el-input
:disabled="item.checked_flag"
type="textarea"
:rows="5"
placeholder="请输入本题点评"
max="2"
resize="none"
v-model="item.comment"
:maxlength="100"
:show-word-limit="true"
>
</el-input>
</div>
<div class="submit-btn">
<el-button type="primary" @click="submitComment(item, data)" v-if="!item.checked_flag">
提交点评
</el-button>
</div>
</el-card>
</div>
</div>
</template>
<template v-slot:students>
<div class="stu-list">
<div class="title">
<span>学生列表</span>
<el-select v-model="selectValue" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</div>
<ul>
<li
:class="item.sheet_id === sheetId ? 'active' : ''"
v-for="(item, index) in currentStudentList"
:key="index"
@click="selectStudent(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</template>
</exam-card>
</div>
</template>
<script>
import * as api from '../api.js'
import ExamCard from '@/components/exam/examCard.vue'
export default {
components: { ExamCard },
data() {
return {
data: {},
selectValue: 0,
sheetId: this.$route.query.sheet_id,
studentList: [],
options: [
{ value: 0, label: '全部' },
{ value: 1, label: '未批阅' },
{ value: 2, label: '已批阅' }
]
}
},
computed: {
examId() {
return this.$route.query.exam_id
},
currentStudentList() {
if (this.selectValue === 0) {
return this.studentList
} else {
return this.studentList.filter(item => item.status === this.selectValue)
}
}
},
created() {
// 获取考卷
this.getTopic()
},
mounted() {
this.studentList = JSON.parse(window.localStorage.testStudentsList)
},
methods: {
handleScoreInput(item) {
item.user_score = parseInt(item.user_score.replace(/[^\d]+/g, ''))
if (item.user_score > item.score) {
item.user_score = item.score
}
},
selectStudent(item) {
this.sheetId = item.sheet_id
this.getTopic()
this.$refs.exam.reset()
},
// 获取考卷
getTopic() {
api.getReviewDetails({ sheet_id: this.sheetId, type: 'chapter' }).then(response => {
this.data = JSON.parse(response.data).sheet
})
},
// 返回
handleBack() {
this.$router.push('/school/review/test')
},
// 提交批阅
submitComment(item, data) {
if (item.comment === '') {
this.$message('请输入点评内容')
return false
}
if (item.user_score === '') {
this.$message('请输入分数')
return false
}
if (parseInt(item.user_score) > item.score) {
this.$message('请填写正确分值')
return false
}
const param = {
type: 'chapter',
sheet_id: this.sheetId,
question_item_id: data.question_item_id,
question_id: item.id,
comment: item.comment,
score: item.user_score
}
this.$confirm('确认评价后将不得再次修改', '请确认', {
confirmButtonText: '点评',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
api.submitReviewDetails(param).then(response => {
item.checked_flag = true
this.$message('批阅成功')
if (response.status === 2) {
this.updateStudentStatus(response.status)
}
})
})
},
updateStudentStatus(stauts) {
const index = this.studentList.findIndex(item => item.sheet_id === this.sheetId)
if (index !== -1) {
this.studentList[index].status = stauts
}
window.localStorage.setItem('testStudentsList', JSON.stringify(this.studentList))
}
}
}
</script>
<style lang="scss" scoped>
.review-btn {
display: flex;
justify-content: right;
padding: 20px 0;
}
.score {
float: right;
display: flex;
align-items: center;
}
.submit-btn {
display: flex;
justify-content: center;
padding-top: 20px;
}
.stu-list {
.title {
// text-align: center;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
::v-deep {
.el-select {
width: 120px;
}
}
}
ul {
padding-bottom: 80px;
li {
padding: 3px 0;
&.active {
color: #c01540;
}
}
}
}
</style>
...@@ -4,28 +4,28 @@ import httpRequest from '@/utils/axios' ...@@ -4,28 +4,28 @@ import httpRequest from '@/utils/axios'
* 获取学员列表 * 获取学员列表
*/ */
export function getStudentList(params) { export function getStudentList(params) {
return httpRequest.get('/api/lms-financial/school/student/list', { params }) return httpRequest.get('/api/zy/school/student/list', { params })
} }
/** /**
* 获取学员详情 * 获取学员详情
*/ */
export function getStudentDetail(params) { export function getStudentDetail(params) {
return httpRequest.get('/api/lms-financial/school/student/view', { params }) return httpRequest.get('/api/zy/school/student/view', { params })
} }
/** /**
* 学员添加 * 学员添加
*/ */
export function createStudent(data) { export function createStudent(data) {
return httpRequest.post('/api/lms-financial/school/student/add', data) return httpRequest.post('/api/zy/school/student/add', data)
} }
/** /**
* 学员更新 * 学员更新
*/ */
export function updateStudent(data) { export function updateStudent(data) {
return httpRequest.post('/api/lms-financial/school/student/update', data) return httpRequest.post('/api/zy/school/student/update', data)
} }
/** /**
...@@ -34,7 +34,7 @@ export function updateStudent(data) { ...@@ -34,7 +34,7 @@ export function updateStudent(data) {
export function importStudent(data) { export function importStudent(data) {
return httpRequest({ return httpRequest({
url: '/api/lms-financial/school/student/import', url: '/api/zy/school/student/import',
method: 'post', method: 'post',
headers: { 'Content-Type': 'multipart/form-data' }, headers: { 'Content-Type': 'multipart/form-data' },
timeout: 900000, timeout: 900000,
...@@ -46,12 +46,12 @@ export function importStudent(data) { ...@@ -46,12 +46,12 @@ export function importStudent(data) {
* 学员列表下载 * 学员列表下载
*/ */
export function downStuList(params) { export function downStuList(params) {
return httpRequest.get('/api/lms-financial/school/student/download', { params }) return httpRequest.get('/api/zy/school/student/download', { params })
} }
/** /**
* 学员删除 * 学员删除
*/ */
export function deleteStudent(data) { export function deleteStudent(data) {
return httpRequest.post('/api/lms-financial/school/student/delete', data) return httpRequest.post('/api/zy/school/student/delete', data)
} }
...@@ -7,35 +7,35 @@ const routes = [ ...@@ -7,35 +7,35 @@ const routes = [
name: 'student', name: 'student',
path: 'student', path: 'student',
component: () => import('./views/List.vue'), component: () => import('./views/List.vue'),
meta: { title: '员管理' } meta: { title: '员管理' }
}, },
{ {
path: 'student/view', path: 'student/view',
component: () => import('./views/Detail.vue'), component: () => import('./views/Detail.vue'),
meta: { title: '员管理' } meta: { title: '员管理' }
}, },
{ {
path: 'student/process', path: 'student/process',
component: () => import('./views/Process.vue'), component: () => import('./views/Process.vue'),
meta: { title: '员管理' } meta: { title: '员管理' }
}, },
{ {
name: 'processDetail', name: 'processDetail',
path: 'student/process/detail', path: 'student/process/detail',
component: () => import('../student/components/processDetail.vue'), component: () => import('../student/components/processDetail.vue'),
meta: { title: '员管理' } meta: { title: '员管理' }
}, },
{ {
name: 'addStudents', name: 'addStudents',
path: 'student/update', path: 'student/update',
component: () => import('./views/Update.vue'), component: () => import('./views/Update.vue'),
meta: { title: '员管理' } meta: { title: '员管理' }
}, },
{ {
name: 'importStudent', name: 'importStudent',
path: 'student/importStudent', path: 'student/importStudent',
component: () => import('../student/components/ImportStudent.vue'), component: () => import('../student/components/ImportStudent.vue'),
meta: { title: '员管理' } meta: { title: '员管理' }
} }
] ]
} }
......
...@@ -3,24 +3,40 @@ ...@@ -3,24 +3,40 @@
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template> <template>
<el-row style="margin-bottom: 20px"> <el-row style="margin-bottom: 20px">
<el-button v-if="btnAdd" type="primary" icon="el-icon-plus" size="mini" @click="add">新建</el-button> <el-button type="primary" icon="el-icon-plus" size="mini" @click="add" v-has="'menu_school_students_add'"
<el-button v-if="btnImport" type="primary" icon="el-icon-upload2" style="margin-left: 20px" @click="imports" size="mini" >新建</el-button
>
<el-button
type="primary"
icon="el-icon-upload2"
style="margin-left: 20px"
@click="imports"
size="mini"
v-has="'menu_school_students_import'"
>导入</el-button >导入</el-button
> >
<!-- <el-button type="primary" icon="el-icon-download" style="margin-left: 20px" @click="downLoad" size="mini">下载</el-button> --> <!-- <el-button type="primary" icon="el-icon-download" style="margin-left: 20px" @click="downLoad" size="mini">下载</el-button> -->
</el-row> </el-row>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<!-- <router-link :to="{ path: 'student/process', query: { id: row.id } }"> <router-link :to="{ path: 'student/process', query: { id: row.id } }">
<el-button type="warning" size="mini" plain>学习进度</el-button> <el-button type="warning" size="mini" plain>学习进度</el-button>
</router-link> --> </router-link>
<router-link v-if="btnView" :to="{ path: 'student/view', query: { id: row.id } }"> <router-link :to="{ path: 'student/view', query: { id: row.id } }" v-has="'menu_school_students_view'">
<el-button type="primary" style="margin-left: 10px" size="mini" plain>查看</el-button> <el-button type="primary" style="margin-left: 10px" size="mini" plain>查看</el-button>
</router-link> </router-link>
<router-link v-if="btnUpdate" :to="{ path: 'student/update', query: { id: row.id } }"> <router-link :to="{ path: 'student/update', query: { id: row.id } }" v-has="'menu_school_students_update'">
<el-button type="success" style="margin-left: 10px" size="mini" plain>更新</el-button> <el-button type="success" style="margin-left: 10px" size="mini" plain>更新</el-button>
</router-link> </router-link>
<el-button v-if="btnDelete" type="danger" @click="onRemove(row)" style="margin-left: 10px" size="mini" plain>删除</el-button> <el-button
type="danger"
@click="onRemove(row)"
style="margin-left: 10px"
size="mini"
plain
v-has="'menu_school_student_delete'"
>删除</el-button
>
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -36,24 +52,6 @@ export default { ...@@ -36,24 +52,6 @@ export default {
return {} return {}
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnAdd() {
return !!this.permissions.find(item => item.tag === 'student-add')
},
btnUpdate() {
return !!this.permissions.find(item => item.tag === 'student-update')
},
btnDelete() {
return !!this.permissions.find(item => item.tag === 'student-delete')
},
btnView() {
return !!this.permissions.find(item => item.tag === 'student-view')
},
btnImport() {
return !!this.permissions.find(item => item.tag === 'student-import')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
...@@ -98,14 +96,10 @@ export default { ...@@ -98,14 +96,10 @@ export default {
}, },
methods: { methods: {
add() { add() {
this.$router.push({ this.$router.push({ name: 'addStudents' })
name: 'addStudents'
})
}, },
imports() { imports() {
this.$router.push({ this.$router.push({ name: 'importStudent' })
name: 'importStudent'
})
}, },
// 删除 // 删除
onRemove(row) { onRemove(row) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<app-card> <app-card>
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template v-slot:course_picture="{ row }"> <template v-slot:course_picture="{ row }">
<el-image :src="row.course_picture"></el-image> <el-image :src="row.course_picture" style="width: 120px; height: 70px"></el-image>
</template> </template>
<template v-slot:progress="{ row }"> <template v-slot:progress="{ row }">
<el-progress :percentage="row.progress"></el-progress> <el-progress :percentage="row.progress"></el-progress>
...@@ -32,12 +32,12 @@ export default { ...@@ -32,12 +32,12 @@ export default {
return { return {
data: this.list, data: this.list,
columns: [ columns: [
{ label: '课程图片', prop: 'course_picture', slots: 'course_picture', width: '140' },
{ label: '课程名称', prop: 'course_name' },
{ label: '课程ID', align: 'center', prop: 'id' }, { label: '课程ID', align: 'center', prop: 'id' },
{ label: '课程名称', align: 'center', prop: 'course_name' },
{ label: '课程图片', align: 'center', prop: 'course_picture', slots: 'course_picture' },
{ label: '总进度', align: 'center', prop: 'progress', slots: 'progress' }, { label: '总进度', align: 'center', prop: 'progress', slots: 'progress' },
{ label: '总时长', align: 'center', prop: 'max_length' }, { label: '总时长', align: 'center', prop: 'max_length' },
{ label: '操作', slots: 'table-x', align: 'center', fixed: 'right' } { label: '操作', slots: 'table-x', align: 'center', fixed: 'right', width: '100' }
] ]
} }
} }
......
...@@ -4,42 +4,42 @@ import httpRequest from '@/utils/axios' ...@@ -4,42 +4,42 @@ import httpRequest from '@/utils/axios'
* 获取班级列表 * 获取班级列表
*/ */
export function getTeacherList(params) { export function getTeacherList(params) {
return httpRequest.get('/api/lms-financial/school/teacher/list', { params }) return httpRequest.get('/api/zy/school/teacher/list', { params })
} }
/** /**
* 获取教师详情 * 获取教师详情
*/ */
export function getTeacherDetail(params) { export function getTeacherDetail(params) {
return httpRequest.get('/api/lms-financial/school/teacher/view', { params }) return httpRequest.get('/api/zy/school/teacher/view', { params })
} }
/** /**
* 教师添加/创建 * 教师添加/创建
*/ */
export function createTeacher(data) { export function createTeacher(data) {
return httpRequest.post('/api/lms-financial/school/teacher/add', data) return httpRequest.post('/api/zy/school/teacher/add', data)
} }
/** /**
* 修改教师 * 修改教师
*/ */
export function updateTeacher(data) { export function updateTeacher(data) {
return httpRequest.post('/api/lms-financial/school/teacher/update', data) return httpRequest.post('/api/zy/school/teacher/update', data)
} }
/** /**
* 删除教师 * 删除教师
*/ */
export function deleteTeacher(data) { export function deleteTeacher(data) {
return httpRequest.post('/api/lms-financial/school/teacher/delete', data) return httpRequest.post('/api/zy/school/teacher/delete', data)
} }
/** /**
* 导入教师 * 导入教师
*/ */
export function importTeacher(data) { export function importTeacher(data) {
return httpRequest({ return httpRequest({
url: '/api/lms-financial/school/teacher/import', url: '/api/zy/school/teacher/import',
method: 'post', method: 'post',
headers: { 'Content-Type': 'multipart/form-data' }, headers: { 'Content-Type': 'multipart/form-data' },
timeout: 900000, timeout: 900000,
......
...@@ -3,20 +3,36 @@ ...@@ -3,20 +3,36 @@
<app-list v-bind="tableOptions" ref="list"> <app-list v-bind="tableOptions" ref="list">
<template> <template>
<el-row style="margin-bottom: 20px"> <el-row style="margin-bottom: 20px">
<el-button v-if="btnAdd" type="primary" icon="el-icon-plus" @click="add" size="mini">新建</el-button> <el-button type="primary" icon="el-icon-plus" @click="add" size="mini" v-has="'menu_school_teacher_add'"
<el-button v-if="btnImport" type="primary" icon="el-icon-upload2" style="margin-left: 20px" @click="imports" size="mini" >新建</el-button
>
<el-button
type="primary"
icon="el-icon-upload2"
style="margin-left: 20px"
@click="imports"
size="mini"
v-has="'menu_school_teacher_import'"
>导入</el-button >导入</el-button
> >
</el-row> </el-row>
</template> </template>
<template v-slot:table-x="{ row }"> <template v-slot:table-x="{ row }">
<router-link v-if="btnView" :to="{ path: 'teacher/view', query: { id: row.id } }"> <router-link :to="{ path: 'teacher/view', query: { id: row.id } }" v-has="'menu_school_teacher_view'">
<el-button type="primary" size="mini" plain>查看</el-button> <el-button type="primary" size="mini" plain>查看</el-button>
</router-link> </router-link>
<router-link v-if="btnUpdate" :to="{ path: 'teacher/update', query: { id: row.id } }"> <router-link :to="{ path: 'teacher/update', query: { id: row.id } }" v-has="'menu_school_teacher_update'">
<el-button type="success" style="margin-left: 10px" size="mini" plain>更新</el-button> <el-button type="success" style="margin-left: 10px" size="mini" plain>更新</el-button>
</router-link> </router-link>
<el-button v-if="btnDelete" type="danger" style="margin-left: 10px" size="mini" plain @click="onRemove(row)">删除</el-button> <el-button
type="danger"
style="margin-left: 10px"
size="mini"
plain
@click="onRemove(row)"
v-has="'menu_school_teacher_delete'"
>删除</el-button
>
</template> </template>
</app-list> </app-list>
</app-card> </app-card>
...@@ -31,24 +47,6 @@ export default { ...@@ -31,24 +47,6 @@ export default {
return {} return {}
}, },
computed: { computed: {
permissions() {
return this.$store.state.permissions
},
btnAdd() {
return !!this.permissions.find(item => item.tag === 'teacher-add')
},
btnUpdate() {
return !!this.permissions.find(item => item.tag === 'teacher-update')
},
btnDelete() {
return !!this.permissions.find(item => item.tag === 'teacher-delete')
},
btnView() {
return !!this.permissions.find(item => item.tag === 'teacher-view')
},
btnImport() {
return !!this.permissions.find(item => item.tag === 'teacher-import')
},
// 列表配置 // 列表配置
tableOptions() { tableOptions() {
return { return {
......
import Vue from 'vue' import Vue from 'vue'
import VueRouter from 'vue-router' import VueRouter from 'vue-router'
import beforeEnter from '@/utils/beforeEnter'
Vue.use(VueRouter) Vue.use(VueRouter)
const routes = [{ path: '*', redirect: '/school/class' }] const routes = [{ path: '*', redirect: '/dashboard' }]
const router = new VueRouter({ const router = new VueRouter({
mode: 'history', mode: 'history',
routes routes
}) })
router.beforeEach(beforeEnter)
export default router export default router
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import { getUser, logout, getPermissions } from '@/api/base' import { getUser, logout, getPermissions } from '@/api/base'
import appConfigList from '@/app.config.js'
Vue.use(Vuex) Vue.use(Vuex)
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
user: {}, user: {},
permissions: [] permissions: [],
appConfig: {},
appConfigList
}, },
mutations: { mutations: {
setUser(state, user) { setUser(state, user) {
...@@ -15,6 +18,10 @@ const store = new Vuex.Store({ ...@@ -15,6 +18,10 @@ const store = new Vuex.Store({
}, },
setPermissions(state, permissions) { setPermissions(state, permissions) {
state.permissions = permissions state.permissions = permissions
},
setAppConfig(state, appConfig) {
state.appConfig = appConfig
localStorage.setItem('app_config', JSON.stringify(appConfig))
} }
}, },
actions: { actions: {
...@@ -50,14 +57,34 @@ const store = new Vuex.Store({ ...@@ -50,14 +57,34 @@ const store = new Vuex.Store({
}, },
// 获取所有权限列表 // 获取所有权限列表
getPermissions({ commit }) { getPermissions({ commit }) {
getPermissions({ type: 1 }).then(res => { getPermissions().then(res => {
if (res.data && res.data.items) { if (res.data && res.data.items) {
commit('setPermissions', res.data.items) commit('setPermissions', res.data.items)
} }
}) })
},
// 设置App配置
setAppConfig({ commit }) {
const found = appConfigList.find(item => {
return item.hosts.find(host => location.host.includes(host))
})
// 获取本地App配置
let localAppConfig = localStorage.getItem('app_config')
if (localAppConfig) {
try {
localAppConfig = JSON.parse(localAppConfig)
} catch (error) {
localAppConfig = null
}
}
const appConfig = found || localAppConfig || appConfigList[0]
commit('setAppConfig', appConfig)
} }
} }
}) })
// 设置项目配置
store.dispatch('setAppConfig')
// 获取权限
store.dispatch('getPermissions') store.dispatch('getPermissions')
export default store export default store
...@@ -4,11 +4,12 @@ import { Message } from 'element-ui' ...@@ -4,11 +4,12 @@ import { Message } from 'element-ui'
import router from '@/router' import router from '@/router'
const httpRequest = axios.create({ const httpRequest = axios.create({
baseURL: import.meta.env.VITE_BASE_URL, // baseURL: import.meta.env.VITE_BASE_URL,
timeout: 60000, timeout: 60000,
withCredentials: true, withCredentials: true,
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded',
tenant: 'x1'
} }
}) })
...@@ -65,7 +66,7 @@ httpRequest.interceptors.response.use( ...@@ -65,7 +66,7 @@ httpRequest.interceptors.response.use(
function (error) { function (error) {
if (error.response) { if (error.response) {
const { status, message } = error.response.data const { status, message } = error.response.data
if (status === 401) { if (status === 401 || status === 402) {
router.push('/401') router.push('/401')
} }
// 未登录 // 未登录
......
import store from '@/store'
// 判断是否有权限
export default Vue => {
Vue.directive('has', {
inserted: function (el, binding) {
if (!binding.value) return
const permissions = store.state.permissions || []
const hasPermission = !!permissions.find(item => item.tag === binding.value)
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
}
})
}
...@@ -2,10 +2,16 @@ import fs from 'fs' ...@@ -2,10 +2,16 @@ import fs from 'fs'
import path from 'path' import path from 'path'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2' import { createVuePlugin } from 'vite-plugin-vue2'
import eslint from '@rollup/plugin-eslint' import checker from 'vite-plugin-checker'
export default defineConfig({ export default defineConfig({
base: process.env.BUILD_ENV === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/fd-admin/' : '/', base: process.env.BUILD_ENV === 'prod' ? 'https://webapp-pub.ezijing.com/website/prod/fd-admin/' : '/',
plugins: [eslint({ include: '**/*.+(vue|js|jsx|ts|tsx)' }), createVuePlugin()], plugins: [
checker({
eslint: { lintCommand: 'eslint "./src/**/*.{vue,js,jsx,ts,tsx}"' }
}),
createVuePlugin()
],
server: { server: {
open: true, open: true,
host: 'dev.ezijing.com', host: 'dev.ezijing.com',
...@@ -14,22 +20,16 @@ export default defineConfig({ ...@@ -14,22 +20,16 @@ export default defineConfig({
cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem')) cert: fs.readFileSync(path.join(__dirname, './https/dev.ezijing.com.pem'))
}, },
proxy: { proxy: {
// '/api': 'http://localhost-financial-api.ezijing.com' '/api/zy': {
// '/api': 'https://learn-api.ezijing.com' target: 'https://zy-school-api.ezijing.com',
'/api/lms-financial': {
target: 'http://localhost-financial-api.ezijing.com',
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api\/fd/, '') rewrite: path => path.replace('/api/zy/', '/')
} },
'/api': 'https://learn-api.ezijing.com'
} }
}, },
resolve: { resolve: {
alias: [ alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }]
{
find: '@',
replacement: path.resolve(__dirname, 'src')
}
]
}, },
css: { css: {
// 禁用SASS警告提醒 // 禁用SASS警告提醒
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论