v3.0.6
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { debounce } from '@/utils'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
$_sidebarElm: null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$_initResizeEvent()
|
||||
this.$_initSidebarResizeEvent()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$_destroyResizeEvent()
|
||||
this.$_destroySidebarResizeEvent()
|
||||
},
|
||||
// to fixed bug when cached by keep-alive
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/2116
|
||||
activated () {
|
||||
this.$_initResizeEvent()
|
||||
this.$_initSidebarResizeEvent()
|
||||
},
|
||||
deactivated () {
|
||||
this.$_destroyResizeEvent()
|
||||
this.$_destroySidebarResizeEvent()
|
||||
},
|
||||
methods: {
|
||||
// use $_ for mixins properties
|
||||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
||||
$_resizeHandler () {
|
||||
return debounce(() => {
|
||||
if (this.echartsUserAction) {
|
||||
this.echartsUserAction.resize()
|
||||
}
|
||||
if (this.echartsQuestion) {
|
||||
this.echartsQuestion.resize()
|
||||
}
|
||||
}, 100)()
|
||||
},
|
||||
$_initResizeEvent () {
|
||||
window.addEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
$_destroyResizeEvent () {
|
||||
window.removeEventListener('resize', this.$_resizeHandler)
|
||||
},
|
||||
$_sidebarResizeHandler (e) {
|
||||
if (e.propertyName === 'width') {
|
||||
this.$_resizeHandler()
|
||||
}
|
||||
},
|
||||
$_initSidebarResizeEvent () {
|
||||
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
},
|
||||
$_destroySidebarResizeEvent () {
|
||||
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||
}
|
||||
}
|
||||
}
|
||||
297
source/vue/xzs-admin/src/views/dashboard/index.vue
Normal file
297
source/vue/xzs-admin/src/views/dashboard/index.vue
Normal file
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<div class="dashboard-container">
|
||||
<el-row :gutter="40" class="panel-group">
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
|
||||
<div class="card-panel">
|
||||
<div class="card-panel-icon-wrapper icon-people">
|
||||
<svg-icon icon-class="exam" class-name="card-panel-icon"/>
|
||||
</div>
|
||||
<div class="card-panel-description">
|
||||
<div class="card-panel-text">
|
||||
试卷总数
|
||||
</div>
|
||||
<count-to :start-val="0" :end-val="examPaperCount" :duration="2600" class="card-panel-num" v-loading="loading"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
|
||||
<div class="card-panel" >
|
||||
<div class="card-panel-icon-wrapper icon-message">
|
||||
<svg-icon icon-class="question" class-name="card-panel-icon"/>
|
||||
</div>
|
||||
<div class="card-panel-description">
|
||||
<div class="card-panel-text">
|
||||
题目总数
|
||||
</div>
|
||||
<count-to :start-val="0" :end-val="questionCount" :duration="3000" class="card-panel-num" v-loading="loading"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
|
||||
<div class="card-panel">
|
||||
<div class="card-panel-icon-wrapper icon-shopping">
|
||||
<svg-icon icon-class="doexampaper" class-name="card-panel-icon"/>
|
||||
</div>
|
||||
<div class="card-panel-description">
|
||||
<div class="card-panel-text">
|
||||
答卷总数
|
||||
</div>
|
||||
<count-to :start-val="0" :end-val="doExamPaperCount" :duration="3600" class="card-panel-num" v-loading="loading"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
|
||||
<div class="card-panel">
|
||||
<div class="card-panel-icon-wrapper icon-money">
|
||||
<svg-icon icon-class="doquestion" class-name="card-panel-icon"/>
|
||||
</div>
|
||||
<div class="card-panel-description">
|
||||
<div class="card-panel-text">
|
||||
答题总数
|
||||
</div>
|
||||
<count-to :start-val="0" :end-val="doQuestionCount" :duration="3200" class="card-panel-num" v-loading="loading"/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="echarts-line">
|
||||
<div id="echarts-moth-user" style="width: 100%;height:400px;" v-loading="loading"/>
|
||||
</el-row>
|
||||
<el-row class="echarts-line">
|
||||
<div id="echarts-moth-question" style="width: 100%;height:400px;" v-loading="loading"/>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resize from './components/mixins/resize'
|
||||
import CountTo from 'vue-count-to'
|
||||
import dashboardApi from '@/api/dashboard'
|
||||
export default {
|
||||
mixins: [resize],
|
||||
components: {
|
||||
CountTo
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
examPaperCount: 0,
|
||||
questionCount: 0,
|
||||
doExamPaperCount: 0,
|
||||
doQuestionCount: 0,
|
||||
echartsUserAction: null,
|
||||
echartsQuestion: null,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// eslint-disable-next-line no-undef
|
||||
this.echartsUserAction = echarts.init(document.getElementById('echarts-moth-user'), 'macarons')
|
||||
// eslint-disable-next-line no-undef
|
||||
this.echartsQuestion = echarts.init(document.getElementById('echarts-moth-question'), 'macarons')
|
||||
let _this = this
|
||||
this.loading = true
|
||||
dashboardApi.index().then(re => {
|
||||
let response = re.response
|
||||
_this.examPaperCount = response.examPaperCount
|
||||
_this.questionCount = response.questionCount
|
||||
_this.doExamPaperCount = response.doExamPaperCount
|
||||
_this.doQuestionCount = response.doQuestionCount
|
||||
_this.echartsUserAction.setOption(this.option('用户活跃度', '{b}日{c}度', response.mothDayText, response.mothDayUserActionValue))
|
||||
_this.echartsQuestion.setOption(this.option('题目月数量', '{b}日{c}题', response.mothDayText, response.mothDayDoExamQuestionValue))
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
option (title, formatter, label, vaule) {
|
||||
return {
|
||||
title: {
|
||||
text: title,
|
||||
x: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: formatter
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: label
|
||||
},
|
||||
grid: {
|
||||
left: 10,
|
||||
right: 10,
|
||||
bottom: 20,
|
||||
top: 30,
|
||||
containLabel: true
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [{
|
||||
data: vaule,
|
||||
type: 'line'
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.dashboard-container {
|
||||
padding: 32px;
|
||||
background-color: rgb(240, 242, 245);
|
||||
position: relative;
|
||||
|
||||
.chart-wrapper {
|
||||
background: #fff;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.chart-wrapper {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-editor-container {
|
||||
padding: 32px;
|
||||
background-color: rgb(240, 242, 245);
|
||||
position: relative;
|
||||
|
||||
.github-corner {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
border: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
background: #fff;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.chart-wrapper {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-group {
|
||||
margin-top: 18px;
|
||||
|
||||
.card-panel-col {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.card-panel {
|
||||
height: 108px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: #666;
|
||||
background: #fff;
|
||||
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
|
||||
border-color: rgba(0, 0, 0, .05);
|
||||
|
||||
&:hover {
|
||||
.card-panel-icon-wrapper {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.icon-people {
|
||||
background: #40c9c6;
|
||||
}
|
||||
|
||||
.icon-message {
|
||||
background: #36a3f7;
|
||||
}
|
||||
|
||||
.icon-money {
|
||||
background: #f4516c;
|
||||
}
|
||||
|
||||
.icon-shopping {
|
||||
background: #34bfa3
|
||||
}
|
||||
}
|
||||
|
||||
.icon-people {
|
||||
color: #40c9c6;
|
||||
}
|
||||
|
||||
.icon-message {
|
||||
color: #36a3f7;
|
||||
}
|
||||
|
||||
.icon-money {
|
||||
color: #f4516c;
|
||||
}
|
||||
|
||||
.icon-shopping {
|
||||
color: #34bfa3
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
float: left;
|
||||
margin: 14px 0 0 14px;
|
||||
padding: 16px;
|
||||
transition: all 0.38s ease-out;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.card-panel-icon {
|
||||
float: left;
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
.card-panel-description {
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin: 26px;
|
||||
margin-left: 0px;
|
||||
|
||||
.card-panel-text {
|
||||
line-height: 18px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.card-panel-num {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.card-panel-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
float: none !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
display: block;
|
||||
margin: 14px auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.echarts-line{
|
||||
background:#fff;
|
||||
padding:16px 16px 0;
|
||||
margin-bottom:32px;
|
||||
}
|
||||
</style>
|
||||
81
source/vue/xzs-admin/src/views/education/subject/edit.vue
Normal file
81
source/vue/xzs-admin/src/views/education/subject/edit.vue
Normal file
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading">
|
||||
<el-form-item label="学科:" required>
|
||||
<el-input v-model="form.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级:" required>
|
||||
<el-select v-model="form.level" placeholder="年级">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import subjectApi from '@/api/subject'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
name: '',
|
||||
level: 1,
|
||||
levelName: ''
|
||||
},
|
||||
formLoading: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
subjectApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.formLoading = true
|
||||
this.form.levelName = this.enumFormat(this.levelEnum, this.form.level)
|
||||
subjectApi.edit(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/education/subject/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
_this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
levelEnum: state => state.user.levelEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
93
source/vue/xzs-admin/src/views/education/subject/list.vue
Normal file
93
source/vue/xzs-admin/src/views/education/subject/list.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="年级:">
|
||||
<el-select v-model="queryParam.level" placeholder="年级" clearable="">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<router-link :to="{path:'/education/subject/edit'}" class="link-left">
|
||||
<el-button type="primary">添加</el-button>
|
||||
</router-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" />
|
||||
<el-table-column prop="name" label="学科"/>
|
||||
<el-table-column prop="levelName" label="年级" />
|
||||
<el-table-column width="220px" label="操作" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<router-link :to="{path:'/education/subject/edit', query:{id:row.id}}" class="link-left">
|
||||
<el-button size="mini">编辑</el-button>
|
||||
</router-link>
|
||||
<el-button size="mini" type="danger" @click="delSubject(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import subjectApi from '@/api/subject'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
level: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
subjectApi.pageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
delSubject (row) {
|
||||
let _this = this
|
||||
subjectApi.deleteSubject(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
levelEnum: state => state.user.levelEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
99
source/vue/xzs-admin/src/views/error-page/401.vue
Normal file
99
source/vue/xzs-admin/src/views/error-page/401.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="errPage-container">
|
||||
<el-button icon="arrow-left" class="pan-back-btn" @click="back">
|
||||
返回
|
||||
</el-button>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<h1 class="text-jumbo text-ginormous">
|
||||
Oops!
|
||||
</h1>
|
||||
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面
|
||||
<h2>你没有权限去该页面</h2>
|
||||
<h6>如有不满请联系你领导</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li>或者你可以去:</li>
|
||||
<li class="link-type">
|
||||
<router-link to="/dashboard">
|
||||
回首页
|
||||
</router-link>
|
||||
</li>
|
||||
<li class="link-type">
|
||||
<a href="https://www.taobao.com/">随便看看</a>
|
||||
</li>
|
||||
<li><a href="#" @click.prevent="dialogVisible=true">点我看图</a></li>
|
||||
</ul>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog :visible.sync="dialogVisible" title="随便看">
|
||||
<img :src="ewizardClap" class="pan-img">
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import errGif from '@/assets/401_images/401.gif'
|
||||
|
||||
export default {
|
||||
name: 'Page401',
|
||||
data () {
|
||||
return {
|
||||
errGif: errGif + '?' + +new Date(),
|
||||
ewizardClap: 'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
|
||||
dialogVisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back () {
|
||||
if (this.$route.query.noGoBack) {
|
||||
this.$router.push({ path: '/dashboard' })
|
||||
} else {
|
||||
this.$router.go(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.errPage-container {
|
||||
width: 800px;
|
||||
max-width: 100%;
|
||||
margin: 100px auto;
|
||||
.pan-back-btn {
|
||||
background: #008489;
|
||||
color: #fff;
|
||||
border: none!important;
|
||||
}
|
||||
.pan-gif {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
.pan-img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
.text-jumbo {
|
||||
font-size: 60px;
|
||||
font-weight: 700;
|
||||
color: #484848;
|
||||
}
|
||||
.list-unstyled {
|
||||
font-size: 14px;
|
||||
li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
a {
|
||||
color: #008489;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
225
source/vue/xzs-admin/src/views/error-page/404.vue
Normal file
225
source/vue/xzs-admin/src/views/error-page/404.vue
Normal file
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404">
|
||||
<div class="pic-404">
|
||||
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
|
||||
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops">OOPS!</div>
|
||||
<div class="bullshit__headline">{{ message }}</div>
|
||||
<div class="bullshit__info">请检查你的访问地址是否正确, 或点击下面按钮返回主页.</div>
|
||||
<a href="" class="bullshit__return-home">返回主页</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'Page404',
|
||||
computed: {
|
||||
message () {
|
||||
return '页面未找到...'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wscn-http404-container{
|
||||
transform: translate(-50%,-50%);
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
}
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
padding: 0 50px;
|
||||
overflow: hidden;
|
||||
.pic-404 {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 600px;
|
||||
overflow: hidden;
|
||||
&__parent {
|
||||
width: 100%;
|
||||
}
|
||||
&__child {
|
||||
position: absolute;
|
||||
&.left {
|
||||
width: 80px;
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
animation-name: cloudLeft;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
&.mid {
|
||||
width: 46px;
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
animation-name: cloudMid;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
&.right {
|
||||
width: 62px;
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
animation-name: cloudRight;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
@keyframes cloudLeft {
|
||||
0% {
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 33px;
|
||||
left: 188px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 81px;
|
||||
left: 92px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 97px;
|
||||
left: 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudMid {
|
||||
0% {
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 40px;
|
||||
left: 360px;
|
||||
opacity: 1;
|
||||
}
|
||||
70% {
|
||||
top: 130px;
|
||||
left: 180px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 160px;
|
||||
left: 120px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudRight {
|
||||
0% {
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 120px;
|
||||
left: 460px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 180px;
|
||||
left: 340px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 200px;
|
||||
left: 300px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bullshit {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 300px;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
&__oops {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 40px;
|
||||
color: #1482f0;
|
||||
opacity: 0;
|
||||
margin-bottom: 20px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__headline {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
margin-bottom: 10px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.1s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__info {
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
color: grey;
|
||||
opacity: 0;
|
||||
margin-bottom: 30px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__return-home {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 110px;
|
||||
height: 36px;
|
||||
background: #1482f0;
|
||||
border-radius: 100px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
opacity: 0;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
266
source/vue/xzs-admin/src/views/exam/paper/edit.vue
Normal file
266
source/vue/xzs-admin/src/views/exam/paper/edit.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="level" required>
|
||||
<el-select v-model="form.level" placeholder="年级" @change="levelChange">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" prop="subjectId" required>
|
||||
<el-select v-model="form.subjectId" placeholder="学科">
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id"
|
||||
:label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="试卷类型:" prop="paperType" required>
|
||||
<el-select v-model="form.paperType" placeholder="试卷类型">
|
||||
<el-option v-for="item in paperTypeEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间限制:" required v-show="form.paperType===4">
|
||||
<el-date-picker v-model="form.limitDateTime" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="试卷名称:" prop="name" required>
|
||||
<el-input v-model="form.name"/>
|
||||
</el-form-item>
|
||||
<el-form-item :key="index" :label="'标题'+(index+1)+':'" required v-for="(titleItem,index) in form.titleItems">
|
||||
<el-input v-model="titleItem.name" style="width: 80%"/>
|
||||
<el-button type="text" class="link-left" style="margin-left: 20px" size="mini" @click="addQuestion(titleItem)">
|
||||
添加题目
|
||||
</el-button>
|
||||
<el-button type="text" class="link-left" size="mini" @click="form.titleItems.splice(index,1)">删除</el-button>
|
||||
<el-card class="exampaper-item-box" v-if="titleItem.questionItems.length!==0">
|
||||
<el-form-item :key="questionIndex" :label="'题目'+(questionIndex+1)+':'"
|
||||
v-for="(questionItem,questionIndex) in titleItem.questionItems" style="margin-bottom: 15px">
|
||||
<el-row>
|
||||
<el-col :span="23">
|
||||
<QuestionShow :qType="questionItem.questionType" :question="questionItem"/>
|
||||
</el-col>
|
||||
<el-col :span="1">
|
||||
<el-button type="text" size="mini" @click="titleItem.questionItems.splice(questionIndex,1)">删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
<el-form-item label="建议时长:" prop="suggestTime" required>
|
||||
<el-input v-model="form.suggestTime" placeholder="分钟"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="addTitle">添加标题</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog :visible.sync="questionPage.showDialog" width="70%">
|
||||
<el-form :model="questionPage.queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="ID:">
|
||||
<el-input v-model="questionPage.queryParam.id" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="题型:">
|
||||
<el-select v-model="questionPage.queryParam.questionType" clearable>
|
||||
<el-option v-for="item in questionTypeEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="queryForm">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="questionPage.listLoading" :data="questionPage.tableData"
|
||||
@selection-change="handleSelectionChange" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column type="selection" width="35"></el-table-column>
|
||||
<el-table-column prop="id" label="Id" width="60px"/>
|
||||
<el-table-column prop="questionType" label="题型" :formatter="questionTypeFormatter" width="70px"/>
|
||||
<el-table-column prop="shortTitle" label="题干" show-overflow-tooltip/>
|
||||
</el-table>
|
||||
<pagination v-show="questionPage.total>0" :total="questionPage.total"
|
||||
:page.sync="questionPage.queryParam.pageIndex" :limit.sync="questionPage.queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="questionPage.showDialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmQuestionSelect">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import QuestionShow from '../question/components/Show'
|
||||
import examPaperApi from '@/api/examPaper'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: { Pagination, QuestionShow },
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
level: null,
|
||||
subjectId: null,
|
||||
paperType: 1,
|
||||
limitDateTime: [],
|
||||
name: '',
|
||||
suggestTime: null,
|
||||
titleItems: []
|
||||
},
|
||||
subjectFilter: null,
|
||||
formLoading: false,
|
||||
rules: {
|
||||
level: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
],
|
||||
subjectId: [
|
||||
{ required: true, message: '请选择学科', trigger: 'change' }
|
||||
],
|
||||
paperType: [
|
||||
{ required: true, message: '请选择试卷类型', trigger: 'change' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请输入试卷名称', trigger: 'blur' }
|
||||
],
|
||||
suggestTime: [
|
||||
{ required: true, message: '请输入建议时长', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
questionPage: {
|
||||
multipleSelection: [],
|
||||
showDialog: false,
|
||||
queryParam: {
|
||||
id: null,
|
||||
questionType: null,
|
||||
subjectId: 1,
|
||||
pageIndex: 1,
|
||||
pageSize: 5
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
},
|
||||
currentTitleItem: null
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.subjectFilter = _this.subjects
|
||||
})
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
examPaperApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
examPaperApi.edit(this.form).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/exam/paper/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
addTitle () {
|
||||
this.form.titleItems.push({
|
||||
name: '',
|
||||
questionItems: []
|
||||
})
|
||||
},
|
||||
addQuestion (titleItem) {
|
||||
this.currentTitleItem = titleItem
|
||||
this.questionPage.showDialog = true
|
||||
this.search()
|
||||
},
|
||||
removeTitleItem (titleItem) {
|
||||
this.form.titleItems.remove(titleItem)
|
||||
},
|
||||
removeQuestion (titleItem, questionItem) {
|
||||
titleItem.questionItems.remove(questionItem)
|
||||
},
|
||||
queryForm () {
|
||||
this.questionPage.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
confirmQuestionSelect () {
|
||||
let _this = this
|
||||
this.questionPage.multipleSelection.forEach(q => {
|
||||
questionApi.select(q.id).then(re => {
|
||||
_this.currentTitleItem.questionItems.push(re.response)
|
||||
})
|
||||
})
|
||||
this.questionPage.showDialog = false
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.form.level)
|
||||
},
|
||||
search () {
|
||||
this.questionPage.queryParam.subjectId = this.form.subjectId
|
||||
this.questionPage.listLoading = true
|
||||
questionApi.pageList(this.questionPage.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.questionPage.tableData = re.list
|
||||
this.questionPage.total = re.total
|
||||
this.questionPage.queryParam.pageIndex = re.pageNum
|
||||
this.questionPage.listLoading = false
|
||||
})
|
||||
},
|
||||
handleSelectionChange (val) {
|
||||
this.questionPage.multipleSelection = val
|
||||
},
|
||||
questionTypeFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.questionTypeEnum, cellValue)
|
||||
},
|
||||
subjectFormatter (row, column, cellValue, index) {
|
||||
return this.subjectEnumFormat(cellValue)
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
paperTypeEnum: state => state.exam.examPaper.paperTypeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.exampaper-item-box {
|
||||
.q-title {
|
||||
margin: 0px 5px 0px 5px;
|
||||
}
|
||||
.q-item-content {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
111
source/vue/xzs-admin/src/views/exam/paper/list.vue
Normal file
111
source/vue/xzs-admin/src/views/exam/paper/list.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="题目ID:">
|
||||
<el-input v-model="queryParam.id" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级:">
|
||||
<el-select v-model="queryParam.level" placeholder="年级" @change="levelChange" clearable>
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" >
|
||||
<el-select v-model="queryParam.subjectId" clearable>
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<router-link :to="{path:'/exam/paper/edit'}" class="link-left">
|
||||
<el-button type="primary">添加</el-button>
|
||||
</router-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" width="90px"/>
|
||||
<el-table-column prop="subjectId" label="学科" :formatter="subjectFormatter" width="120px" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="操作" align="center" width="160px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="$router.push({path:'/exam/paper/edit',query:{id:row.id}})" >编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="deletePaper(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import examPaperApi from '@/api/examPaper'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
id: null,
|
||||
level: null,
|
||||
subjectId: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
subjectFilter: null,
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initSubject()
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
search () {
|
||||
this.listLoading = true
|
||||
examPaperApi.pageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
deletePaper (row) {
|
||||
let _this = this
|
||||
examPaperApi.deletePaper(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
levelChange () {
|
||||
this.queryParam.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.queryParam.level)
|
||||
},
|
||||
subjectFormatter (row, column, cellValue, index) {
|
||||
return this.subjectEnumFormat(cellValue)
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapGetters('exam', ['subjectEnumFormat']),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div style="line-height:1.8">
|
||||
<div v-if="qType==1" v-loading="qLoading">
|
||||
<div class="q-title" v-html="question.title"/>
|
||||
<div class="q-content">
|
||||
<span :key="item.id" v-for="item in question.items" class="q-item-contain">
|
||||
<span class="q-item-prefix">{{item.prefix}}</span>
|
||||
<span v-html="item.content" class="q-item-content"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="qType==2" v-loading="qLoading">
|
||||
<div class="q-title" v-html="question.title"/>
|
||||
<div class="q-content">
|
||||
<span :key="item.id" v-for="item in question.items" class="q-item-contain">
|
||||
<span class="q-item-prefix">{{item.prefix}}</span>
|
||||
<span v-html="item.content" class="q-item-content"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="qType==3" v-loading="qLoading">
|
||||
<div class="q-title" v-html="question.title" style="display: inline;margin-right: 10px"/>
|
||||
<span>(</span>
|
||||
<span :key="item.id" v-for="item in question.items">
|
||||
<span v-html="item.content" class="q-item-content"></span>
|
||||
</span>
|
||||
<span>)</span>
|
||||
</div>
|
||||
<div v-else-if="qType==4" v-loading="qLoading">
|
||||
<div class="q-title" v-html="question.title"/>
|
||||
</div>
|
||||
<div v-else-if="qType==5" v-loading="qLoading">
|
||||
<div class="q-title" v-html="question.title"/>
|
||||
</div>
|
||||
<div v-else>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'QuestionShow',
|
||||
props: {
|
||||
question: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
qLoading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
qType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="gradeLevel" required>
|
||||
<el-select v-model="form.gradeLevel" placeholder="年级" @change="levelChange">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" prop="subjectId" required>
|
||||
<el-select v-model="form.subjectId" placeholder="学科" >
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题干:" prop="title" required>
|
||||
<el-input v-model="form.title" @focus="inputClick(form,'title')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="填空答案:" required>
|
||||
<el-form-item :label="item.prefix" :key="item.prefix" v-for="item in form.items" label-width="50px" class="question-item-label">
|
||||
<el-input v-model="item.content" @focus="inputClick(item,'content')" class="question-item-content-input" style="width: 80%"/>
|
||||
<span class="question-item-span">分数:</span><el-input-number v-model="item.score" :precision="1" :step="1" :max="100" ></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="解析:" prop="analyze" required>
|
||||
<el-input v-model="form.analyze" @focus="inputClick(form,'analyze')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分数:" prop="score" required>
|
||||
<el-input-number v-model="form.score" :precision="1" :step="1" :max="100"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="难度:" required>
|
||||
<el-rate v-model="form.difficult" class="question-item-rate"></el-rate>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="showQuestion">预览</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog :visible.sync="richEditor.dialogVisible" append-to-body :close-on-click-modal="false" style="width: 100%;height: 100%" :show-close="false" center>
|
||||
<Ueditor @ready="editorReady"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="editorConfirm">确 定</el-button>
|
||||
<el-button @click="richEditor.dialogVisible = false">取 消</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="questionShow.dialog" style="width: 100%;height: 100%">
|
||||
<QuestionShow :qType="questionShow.qType" :question="questionShow.question" :qLoading="questionShow.loading"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuestionShow from '../components/Show'
|
||||
import Ueditor from '@/components/Ueditor'
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ueditor, QuestionShow
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
questionType: 4,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
},
|
||||
subjectFilter: null,
|
||||
formLoading: false,
|
||||
rules: {
|
||||
gradeLevel: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
],
|
||||
subjectId: [
|
||||
{ required: true, message: '请选择学科', trigger: 'change' }
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: '请输入题干', trigger: 'blur' }
|
||||
],
|
||||
analyze: [
|
||||
{ required: true, message: '请输入解析', trigger: 'blur' }
|
||||
],
|
||||
score: [
|
||||
{ required: true, message: '请输入分数', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
richEditor: {
|
||||
dialogVisible: false,
|
||||
object: null,
|
||||
parameterName: '',
|
||||
instance: null
|
||||
},
|
||||
questionShow: {
|
||||
qType: 0,
|
||||
dialog: false,
|
||||
question: null,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.subjectFilter = _this.subjects
|
||||
})
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
questionApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editorReady (instance) {
|
||||
this.richEditor.instance = instance
|
||||
let currentContent = this.richEditor.object[this.richEditor.parameterName]
|
||||
this.richEditor.instance.setContent(currentContent)
|
||||
// 光标定位到Ueditor
|
||||
this.richEditor.instance.focus(true)
|
||||
},
|
||||
inputClick (object, parameterName) {
|
||||
this.richEditor.object = object
|
||||
this.richEditor.parameterName = parameterName
|
||||
this.richEditor.dialogVisible = true
|
||||
},
|
||||
editorConfirm () {
|
||||
let content = this.richEditor.instance.getContent()
|
||||
if (this.richEditor.parameterName === 'title') { // 题干的正确答案重置
|
||||
if (this.questionItemReset(content)) {
|
||||
this.richEditor.object[this.richEditor.parameterName] = content
|
||||
this.richEditor.dialogVisible = false
|
||||
} else {
|
||||
|
||||
}
|
||||
} else {
|
||||
this.richEditor.object[this.richEditor.parameterName] = content
|
||||
this.richEditor.dialogVisible = false
|
||||
}
|
||||
},
|
||||
questionItemReset (content) {
|
||||
let spanRegex = new RegExp('<span class="gapfilling-span (.*?)">(.*?)<\\/span>', 'g')
|
||||
let _this = this
|
||||
let newFormItem = []
|
||||
let gapfillingItems = content.match(spanRegex)
|
||||
if (gapfillingItems === null) {
|
||||
this.$message.error('请插入填空')
|
||||
return false
|
||||
}
|
||||
gapfillingItems.forEach(function (span, index) {
|
||||
let pairRegex = /<span class="gapfilling-span (.*?)">(.*?)<\/span>/
|
||||
pairRegex.test(span)
|
||||
newFormItem.push({ id: null, prefix: RegExp.$2, content: '', score: '0' })
|
||||
})
|
||||
|
||||
newFormItem.forEach(function (item) {
|
||||
_this.form.items.some((oldItem, index) => {
|
||||
if (oldItem.itemUuid === item.itemUuid) {
|
||||
item.content = oldItem.content
|
||||
item.id = oldItem.id
|
||||
item.score = oldItem.score
|
||||
return true
|
||||
}
|
||||
})
|
||||
})
|
||||
_this.form.items = newFormItem
|
||||
return true
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
questionApi.edit(this.form).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/exam/question/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.form.gradeLevel)
|
||||
},
|
||||
showQuestion () {
|
||||
this.questionShow.dialog = true
|
||||
this.questionShow.qType = this.form.questionType
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,212 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="gradeLevel" required>
|
||||
<el-select v-model="form.gradeLevel" placeholder="年级" @change="levelChange">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" prop="subjectId" required>
|
||||
<el-select v-model="form.subjectId" placeholder="学科" >
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题干:" prop="title" required>
|
||||
<el-input v-model="form.title" @focus="inputClick(form,'title')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="选项:" required>
|
||||
<el-form-item :label="item.prefix" :key="item.prefix" v-for="(item,index) in form.items" label-width="50px" class="question-item-label">
|
||||
<el-input v-model="item.prefix" style="width:50px;" />
|
||||
<el-input v-model="item.content" @focus="inputClick(item,'content')" class="question-item-content-input"/>
|
||||
<el-button type="danger" size="mini" class="question-item-remove" icon="el-icon-delete" @click="questionItemRemove(index)"></el-button>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="解析:" prop="analyze" required>
|
||||
<el-input v-model="form.analyze" @focus="inputClick(form,'analyze')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分数:" prop="score" required>
|
||||
<el-input-number v-model="form.score" :precision="1" :step="1" :max="100"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="难度:" required>
|
||||
<el-rate v-model="form.difficult" class="question-item-rate"></el-rate>
|
||||
</el-form-item>
|
||||
<el-form-item label="正确答案:" prop="correctArray" required>
|
||||
<el-checkbox-group v-model="form.correctArray">
|
||||
<el-checkbox v-for="item in form.items" :label="item.prefix" :key="item.prefix">{{item.prefix}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="questionItemAdd">添加选项</el-button>
|
||||
<el-button type="success" @click="showQuestion">预览</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog :visible.sync="richEditor.dialogVisible" append-to-body :close-on-click-modal="false" style="width: 100%;height: 100%" :show-close="false" center>
|
||||
<Ueditor @ready="editorReady"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="editorConfirm">确 定</el-button>
|
||||
<el-button @click="richEditor.dialogVisible = false">取 消</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="questionShow.dialog" style="width: 100%;height: 100%">
|
||||
<QuestionShow :qType="questionShow.qType" :question="questionShow.question" :qLoading="questionShow.loading"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuestionShow from '../components/Show'
|
||||
import Ueditor from '@/components/Ueditor'
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ueditor, QuestionShow
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
questionType: 2,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
{ id: null, prefix: 'A', content: '' },
|
||||
{ id: null, prefix: 'B', content: '' },
|
||||
{ id: null, prefix: 'C', content: '' },
|
||||
{ id: null, prefix: 'D', content: '' }
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
correctArray: [],
|
||||
score: '',
|
||||
difficult: 0
|
||||
},
|
||||
subjectFilter: null,
|
||||
formLoading: false,
|
||||
rules: {
|
||||
gradeLevel: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
],
|
||||
subjectId: [
|
||||
{ required: true, message: '请选择学科', trigger: 'change' }
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: '请输入题干', trigger: 'blur' }
|
||||
],
|
||||
analyze: [
|
||||
{ required: true, message: '请输入解析', trigger: 'blur' }
|
||||
],
|
||||
score: [
|
||||
{ required: true, message: '请输入分数', trigger: 'blur' }
|
||||
],
|
||||
correctArray: [
|
||||
{ required: true, message: '请选择正确答案', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
richEditor: {
|
||||
dialogVisible: false,
|
||||
object: null,
|
||||
parameterName: '',
|
||||
instance: null
|
||||
},
|
||||
questionShow: {
|
||||
qType: 0,
|
||||
dialog: false,
|
||||
question: null,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.subjectFilter = _this.subjects
|
||||
})
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
questionApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editorReady (instance) {
|
||||
this.richEditor.instance = instance
|
||||
let currentContent = this.richEditor.object[this.richEditor.parameterName]
|
||||
this.richEditor.instance.setContent(currentContent)
|
||||
// 光标定位到Ueditor
|
||||
this.richEditor.instance.focus(true)
|
||||
},
|
||||
inputClick (object, parameterName) {
|
||||
this.richEditor.object = object
|
||||
this.richEditor.parameterName = parameterName
|
||||
this.richEditor.dialogVisible = true
|
||||
},
|
||||
editorConfirm () {
|
||||
let content = this.richEditor.instance.getContent()
|
||||
this.richEditor.object[this.richEditor.parameterName] = content
|
||||
this.richEditor.dialogVisible = false
|
||||
},
|
||||
questionItemRemove (index) {
|
||||
this.form.items.splice(index, 1)
|
||||
},
|
||||
questionItemAdd () {
|
||||
let items = this.form.items
|
||||
let last = items[items.length - 1]
|
||||
let newLastPrefix = String.fromCharCode(last.prefix.charCodeAt() + 1)
|
||||
items.push({ id: null, prefix: newLastPrefix, content: '' })
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
questionApi.edit(this.form).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/exam/question/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.form.gradeLevel)
|
||||
},
|
||||
showQuestion () {
|
||||
this.questionShow.dialog = true
|
||||
this.questionShow.qType = this.form.questionType
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="gradeLevel" required>
|
||||
<el-select v-model="form.gradeLevel" placeholder="年级" @change="levelChange">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" prop="subjectId" required>
|
||||
<el-select v-model="form.subjectId" placeholder="学科" >
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题干:" prop="title" required>
|
||||
<el-input v-model="form.title" @focus="inputClick(form,'title')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="答案:" prop="correct" required>
|
||||
<el-input v-model="form.correct" @focus="inputClick(form,'correct')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="解析:" prop="analyze" required>
|
||||
<el-input v-model="form.analyze" @focus="inputClick(form,'analyze')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分数:" prop="score" required>
|
||||
<el-input-number v-model="form.score" :precision="1" :step="1" :max="100"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="难度:" required>
|
||||
<el-rate v-model="form.difficult" class="question-item-rate"></el-rate>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="showQuestion">预览</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog :visible.sync="richEditor.dialogVisible" append-to-body :close-on-click-modal="false" style="width: 100%;height: 100%" :show-close="false" center>
|
||||
<Ueditor @ready="editorReady"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="editorConfirm">确 定</el-button>
|
||||
<el-button @click="richEditor.dialogVisible = false">取 消</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="questionShow.dialog" style="width: 100%;height: 100%">
|
||||
<QuestionShow :qType="questionShow.qType" :question="questionShow.question" :qLoading="questionShow.loading"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuestionShow from '../components/Show'
|
||||
import Ueditor from '@/components/Ueditor'
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ueditor, QuestionShow
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
questionType: 5,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
},
|
||||
subjectFilter: null,
|
||||
formLoading: false,
|
||||
rules: {
|
||||
gradeLevel: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
],
|
||||
subjectId: [
|
||||
{ required: true, message: '请选择学科', trigger: 'change' }
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: '请输入题干', trigger: 'blur' }
|
||||
],
|
||||
correct: [
|
||||
{ required: true, message: '请输入答案', trigger: 'blur' }
|
||||
],
|
||||
analyze: [
|
||||
{ required: true, message: '请输入解析', trigger: 'blur' }
|
||||
],
|
||||
score: [
|
||||
{ required: true, message: '请输入分数', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
richEditor: {
|
||||
dialogVisible: false,
|
||||
object: null,
|
||||
parameterName: '',
|
||||
instance: null
|
||||
},
|
||||
questionShow: {
|
||||
qType: 0,
|
||||
dialog: false,
|
||||
question: null,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.subjectFilter = _this.subjects
|
||||
})
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
questionApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editorReady (instance) {
|
||||
this.richEditor.instance = instance
|
||||
let currentContent = this.richEditor.object[this.richEditor.parameterName]
|
||||
this.richEditor.instance.setContent(currentContent)
|
||||
// 光标定位到Ueditor
|
||||
this.richEditor.instance.focus(true)
|
||||
},
|
||||
inputClick (object, parameterName) {
|
||||
this.richEditor.object = object
|
||||
this.richEditor.parameterName = parameterName
|
||||
this.richEditor.dialogVisible = true
|
||||
},
|
||||
editorConfirm () {
|
||||
let content = this.richEditor.instance.getContent()
|
||||
this.richEditor.object[this.richEditor.parameterName] = content
|
||||
this.richEditor.dialogVisible = false
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
questionApi.edit(this.form).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/exam/question/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.form.gradeLevel)
|
||||
},
|
||||
showQuestion () {
|
||||
this.questionShow.dialog = true
|
||||
this.questionShow.qType = this.form.questionType
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="gradeLevel" required>
|
||||
<el-select v-model="form.gradeLevel" placeholder="年级" @change="levelChange" clearable>
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" prop="subjectId" required>
|
||||
<el-select v-model="form.subjectId" placeholder="学科" >
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题干:" prop="title" required>
|
||||
<el-input v-model="form.title" @focus="inputClick(form,'title')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="选项:" required>
|
||||
<el-form-item :label="item.prefix" :key="item.prefix" v-for="(item,index) in form.items" label-width="50px" class="question-item-label">
|
||||
<el-input v-model="item.prefix" style="width:50px;" />
|
||||
<el-input v-model="item.content" @focus="inputClick(item,'content')" class="question-item-content-input"/>
|
||||
<el-button type="danger" size="mini" class="question-item-remove" icon="el-icon-delete" @click="questionItemRemove(index)"></el-button>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="解析:" prop="analyze" required>
|
||||
<el-input v-model="form.analyze" @focus="inputClick(form,'analyze')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分数:" prop="score" required>
|
||||
<el-input-number v-model="form.score" :precision="1" :step="1" :max="100"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="难度:" required>
|
||||
<el-rate v-model="form.difficult" class="question-item-rate"></el-rate>
|
||||
</el-form-item>
|
||||
<el-form-item label="正确答案:" prop="correct" required>
|
||||
<el-radio-group v-model="form.correct">
|
||||
<el-radio v-for="item in form.items" :key="item.prefix" :label="item.prefix">{{item.prefix}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="questionItemAdd">添加选项</el-button>
|
||||
<el-button type="success" @click="showQuestion">预览</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog :visible.sync="richEditor.dialogVisible" append-to-body :close-on-click-modal="false" style="width: 100%;height: 100%" :show-close="false" center>
|
||||
<Ueditor @ready="editorReady"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="editorConfirm">确 定</el-button>
|
||||
<el-button @click="richEditor.dialogVisible = false">取 消</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="questionShow.dialog" style="width: 100%;height: 100%">
|
||||
<QuestionShow :qType="questionShow.qType" :question="questionShow.question" :qLoading="questionShow.loading"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuestionShow from '../components/Show'
|
||||
import Ueditor from '@/components/Ueditor'
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ueditor, QuestionShow
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
questionType: 1,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
{ prefix: 'A', content: '' },
|
||||
{ prefix: 'B', content: '' },
|
||||
{ prefix: 'C', content: '' },
|
||||
{ prefix: 'D', content: '' }
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
},
|
||||
subjectFilter: null,
|
||||
formLoading: false,
|
||||
rules: {
|
||||
gradeLevel: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
],
|
||||
subjectId: [
|
||||
{ required: true, message: '请选择学科', trigger: 'change' }
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: '请输入题干', trigger: 'blur' }
|
||||
],
|
||||
analyze: [
|
||||
{ required: true, message: '请输入解析', trigger: 'blur' }
|
||||
],
|
||||
score: [
|
||||
{ required: true, message: '请输入分数', trigger: 'blur' }
|
||||
],
|
||||
correct: [
|
||||
{ required: true, message: '请选择正确答案', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
richEditor: {
|
||||
dialogVisible: false,
|
||||
object: null,
|
||||
parameterName: '',
|
||||
instance: null
|
||||
},
|
||||
questionShow: {
|
||||
qType: 0,
|
||||
dialog: false,
|
||||
question: null,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.subjectFilter = _this.subjects
|
||||
})
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
questionApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editorReady (instance) {
|
||||
this.richEditor.instance = instance
|
||||
let currentContent = this.richEditor.object[this.richEditor.parameterName]
|
||||
this.richEditor.instance.setContent(currentContent)
|
||||
// 光标定位到Ueditor
|
||||
this.richEditor.instance.focus(true)
|
||||
},
|
||||
inputClick (object, parameterName) {
|
||||
this.richEditor.object = object
|
||||
this.richEditor.parameterName = parameterName
|
||||
this.richEditor.dialogVisible = true
|
||||
},
|
||||
editorConfirm () {
|
||||
let content = this.richEditor.instance.getContent()
|
||||
this.richEditor.object[this.richEditor.parameterName] = content
|
||||
this.richEditor.dialogVisible = false
|
||||
},
|
||||
questionItemRemove (index) {
|
||||
this.form.items.splice(index, 1)
|
||||
},
|
||||
questionItemAdd () {
|
||||
let items = this.form.items
|
||||
let last = items[items.length - 1]
|
||||
let newLastPrefix = String.fromCharCode(last.prefix.charCodeAt() + 1)
|
||||
items.push({ id: null, prefix: newLastPrefix, content: '' })
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
questionApi.edit(this.form).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/exam/question/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.form.gradeLevel)
|
||||
},
|
||||
showQuestion () {
|
||||
this.questionShow.dialog = true
|
||||
this.questionShow.qType = this.form.questionType
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
198
source/vue/xzs-admin/src/views/exam/question/edit/true-false.vue
Normal file
198
source/vue/xzs-admin/src/views/exam/question/edit/true-false.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="gradeLevel" required>
|
||||
<el-select v-model="form.gradeLevel" placeholder="年级" @change="levelChange">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:" prop="subjectId" required>
|
||||
<el-select v-model="form.subjectId" placeholder="学科" >
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题干:" prop="title" required>
|
||||
<el-input v-model="form.title" @focus="inputClick(form,'title')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="选项:" required>
|
||||
<el-form-item :label="item.prefix" :key="item.prefix" v-for="(item) in form.items" label-width="50px" class="question-item-label">
|
||||
<el-input v-model="item.prefix" style="width:50px;" />
|
||||
<el-input v-model="item.content" @focus="inputClick(item,'content')" class="question-item-content-input"/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="解析:" prop="analyze" required>
|
||||
<el-input v-model="form.analyze" @focus="inputClick(form,'analyze')" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分数:" prop="score" required>
|
||||
<el-input-number v-model="form.score" :precision="1" :step="1" :max="100"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="难度:" required>
|
||||
<el-rate v-model="form.difficult" class="question-item-rate"></el-rate>
|
||||
</el-form-item>
|
||||
<el-form-item label="正确答案:" prop="correct" required>
|
||||
<el-radio-group v-model="form.correct">
|
||||
<el-radio v-for="item in form.items" :key="item.prefix" :label="item.prefix">{{item.prefix}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="showQuestion">预览</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog :visible.sync="richEditor.dialogVisible" append-to-body :close-on-click-modal="false" style="width: 100%;height: 100%" :show-close="false" center>
|
||||
<Ueditor @ready="editorReady"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="editorConfirm">确 定</el-button>
|
||||
<el-button @click="richEditor.dialogVisible = false">取 消</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="questionShow.dialog" style="width: 100%;height: 100%">
|
||||
<QuestionShow :qType="questionShow.qType" :question="questionShow.question" :qLoading="questionShow.loading"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuestionShow from '../components/Show'
|
||||
import Ueditor from '@/components/Ueditor'
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Ueditor, QuestionShow
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
questionType: 3,
|
||||
gradeLevel: null,
|
||||
subjectId: null,
|
||||
title: '',
|
||||
items: [
|
||||
{ id: null, prefix: 'A', content: '是' },
|
||||
{ id: null, prefix: 'B', content: '否' }
|
||||
],
|
||||
analyze: '',
|
||||
correct: '',
|
||||
score: '',
|
||||
difficult: 0
|
||||
},
|
||||
subjectFilter: null,
|
||||
formLoading: false,
|
||||
rules: {
|
||||
gradeLevel: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
],
|
||||
subjectId: [
|
||||
{ required: true, message: '请选择学科', trigger: 'change' }
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: '请输入题干', trigger: 'blur' }
|
||||
],
|
||||
analyze: [
|
||||
{ required: true, message: '请输入解析', trigger: 'blur' }
|
||||
],
|
||||
score: [
|
||||
{ required: true, message: '请输入分数', trigger: 'blur' }
|
||||
],
|
||||
correct: [
|
||||
{ required: true, message: '请选择正确答案', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
richEditor: {
|
||||
dialogVisible: false,
|
||||
object: null,
|
||||
parameterName: '',
|
||||
instance: null
|
||||
},
|
||||
questionShow: {
|
||||
qType: 0,
|
||||
dialog: false,
|
||||
question: null,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.subjectFilter = _this.subjects
|
||||
})
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
questionApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editorReady (instance) {
|
||||
this.richEditor.instance = instance
|
||||
let currentContent = this.richEditor.object[this.richEditor.parameterName]
|
||||
this.richEditor.instance.setContent(currentContent)
|
||||
// 光标定位到Ueditor
|
||||
this.richEditor.instance.focus(true)
|
||||
},
|
||||
inputClick (object, parameterName) {
|
||||
this.richEditor.object = object
|
||||
this.richEditor.parameterName = parameterName
|
||||
this.richEditor.dialogVisible = true
|
||||
},
|
||||
editorConfirm () {
|
||||
let content = this.richEditor.instance.getContent()
|
||||
this.richEditor.object[this.richEditor.parameterName] = content
|
||||
this.richEditor.dialogVisible = false
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
questionApi.edit(this.form).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/exam/question/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
levelChange () {
|
||||
this.form.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.form.gradeLevel)
|
||||
},
|
||||
showQuestion () {
|
||||
this.questionShow.dialog = true
|
||||
this.questionShow.qType = this.form.questionType
|
||||
this.questionShow.question = this.form
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
157
source/vue/xzs-admin/src/views/exam/question/list.vue
Normal file
157
source/vue/xzs-admin/src/views/exam/question/list.vue
Normal file
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="题目ID:">
|
||||
<el-input v-model="queryParam.id" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级:">
|
||||
<el-select v-model="queryParam.level" placeholder="年级" @change="levelChange" clearable>
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="学科:">
|
||||
<el-select v-model="queryParam.subjectId" clearable>
|
||||
<el-option v-for="item in subjectFilter" :key="item.id" :value="item.id"
|
||||
:label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="题型:">
|
||||
<el-select v-model="queryParam.questionType" clearable>
|
||||
<el-option v-for="item in questionType" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<el-popover placement="bottom" trigger="click">
|
||||
<el-button type="warning" size="mini" v-for="item in editUrlEnum" :key="item.key"
|
||||
@click="$router.push({path:item.value})">{{item.name}}
|
||||
</el-button>
|
||||
<el-button slot="reference" type="primary" class="link-left">添加</el-button>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" width="90px"/>
|
||||
<el-table-column prop="subjectId" label="学科" :formatter="subjectFormatter" width="120px"/>
|
||||
<el-table-column prop="questionType" label="题型" :formatter="questionTypeFormatter" width="70px"/>
|
||||
<el-table-column prop="shortTitle" label="题干" show-overflow-tooltip/>
|
||||
<el-table-column prop="score" label="分数" width="60px"/>
|
||||
<el-table-column prop="difficult" label="难度" width="60px"/>
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="操作" align="center" width="220px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="showQuestion(row)">预览</el-button>
|
||||
<el-button size="mini" @click="editQuestion(row)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="deleteQuestion(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
<el-dialog :visible.sync="questionShow.dialog" style="width: 100%;height: 100%">
|
||||
<QuestionShow :qType="questionShow.qType" :question="questionShow.question" :qLoading="questionShow.loading"/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import QuestionShow from './components/Show'
|
||||
import questionApi from '@/api/question'
|
||||
|
||||
export default {
|
||||
components: { Pagination, QuestionShow },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
id: null,
|
||||
questionType: null,
|
||||
level: null,
|
||||
subjectId: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
subjectFilter: null,
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0,
|
||||
questionShow: {
|
||||
qType: 0,
|
||||
dialog: false,
|
||||
question: null,
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.initSubject()
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
search () {
|
||||
this.listLoading = true
|
||||
questionApi.pageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
levelChange () {
|
||||
this.queryParam.subjectId = null
|
||||
this.subjectFilter = this.subjects.filter(data => data.level === this.queryParam.level)
|
||||
},
|
||||
addQuestion () {
|
||||
this.$router.push('/exam/question/edit/singleChoice')
|
||||
},
|
||||
showQuestion (row) {
|
||||
let _this = this
|
||||
this.questionShow.dialog = true
|
||||
this.questionShow.loading = true
|
||||
questionApi.select(row.id).then(re => {
|
||||
_this.questionShow.qType = re.response.questionType
|
||||
_this.questionShow.question = re.response
|
||||
_this.questionShow.loading = false
|
||||
})
|
||||
},
|
||||
editQuestion (row) {
|
||||
let url = this.enumFormat(this.editUrlEnum, row.questionType)
|
||||
this.$router.push({ path: url, query: { id: row.id } })
|
||||
},
|
||||
deleteQuestion (row) {
|
||||
let _this = this
|
||||
questionApi.deleteQuestion(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
questionTypeFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.questionType, cellValue)
|
||||
},
|
||||
subjectFormatter (row, column, cellValue, index) {
|
||||
return this.subjectEnumFormat(cellValue)
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionType: state => state.exam.question.typeEnum,
|
||||
editUrlEnum: state => state.exam.question.editUrlEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapGetters('exam', ['subjectEnumFormat']),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
70
source/vue/xzs-admin/src/views/log/list.vue
Normal file
70
source/vue/xzs-admin/src/views/log/list.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="用户Id:">
|
||||
<el-input v-model="queryParam.userId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名:">
|
||||
<el-input v-model="queryParam.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" width="100" />
|
||||
<el-table-column prop="userName" label="用户名" width="150" />
|
||||
<el-table-column prop="realName" label="真实姓名" width="150" />
|
||||
<el-table-column prop="content" label="动态" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Pagination from '@/components/Pagination'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
userId: null,
|
||||
userName: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let userId = this.$route.query.userId
|
||||
if (userId && parseInt(userId) !== 0) {
|
||||
this.queryParam.userId = userId
|
||||
}
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
userApi.getUserEventPageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
286
source/vue/xzs-admin/src/views/login/index.vue
Normal file
286
source/vue/xzs-admin/src/views/login/index.vue
Normal file
@@ -0,0 +1,286 @@
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
|
||||
|
||||
<div class="title-container">
|
||||
<h3 class="title">学之思管理系统</h3>
|
||||
</div>
|
||||
|
||||
<el-form-item prop="userName">
|
||||
<span class="svg-container">
|
||||
<svg-icon icon-class="user" />
|
||||
</span>
|
||||
<el-input
|
||||
ref="userName"
|
||||
v-model="loginForm.userName"
|
||||
placeholder="用户名"
|
||||
name="userName"
|
||||
type="text"
|
||||
tabindex="1"
|
||||
auto-complete="on"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
|
||||
<el-form-item prop="password">
|
||||
<span class="svg-container">
|
||||
<svg-icon icon-class="password" />
|
||||
</span>
|
||||
<el-input
|
||||
:key="passwordType"
|
||||
ref="password"
|
||||
v-model="loginForm.password"
|
||||
:type="passwordType"
|
||||
placeholder="密码"
|
||||
name="password"
|
||||
tabindex="2"
|
||||
auto-complete="on"
|
||||
@keyup.native="checkCapslock"
|
||||
@blur="capsTooltip = false"
|
||||
@keyup.enter.native="handleLogin"
|
||||
/>
|
||||
<span class="show-pwd" @click="showPwd">
|
||||
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
|
||||
</span>
|
||||
</el-form-item>
|
||||
</el-tooltip>
|
||||
|
||||
<el-checkbox v-model="loginForm.remember" style="margin-bottom: 20px;margin-left: 5px;">记住密码</el-checkbox>
|
||||
|
||||
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
|
||||
|
||||
</el-form>
|
||||
|
||||
<div class="account-foot-copyright">
|
||||
<span>Copyright © 2020 武汉思维跳跃科技有限公司 版权所有</span><span>|</span>
|
||||
<span>鄂ICP备19021884号-1</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import loginApi from '@/api/login'
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
data () {
|
||||
const validateUsername = (rule, value, callback) => {
|
||||
if (value.length < 5) {
|
||||
callback(new Error('用户名不能少于5个字符'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
const validatePassword = (rule, value, callback) => {
|
||||
if (value.length < 5) {
|
||||
callback(new Error('密码不能少于5个字符'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
loginForm: {
|
||||
userName: '',
|
||||
password: '',
|
||||
remember: false
|
||||
},
|
||||
loginRules: {
|
||||
userName: [{ required: true, trigger: 'blur', validator: validateUsername }],
|
||||
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
|
||||
},
|
||||
passwordType: 'password',
|
||||
capsTooltip: false,
|
||||
loading: false,
|
||||
showDialog: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// window.addEventListener('storage', this.afterQRScan)
|
||||
},
|
||||
mounted () {
|
||||
if (this.loginForm.userName === '') {
|
||||
this.$refs.userName.focus()
|
||||
} else if (this.loginForm.password === '') {
|
||||
this.$refs.password.focus()
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
// window.removeEventListener('storage', this.afterQRScan)
|
||||
},
|
||||
methods: {
|
||||
checkCapslock ({ shiftKey, key } = {}) {
|
||||
if (key && key.length === 1) {
|
||||
// eslint-disable-next-line no-mixed-operators
|
||||
if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) {
|
||||
this.capsTooltip = true
|
||||
} else {
|
||||
this.capsTooltip = false
|
||||
}
|
||||
}
|
||||
if (key === 'CapsLock' && this.capsTooltip === true) {
|
||||
this.capsTooltip = false
|
||||
}
|
||||
},
|
||||
showPwd () {
|
||||
if (this.passwordType === 'password') {
|
||||
this.passwordType = ''
|
||||
} else {
|
||||
this.passwordType = 'password'
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs.password.focus()
|
||||
})
|
||||
},
|
||||
handleLogin () {
|
||||
let _this = this
|
||||
this.$refs.loginForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
loginApi.login(this.loginForm).then(function (result) {
|
||||
if (result && result.code === 1) {
|
||||
_this.setUserName(_this.loginForm.userName)
|
||||
_this.$router.push({ path: '/' })
|
||||
} else {
|
||||
_this.loading = false
|
||||
_this.$message({
|
||||
message: result.message,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
}).catch(function (reason) {
|
||||
_this.loading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
...mapMutations('user', ['setUserName'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* 修复input 背景不协调 和光标变色 */
|
||||
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
|
||||
|
||||
$bg:#283443;
|
||||
$light_gray:#fff;
|
||||
$cursor: #fff;
|
||||
|
||||
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
|
||||
.login-container .el-input input {
|
||||
color: $cursor;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset element-ui css */
|
||||
.login-container {
|
||||
.el-input {
|
||||
display: inline-block;
|
||||
height: 47px;
|
||||
width: 85%;
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
border: 0px;
|
||||
-webkit-appearance: none;
|
||||
border-radius: 0px;
|
||||
padding: 12px 5px 12px 15px;
|
||||
color: $light_gray;
|
||||
height: 47px;
|
||||
caret-color: $cursor;
|
||||
|
||||
&:-webkit-autofill {
|
||||
box-shadow: 0 0 0px 1000px $bg inset !important;
|
||||
-webkit-text-fill-color: $cursor !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
color: #454545;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$bg:#2d3a4b;
|
||||
$dark_gray:#889aa4;
|
||||
$light_gray:#eee;
|
||||
|
||||
.login-container {
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
background-color: $bg;
|
||||
overflow: hidden;
|
||||
|
||||
.login-form {
|
||||
position: relative;
|
||||
width: 520px;
|
||||
max-width: 100%;
|
||||
padding:30px 50px 10px 50px;
|
||||
margin:120px auto auto auto;
|
||||
overflow: hidden;
|
||||
background: rgba(252, 254, 255, 0.11)
|
||||
}
|
||||
|
||||
.tips {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
margin-bottom: 10px;
|
||||
|
||||
span {
|
||||
&:first-of-type {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
padding: 6px 5px 6px 15px;
|
||||
color: $dark_gray;
|
||||
vertical-align: middle;
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.title-container {
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-size: 26px;
|
||||
color: $light_gray;
|
||||
margin: 0px auto 40px auto;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.show-pwd {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 7px;
|
||||
font-size: 16px;
|
||||
color: $dark_gray;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.thirdparty-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 6px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 470px) {
|
||||
.thirdparty-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
66
source/vue/xzs-admin/src/views/message/list.vue
Normal file
66
source/vue/xzs-admin/src/views/message/list.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="发送者用户名:">
|
||||
<el-input v-model="queryParam.sendUserName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" width="100" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip/>
|
||||
<el-table-column prop="content" label="内容" show-overflow-tooltip />
|
||||
<el-table-column prop="sendUserName" label="发送人" width="100" />
|
||||
<el-table-column prop="receives" label="接收人" show-overflow-tooltip />
|
||||
<el-table-column prop="readCount" label="已读数" width="70" />
|
||||
<el-table-column prop="receiveUserCount" label="接收人数" width="100" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import Pagination from '@/components/Pagination'
|
||||
import messageApi from '@/api/message'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
sendUserName: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
messageApi.pageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
99
source/vue/xzs-admin/src/views/message/send.vue
Normal file
99
source/vue/xzs-admin/src/views/message/send.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="标题:" prop="title" required>
|
||||
<el-input v-model="form.title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="内容:" prop="content" required>
|
||||
<el-input type="textarea" rows="13" v-model="form.content"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="接收人:" required>
|
||||
<el-select v-model="form.receiveUserIds" multiple filterable remote reserve-keyword
|
||||
placeholder="请输入用户名"
|
||||
:remote-method="getUserByUserName"
|
||||
:loading="selectLoading">
|
||||
<el-option v-for="item in options" :key="item.value" :label="item.name" :value="item.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">发送</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex'
|
||||
import userApi from '@/api/user'
|
||||
import messageApi from '@/api/message'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
title: '',
|
||||
content: '',
|
||||
receiveUserIds: []
|
||||
},
|
||||
formLoading: false,
|
||||
selectLoading: false,
|
||||
options: [],
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, message: '请输入消息标题', trigger: 'blur' }
|
||||
],
|
||||
realName: [
|
||||
{ required: true, message: '请输入消息内容', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
getUserByUserName (query) {
|
||||
let _this = this
|
||||
if (query !== '') {
|
||||
_this.selectLoading = true
|
||||
userApi.selectByUserName(query).then(re => {
|
||||
_this.selectLoading = false
|
||||
_this.options = re.response
|
||||
})
|
||||
} else {
|
||||
_this.options = []
|
||||
}
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
messageApi.send(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/message/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
_this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
this.options = []
|
||||
this.form.receiveUserIds = []
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<el-form>
|
||||
<el-form-item label="真实姓名">
|
||||
<el-input v-model.trim="userInfo.realName" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号">
|
||||
<el-input v-model.trim="userInfo.phone" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submit">更新</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import userApi from '@/api/user'
|
||||
export default {
|
||||
props: {
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
realName: '',
|
||||
phone: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit () {
|
||||
let _this = this
|
||||
userApi.updateUser(this.userInfo).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<div class="block">
|
||||
<el-timeline>
|
||||
<el-timeline-item placement="top" :timestamp="userInfo.lastActiveTime">
|
||||
<el-card>
|
||||
<h4>最后活动时间</h4>
|
||||
<p>{{ userInfo.realName+'在校考系统中最后活动了' }}</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
<el-timeline-item placement="top" :timestamp="userInfo.createTime">
|
||||
<el-card>
|
||||
<h4>加入时间</h4>
|
||||
<p>{{ userInfo.realName+'加入了校考系统' }}</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
realName: '',
|
||||
lastActiveTime: '',
|
||||
createTime: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
117
source/vue/xzs-admin/src/views/profile/components/UserCard.vue
Normal file
117
source/vue/xzs-admin/src/views/profile/components/UserCard.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<el-card style="margin-bottom:20px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>关于我</span>
|
||||
</div>
|
||||
|
||||
<div class="user-profile">
|
||||
<div class="box-center">
|
||||
<img :src="userInfo.imagePath === null ? require('@/assets/avatar.gif') : userInfo.imagePath " height="100px" width="100px" style="border-radius: 50px">
|
||||
</div>
|
||||
<div class="box-center">
|
||||
<div class="user-name text-center">{{ userInfo.userName }}</div>
|
||||
<div class="user-role text-center text-muted">{{ enumFormat(roleEnum,userInfo.role) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-bio">
|
||||
<div class="user-education user-bio-section">
|
||||
<div class="user-bio-section-header"><svg-icon icon-class="education" /><span>个人简介</span></div>
|
||||
<div class="user-bio-section-body">
|
||||
<div class="text-muted">
|
||||
无
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
realName: '',
|
||||
userName: '',
|
||||
role: '',
|
||||
imagePath: null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
roleEnum: state => state.user.roleEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box-center {
|
||||
margin: 0 auto;
|
||||
display: table;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.user-profile {
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.box-center {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
padding-top: 10px;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.box-social {
|
||||
padding-top: 30px;
|
||||
|
||||
.el-table {
|
||||
border-top: 1px solid #dfe6ec;
|
||||
}
|
||||
}
|
||||
|
||||
.user-follow {
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-bio {
|
||||
margin-top: 20px;
|
||||
color: #606266;
|
||||
|
||||
span {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.user-bio-section {
|
||||
font-size: 14px;
|
||||
padding: 15px 0;
|
||||
|
||||
.user-bio-section-header {
|
||||
border-bottom: 1px solid #dfe6ec;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
56
source/vue/xzs-admin/src/views/profile/index.vue
Normal file
56
source/vue/xzs-admin/src/views/profile/index.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
|
||||
<el-col :span="6" :xs="24">
|
||||
<user-card :userInfo="userInfo" />
|
||||
</el-col>
|
||||
|
||||
<el-col :span="18" :xs="24">
|
||||
<el-card>
|
||||
<el-tabs active-name="timeline">
|
||||
<el-tab-pane label="时间线" name="timeline">
|
||||
<timeline :userInfo="userInfo" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="账号" name="account">
|
||||
<account :userInfo="userInfo" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserCard from './components/UserCard'
|
||||
import Timeline from './components/Timeline'
|
||||
import Account from './components/Account'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
name: 'Profile',
|
||||
data () {
|
||||
return {
|
||||
userInfo: {
|
||||
realName: '',
|
||||
phone: '',
|
||||
lastActiveTime: '',
|
||||
createTime: '',
|
||||
role: '1',
|
||||
imagePath: null
|
||||
}
|
||||
}
|
||||
},
|
||||
components: { UserCard, Timeline, Account },
|
||||
created () {
|
||||
let _this = this
|
||||
userApi.getCurrentUser().then(re => {
|
||||
_this.userInfo = re.response
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
12
source/vue/xzs-admin/src/views/redirect/index.vue
Normal file
12
source/vue/xzs-admin/src/views/redirect/index.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<script>
|
||||
export default {
|
||||
created () {
|
||||
const { params, query } = this.$route
|
||||
const { path } = params
|
||||
this.$router.replace({ path: '/' + path, query })
|
||||
},
|
||||
render: function (h) {
|
||||
return h() // avoid warning message
|
||||
}
|
||||
}
|
||||
</script>
|
||||
196
source/vue/xzs-admin/src/views/task/edit.vue
Normal file
196
source/vue/xzs-admin/src/views/task/edit.vue
Normal file
@@ -0,0 +1,196 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="年级:" prop="gradeLevel" required>
|
||||
<el-select v-model="form.gradeLevel" placeholder="年级" @change="levelChange" >
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标题:" prop="title" required>
|
||||
<el-input v-model="form.title"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="试卷:" required>
|
||||
<el-table :data="form.paperItems" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="subjectId" label="学科" :formatter="subjectFormatter" width="120px" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="操作" align="center" width="160px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" type="danger" @click="removePaper(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button type="success" @click="addPaper">添加试卷</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-dialog :visible.sync="paperPage.showDialog" width="70%">
|
||||
<el-form :model="paperPage.queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="学科:" >
|
||||
<el-select v-model="paperPage.queryParam.subjectId" clearable>
|
||||
<el-option v-for="item in paperPage.subjectFilter" :key="item.id" :value="item.id" :label="item.name+' ( '+item.levelName+' )'"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="examPaperSubmitForm">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="paperPage.listLoading" :data="paperPage.tableData"
|
||||
@selection-change="handleSelectionChange" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column type="selection" width="35"></el-table-column>
|
||||
<el-table-column prop="id" label="Id" width="90px"/>
|
||||
<el-table-column prop="subjectId" label="学科" :formatter="subjectFormatter" width="120px" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
</el-table>
|
||||
<pagination v-show="paperPage.total>0" :total="paperPage.total"
|
||||
:page.sync="paperPage.queryParam.pageIndex" :limit.sync="paperPage.queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="paperPage.showDialog = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmPaperSelect">确定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import taskApi from '@/api/task'
|
||||
import examPaperApi from '@/api/examPaper'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
gradeLevel: null,
|
||||
title: '',
|
||||
paperItems: []
|
||||
},
|
||||
formLoading: false,
|
||||
paperPage: {
|
||||
subjectFilter: null,
|
||||
multipleSelection: [],
|
||||
showDialog: false,
|
||||
queryParam: {
|
||||
subjectId: null,
|
||||
level: null,
|
||||
paperType: 6,
|
||||
pageIndex: 1,
|
||||
pageSize: 5
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
},
|
||||
rules: {
|
||||
gradeLevel: [{ required: true, message: '请输入年级', trigger: 'change' }],
|
||||
title: [{ required: true, message: '请输入任务标题', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let _this = this
|
||||
this.initSubject(function () {
|
||||
_this.paperPage.subjectFilter = _this.subjects
|
||||
})
|
||||
|
||||
let id = this.$route.query.id
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
taskApi.select(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addPaper () {
|
||||
this.paperPage.queryParam.level = this.form.gradeLevel
|
||||
this.paperPage.showDialog = true
|
||||
this.search()
|
||||
},
|
||||
confirmPaperSelect () {
|
||||
this.paperPage.multipleSelection.forEach(ep => this.form.paperItems.push(ep))
|
||||
this.paperPage.showDialog = false
|
||||
},
|
||||
search () {
|
||||
this.paperPage.showDialog = true
|
||||
this.listLoading = true
|
||||
examPaperApi.taskExamPage(this.paperPage.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.paperPage.tableData = re.list
|
||||
this.paperPage.total = re.total
|
||||
this.paperPage.queryParam.pageIndex = re.pageNum
|
||||
this.paperPage.listLoading = false
|
||||
})
|
||||
},
|
||||
handleSelectionChange (val) {
|
||||
this.paperPage.multipleSelection = val
|
||||
},
|
||||
examPaperSubmitForm () {
|
||||
this.paperPage.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
levelChange () {
|
||||
this.paperPage.queryParam.subjectId = null
|
||||
this.paperPage.subjectFilter = this.subjects.filter(data => data.level === this.form.gradeLevel)
|
||||
},
|
||||
removePaper (row) {
|
||||
this.form.paperItems.forEach((item, index, arr) => {
|
||||
if (item.id === row.id) {
|
||||
arr.splice(index, 1)
|
||||
}
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
taskApi.edit(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/task/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
}
|
||||
_this.formLoading = false
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
subjectFormatter (row, column, cellValue, index) {
|
||||
return this.subjectEnumFormat(cellValue)
|
||||
},
|
||||
...mapActions('exam', { initSubject: 'initSubject' }),
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
questionTypeEnum: state => state.exam.question.typeEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
}),
|
||||
...mapGetters('exam', ['subjectEnumFormat']),
|
||||
...mapState('exam', { subjects: state => state.subjects })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
91
source/vue/xzs-admin/src/views/task/list.vue
Normal file
91
source/vue/xzs-admin/src/views/task/list.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="年级:">
|
||||
<el-select v-model="queryParam.gradeLevel" placeholder="年级" clearable>
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" width="100" />
|
||||
<el-table-column prop="title" label="标题" />
|
||||
<el-table-column prop="gradeLevel" label="学级" :formatter="levelFormatter"/>
|
||||
<el-table-column prop="createUserName" label="发送人" width="100" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="操作" align="center" width="160px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="$router.push({path:'/task/edit',query:{id:row.id}})" >编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="deleteTask(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import taskApi from '@/api/task'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
gradeLevel: null,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
taskApi.pageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
deleteTask (row) {
|
||||
let _this = this
|
||||
taskApi.deleteTask(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
levelFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.levelEnum, cellValue)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', ['enumFormat']),
|
||||
...mapState('enumItem', {
|
||||
levelEnum: state => state.user.levelEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
122
source/vue/xzs-admin/src/views/user/admin/edit.vue
Normal file
122
source/vue/xzs-admin/src/views/user/admin/edit.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="用户名:" prop="userName" required>
|
||||
<el-input v-model="form.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码:" required>
|
||||
<el-input v-model="form.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="真实姓名:" prop="realName" required>
|
||||
<el-input v-model="form.realName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年龄:">
|
||||
<el-input v-model="form.age"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-select v-model="form.sex" placeholder="性别" clearable>
|
||||
<el-option v-for="item in sexEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态:" required>
|
||||
<el-select v-model="form.status" placeholder="状态">
|
||||
<el-option v-for="item in statusEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
userName: '',
|
||||
password: '',
|
||||
realName: '',
|
||||
role: 3,
|
||||
status: 1,
|
||||
age: '',
|
||||
sex: '',
|
||||
birthDay: null,
|
||||
phone: null
|
||||
},
|
||||
formLoading: false,
|
||||
rules: {
|
||||
userName: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' }
|
||||
],
|
||||
realName: [
|
||||
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
userApi.selectUser(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
userApi.createUser(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/user/admin/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
_this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
roleEnum: state => state.user.roleEnum,
|
||||
statusEnum: state => state.user.statusEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
131
source/vue/xzs-admin/src/views/user/admin/list.vue
Normal file
131
source/vue/xzs-admin/src/views/user/admin/list.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="用户名:">
|
||||
<el-input v-model="queryParam.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<router-link :to="{path:'/user/admin/edit'}" class="link-left">
|
||||
<el-button type="primary">添加</el-button>
|
||||
</router-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" />
|
||||
<el-table-column prop="userName" label="用户名"/>
|
||||
<el-table-column prop="realName" label="真实姓名" />
|
||||
<el-table-column prop="sex" label="性别" width="60px;" :formatter="sexFormatter"/>
|
||||
<el-table-column prop="phone" label="手机号"/>
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="状态" prop="status" width="70px">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag :type="statusTagFormatter(row.status)">
|
||||
{{ statusFormatter(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="220px" label="操作" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="changeStatus(row)" class="link-left">
|
||||
{{ statusBtnFormatter(row.status) }}
|
||||
</el-button>
|
||||
<router-link :to="{path:'/user/admin/edit', query:{id:row.id}}" class="link-left">
|
||||
<el-button size="mini">编辑</el-button>
|
||||
</router-link>
|
||||
<el-button size="mini" type="danger" @click="deleteUser(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
userName: '',
|
||||
role: 3,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
userApi.getUserPageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
changeStatus (row) {
|
||||
let _this = this
|
||||
userApi.changeStatus(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
row.status = re.response
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteUser (row) {
|
||||
let _this = this
|
||||
userApi.deleteUser(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
sexFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.sexEnum, cellValue)
|
||||
},
|
||||
statusFormatter (status) {
|
||||
return this.enumFormat(this.statusEnum, status)
|
||||
},
|
||||
statusTagFormatter (status) {
|
||||
return this.enumFormat(this.statusTag, status)
|
||||
},
|
||||
statusBtnFormatter (status) {
|
||||
return this.enumFormat(this.statusBtn, status)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
statusEnum: state => state.user.statusEnum,
|
||||
statusTag: state => state.user.statusTag,
|
||||
statusBtn: state => state.user.statusBtn
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
132
source/vue/xzs-admin/src/views/user/student/edit.vue
Normal file
132
source/vue/xzs-admin/src/views/user/student/edit.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="用户名:" prop="userName" required>
|
||||
<el-input v-model="form.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码:" required>
|
||||
<el-input v-model="form.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="真实姓名:" prop="realName" required>
|
||||
<el-input v-model="form.realName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年龄:">
|
||||
<el-input v-model="form.age"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-select v-model="form.sex" placeholder="性别" clearable>
|
||||
<el-option v-for="item in sexEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年级:" prop="userLevel" required>
|
||||
<el-select v-model="form.userLevel" placeholder="年级">
|
||||
<el-option v-for="item in levelEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态:" required>
|
||||
<el-select v-model="form.status" placeholder="状态">
|
||||
<el-option v-for="item in statusEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
userName: '',
|
||||
password: '',
|
||||
realName: '',
|
||||
role: 1,
|
||||
status: 1,
|
||||
age: '',
|
||||
sex: '',
|
||||
birthDay: null,
|
||||
phone: null,
|
||||
userLevel: null
|
||||
},
|
||||
formLoading: false,
|
||||
rules: {
|
||||
userName: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' }
|
||||
],
|
||||
realName: [
|
||||
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
|
||||
],
|
||||
userLevel: [
|
||||
{ required: true, message: '请选择年级', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
userApi.selectUser(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
userApi.createUser(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/user/student/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
_this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
roleEnum: state => state.user.roleEnum,
|
||||
statusEnum: state => state.user.statusEnum,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
139
source/vue/xzs-admin/src/views/user/student/list.vue
Normal file
139
source/vue/xzs-admin/src/views/user/student/list.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="用户名:">
|
||||
<el-input v-model="queryParam.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<router-link :to="{path:'/user/student/edit'}" class="link-left">
|
||||
<el-button type="primary">添加</el-button>
|
||||
</router-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" />
|
||||
<el-table-column prop="userName" label="用户名"/>
|
||||
<el-table-column prop="realName" label="真实姓名" />
|
||||
<el-table-column prop="userLevel" label="学级" :formatter="levelFormatter"/>
|
||||
<el-table-column prop="sex" label="性别" width="60px;" :formatter="sexFormatter"/>
|
||||
<el-table-column prop="phone" label="手机号"/>
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="状态" prop="status" width="70px">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag :type="statusTagFormatter(row.status)">
|
||||
{{ statusFormatter(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="270px" label="操作" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="changeStatus(row)" class="link-left">
|
||||
{{ statusBtnFormatter(row.status) }}
|
||||
</el-button>
|
||||
<router-link :to="{path:'/user/student/edit', query:{id:row.id}}" class="link-left">
|
||||
<el-button size="mini" >编辑</el-button>
|
||||
</router-link>
|
||||
<router-link :to="{path:'/log/user/list', query:{userId:row.id}}" class="link-left">
|
||||
<el-button size="mini" >日志</el-button>
|
||||
</router-link>
|
||||
<el-button size="mini" type="danger" @click="deleteUser(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
userName: '',
|
||||
role: 1,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
userApi.getUserPageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
changeStatus (row) {
|
||||
let _this = this
|
||||
userApi.changeStatus(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
row.status = re.response
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteUser (row) {
|
||||
let _this = this
|
||||
userApi.deleteUser(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
levelFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.levelEnum, cellValue)
|
||||
},
|
||||
sexFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.sexEnum, cellValue)
|
||||
},
|
||||
statusFormatter (status) {
|
||||
return this.enumFormat(this.statusEnum, status)
|
||||
},
|
||||
statusTagFormatter (status) {
|
||||
return this.enumFormat(this.statusTag, status)
|
||||
},
|
||||
statusBtnFormatter (status) {
|
||||
return this.enumFormat(this.statusBtn, status)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
statusEnum: state => state.user.statusEnum,
|
||||
statusTag: state => state.user.statusTag,
|
||||
statusBtn: state => state.user.statusBtn,
|
||||
levelEnum: state => state.user.levelEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
122
source/vue/xzs-admin/src/views/user/teacher/edit.vue
Normal file
122
source/vue/xzs-admin/src/views/user/teacher/edit.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<el-form :model="form" ref="form" label-width="100px" v-loading="formLoading" :rules="rules">
|
||||
<el-form-item label="用户名:" prop="userName" required>
|
||||
<el-input v-model="form.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码:" required>
|
||||
<el-input v-model="form.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="真实姓名:" prop="realName" required>
|
||||
<el-input v-model="form.realName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="年龄:">
|
||||
<el-input v-model="form.age"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别:">
|
||||
<el-select v-model="form.sex" placeholder="性别" clearable>
|
||||
<el-option v-for="item in sexEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="出生日期:">
|
||||
<el-date-picker v-model="form.birthDay" type="date" placeholder="选择日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机:">
|
||||
<el-input v-model="form.phone"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态:" required>
|
||||
<el-select v-model="form.status" placeholder="状态">
|
||||
<el-option v-for="item in statusEnum" :key="item.key" :value="item.key" :label="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
form: {
|
||||
id: null,
|
||||
userName: '',
|
||||
password: '',
|
||||
realName: '',
|
||||
role: 2,
|
||||
status: 1,
|
||||
age: '',
|
||||
sex: '',
|
||||
birthDay: null,
|
||||
phone: null
|
||||
},
|
||||
formLoading: false,
|
||||
rules: {
|
||||
userName: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' }
|
||||
],
|
||||
realName: [
|
||||
{ required: true, message: '请输入真实姓名', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
let id = this.$route.query.id
|
||||
let _this = this
|
||||
if (id && parseInt(id) !== 0) {
|
||||
_this.formLoading = true
|
||||
userApi.selectUser(id).then(re => {
|
||||
_this.form = re.response
|
||||
_this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm () {
|
||||
let _this = this
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.formLoading = true
|
||||
userApi.createUser(this.form).then(data => {
|
||||
if (data.code === 1) {
|
||||
_this.$message.success(data.message)
|
||||
_this.delCurrentView(_this).then(() => {
|
||||
_this.$router.push('/user/teacher/list')
|
||||
})
|
||||
} else {
|
||||
_this.$message.error(data.message)
|
||||
_this.formLoading = false
|
||||
}
|
||||
}).catch(e => {
|
||||
_this.formLoading = false
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm () {
|
||||
this.$refs['form'].resetFields()
|
||||
},
|
||||
...mapActions('tagsView', { delCurrentView: 'delCurrentView' })
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
roleEnum: state => state.user.roleEnum,
|
||||
statusEnum: state => state.user.statusEnum
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
131
source/vue/xzs-admin/src/views/user/teacher/list.vue
Normal file
131
source/vue/xzs-admin/src/views/user/teacher/list.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParam" ref="queryForm" :inline="true">
|
||||
<el-form-item label="用户名:">
|
||||
<el-input v-model="queryParam.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm">查询</el-button>
|
||||
<router-link :to="{path:'/user/teacher/edit'}" class="link-left">
|
||||
<el-button type="primary">添加</el-button>
|
||||
</router-link>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="listLoading" :data="tableData" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column prop="id" label="Id" />
|
||||
<el-table-column prop="userName" label="用户名"/>
|
||||
<el-table-column prop="realName" label="真实姓名" />
|
||||
<el-table-column prop="sex" label="性别" width="60px;" :formatter="sexFormatter"/>
|
||||
<el-table-column prop="phone" label="手机号"/>
|
||||
<el-table-column prop="createTime" label="创建时间" width="160px"/>
|
||||
<el-table-column label="状态" prop="status" width="70px">
|
||||
<template slot-scope="{row}">
|
||||
<el-tag :type="statusTagFormatter(row.status)">
|
||||
{{ statusFormatter(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="220px" label="操作" align="center">
|
||||
<template slot-scope="{row}">
|
||||
<el-button size="mini" @click="changeStatus(row)" class="link-left">
|
||||
{{ statusBtnFormatter(row.status) }}
|
||||
</el-button>
|
||||
<router-link :to="{path:'/user/teacher/edit', query:{id:row.id}}" class="link-left">
|
||||
<el-button size="mini" >编辑</el-button>
|
||||
</router-link>
|
||||
<el-button size="mini" type="danger" @click="deleteUser(row)" class="link-left">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParam.pageIndex" :limit.sync="queryParam.pageSize"
|
||||
@pagination="search"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import userApi from '@/api/user'
|
||||
|
||||
export default {
|
||||
components: { Pagination },
|
||||
data () {
|
||||
return {
|
||||
queryParam: {
|
||||
userName: '',
|
||||
role: 2,
|
||||
pageIndex: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
listLoading: true,
|
||||
tableData: [],
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search()
|
||||
},
|
||||
methods: {
|
||||
search () {
|
||||
this.listLoading = true
|
||||
userApi.getUserPageList(this.queryParam).then(data => {
|
||||
const re = data.response
|
||||
this.tableData = re.list
|
||||
this.total = re.total
|
||||
this.queryParam.pageIndex = re.pageNum
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
changeStatus (row) {
|
||||
let _this = this
|
||||
userApi.changeStatus(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
row.status = re.response
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteUser (row) {
|
||||
let _this = this
|
||||
userApi.deleteUser(row.id).then(re => {
|
||||
if (re.code === 1) {
|
||||
_this.search()
|
||||
_this.$message.success(re.message)
|
||||
} else {
|
||||
_this.$message.error(re.message)
|
||||
}
|
||||
})
|
||||
},
|
||||
submitForm () {
|
||||
this.queryParam.pageIndex = 1
|
||||
this.search()
|
||||
},
|
||||
sexFormatter (row, column, cellValue, index) {
|
||||
return this.enumFormat(this.sexEnum, cellValue)
|
||||
},
|
||||
statusFormatter (status) {
|
||||
return this.enumFormat(this.statusEnum, status)
|
||||
},
|
||||
statusTagFormatter (status) {
|
||||
return this.enumFormat(this.statusTag, status)
|
||||
},
|
||||
statusBtnFormatter (status) {
|
||||
return this.enumFormat(this.statusBtn, status)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('enumItem', [
|
||||
'enumFormat'
|
||||
]),
|
||||
...mapState('enumItem', {
|
||||
sexEnum: state => state.user.sexEnum,
|
||||
statusEnum: state => state.user.statusEnum,
|
||||
statusTag: state => state.user.statusTag,
|
||||
statusBtn: state => state.user.statusBtn
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user