This commit is contained in:
zhangwei 2019-01-20 15:37:18 +08:00
parent 06b55ff886
commit ff00a718ea
37 changed files with 7339 additions and 122 deletions

View File

@ -0,0 +1,254 @@
<template>
<div class="">
<el-form ref="article" :model="article" :rules="rules">
<div style="z-index: 1; height: 50px;">
<div class="sub-navbar draft" style="top: 0px; z-index: 1;height: 45px;margin-top:-5px;">
<button type="button" class="el-button el-button--success el-button--mini" style="margin-left: 10px;"><!----><!---->
<span>发布</span>
</button>
<button type="button" class="el-button el-button--warning el-button--mini" @click="saveUEContent">
<span>保存</span>
</button>
</div>
</div>
<el-form-item label="标题" label-width="120px" prop="title" style="margin-top:-5px">
<el-input v-model="article.title" :rows="1" :minlength="4" :maxlength="50" type="text" placeholder="请输入标题(少于50字)" style="width:95%;"/>
</el-form-item>
<el-form-item label="收件人" label-width="120px" style="margin-bottom:12px;">
<el-button type="success" size="mini" @click="showSelectUser">收件人</el-button>
</el-form-item>
<el-form-item label="用户上传附件:" label-width="120px" prop="upload" style="margin-top:-12px;">
<el-radio-group v-model="article.upload">
<el-radio :label="0">不支持上传</el-radio>
<el-radio :label="1">支持上传</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="content" style="margin-top:-10px;">
<div style="margin-left:15px;margin-right:25px;line-height:0px;">
<vue-ueditor-wrap ref="ueditor" v-model="article.content" @ready="ready"/>
</div>
</el-form-item>
</el-form>
<el-dialog :visible.sync="dialogFormVisible" title="收件人">
<el-button type="success" size="mini" style="margin-top:-150px;" @click="selectUser">
添加收件人
</el-button>
<el-table
:data="article.receiverList"
:height="300"
border
style="width:100%;overflow:auto;">
<el-table-column :label="$t('id')" align="center" min-width="10%">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="名称" min-width="30%" align="center">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="类型" min-width="30%" align="center">
<template slot-scope="scope">
<span v-if="scope.row.roles[0]==1">教师</span>
<span v-if="scope.row.roles[0]==2">班级</span>
<span v-if="scope.row.roles[0]==3">群组</span>
</template>
</el-table-column>
<el-table-column v-if="!disabled" :label="$t('table.actions')" align="center" min-width="30%" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="handleDeleteUser(scope.$index)">{{ $t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogFormVisible = false">{{ $t('table.confirm') }}</el-button>
</span>
</el-dialog>
<showUser v-if="hackReset" ref="showUser" @listenToChildEvent="getSelectUser"/>
</div>
</template>
<script>
import VueUeditorWrap from 'vue-ueditor-wrap'
import { saveArticle, fetchArticle } from '@/api/article'
import { fetchTeacherList, fetchGroupList } from '@/api/user'
import showUser from '@/views/notice/showUser'
export default {
name: 'CreateForm',
components: { VueUeditorWrap, showUser },
data() {
return {
hackReset: false,
disabled: false,
dialogFormVisible: false,
userList: [],
articleId: this.$route.params.id,
article: {
id: undefined,
fid: this.$store.state.user.fid,
title: undefined,
upload: 0,
type: '',
content: '',
group: undefined,
attachmentList: [],
receiverList: [],
status: 'published'
},
receiverList: [],
listQuery: {
fid: this.$store.state.user.fid,
importance: undefined,
name: undefined,
type: undefined,
sort: '+id'
},
input: '',
users: undefined,
groups: undefined,
value7: '',
rules: {
title: [
{ required: true, message: '请输入标题', trigger: 'blur' },
{ min: 4, max: 50, message: '长度必须在4到50个字符之间', trigger: 'blur' }
]
}
}
},
created() {
this.fetchArticle()
this.tempRoute = Object.assign({}, this.$route)
},
methods: {
handleDeleteUser(index) {
this.article.receiverList.splice(index, 1)
},
fetchArticle() {
if (this.articleId) {
fetchArticle(this.articleId).then(response => {
if (response.data.code === 200) {
this.article = response.data.result
const route = Object.assign({}, this.tempRoute, { title: this.article.title })
this.$store.dispatch('updateVisitedView', route)
}
})
}
},
getSelectUser: function(data) {
var tempList = []
var userList = data.get('user')
for (var index in userList) {
var userReceiver = {}
userReceiver.uid = userList[index].uid
userReceiver.name = userList[index].name
userReceiver.roles = [1]
tempList.push(userReceiver)
}
var groupList = data.get('group')
for (var i in groupList) {
var groupReceiver = {}
groupReceiver.uid = groupList[i].groupId
groupReceiver.name = groupList[i].name
groupReceiver.roles = [3]
tempList.push(groupReceiver)
}
for (const v of tempList) {
var flag = true
for (const userData of this.article.receiverList) {
if (v.uid === userData.uid && v.roles[0] === userData.roles[0]) {
flag = false
break
}
}
if (flag) {
this.article.receiverList.push(v)
}
}
},
showSelectUser() {
this.dialogFormVisible = true
},
selectUser() {
this.hackReset = false
if (this.$refs.showUser) {
this.$refs.showUser.handleModifyStatus()
}
this.$nextTick(() => {
this.hackReset = true
})
},
getReceivers(name) {
if (name !== '') {
this.listQuery.name = name
fetchTeacherList(this.listQuery).then(response => {
var data = response.data
if (data.code === 200 && data.result.total > 0) {
this.users = [{
label: '用户',
options: data.result.list
}]
} else {
this.users = []
}
})
fetchGroupList(this.listQuery).then(response => {
var data = response.data
if (data.code === 200 && data.result.total > 0) {
this.groups = [{
label: '组名',
options: response.data.result.list
}]
} else {
this.groups = []
}
})
} else {
this.users = []
this.groups = []
}
},
ready(editorInstance) {
console.log(`编辑器实例${editorInstance.key}: `, editorInstance)
// setInterval(this.getUEContent,10000)
},
getUEContent: function() {
console.log(this.msg)
},
draft: function() {
console.log(this.msg)
},
saveUEContent: function() {
this.$refs['article'].validate((valid) => {
if (valid) {
saveArticle(this.article).then(() => {
this.$notify({
title: '成功',
message: '保存成功',
type: 'success',
duration: 2000
})
var path = this.$route
var allOpenViews = this.$store.state.tagsView.visitedViews
for (var index in allOpenViews) {
if (allOpenViews[index].fullPath === path.fullPath) {
this.$store.dispatch('delView', allOpenViews[index]).then(({ visitedViews }) => {
this.$router.push({ path: '/notice/list' })
})
}
}
})
}
})
}
}
}
</script>
<style>
</style>

View File

@ -1,50 +1,95 @@
<template>
<el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('newVisitis')">
<div class="card-panel-icon-wrapper icon-people">
<svg-icon icon-class="peoples" class-name="card-panel-icon" />
<div>
<el-row :gutter="50" class="panel-group">
<el-col :lg="24" class="card-panel-col">
<el-card class="box-card" style="background-color:#d9e8fb">
<el-tabs type="border-card" style="margin-top:-10px;">
<el-tab-pane label="教务通知">
<div v-for="o in 20" :key="o" class="text item separatorLine">
<a href="www.baidu.com">{{ '列表内容 ' + o }}</a>
<span style="float:right">2018-11-22</span>
<span style="color: #a7a7a7;float:right; margin-right:20px;">[ 其他 ]</span>
</div>
<div class="pagination-container" style="margin-top:10px;">
<el-pagination :current-page="1" :page-sizes="[10,20,30, 50]" :page-size="1" :total="20" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"/>
</div>
</el-tab-pane>
<el-tab-pane is-dot label="办事指南(教师)">配置管理</el-tab-pane>
<el-tab-pane label="文件下载(学生)">角色管理</el-tab-pane>
<el-tab-pane label="定时任务补偿">定时任务补偿</el-tab-pane>
</el-tabs>
<el-tabs type="border-card" style="margin-top:20px;">
<el-tab-pane label="教师通知">
<div v-for="o in 20" :key="o" class="text item separatorLine">
<a href="www.baidu.com">{{ '列表内容 ' + o }}</a>
<span style="float:right">2018-11-22</span>
<span v-if="o != 10 " style="color: #a7a7a7;float:right; margin-right:20px;">[ 张三 - 其他 ]</span>
<span v-if="o === 10 " style="color: #a7a7a7;float:right; margin-right:20px;">[ 张三1234 - 其他 ]</span>
</div>
<div class="pagination-container" style="margin-top:10px;">
<el-pagination :current-page="1" :page-sizes="[10,20,30, 50]" :page-size="1" :total="20" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"/>
</div>
</el-tab-pane>
</el-tabs>
<el-tabs type="border-card" style="margin-top:20px;">
<el-tab-pane name="more" class="more-btn">
<span slot="label">
<el-badge is-dot class="item">教务通知</el-badge>
</span>
测试
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
<el-row :gutter="40" class="panel-group">
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('purchases')">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="money" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">天气预报</div>
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num"/>
</div>
</div>
<div class="card-panel-description">
<div class="card-panel-text">New Visits</div>
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num"/>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('shoppings')">
<div class="card-panel-icon-wrapper icon-shoppingCard">
<svg-icon icon-class="shoppingCard" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">新闻</div>
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num"/>
</div>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('messages')">
<div class="card-panel-icon-wrapper icon-message">
<svg-icon icon-class="message" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">Messages</div>
<count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('purchases')">
<div class="card-panel-icon-wrapper icon-money">
<svg-icon icon-class="money" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">Purchases</div>
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num"/>
</div>
</div>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<div class="card-panel" @click="handleSetLineChartData('shoppings')">
<div class="card-panel-icon-wrapper icon-shopping">
<svg-icon icon-class="shopping" class-name="card-panel-icon" />
</div>
<div class="card-panel-description">
<div class="card-panel-text">Shoppings</div>
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num"/>
</div>
</div>
</el-col>
</el-row>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<el-card class="box-card">
<div slot="header" class="clearfix panel-group">
<span>最新公告</span>
<a href="#/example/list">
<el-button style="float: right; padding: 3px 0" type="text">更多...</el-button></a>
</div>
<div v-for="o in 8" :key="o" class="text item">
<a href="#/example/list">{{ '列表内容afassdfsaffsdf列表内容列表内容列表内容列表内容列表内容列表内容 ' + o }}</a>[17/08/29]
</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
<el-card class="box-card">
<div slot="header" class="clearfix panel-group">
<span>资源管理</span>
<el-button style="float: right; padding: 3px 0" type="text">更多...</el-button>
</div>
<div v-for="o in 8" :key="o" class="text item">
<a href="www.baidu.com">{{ '列表内容 ' + o }}</a>[17/08/29]
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
@ -55,6 +100,18 @@ export default {
CountTo
},
methods: {
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
handleSetLineChartData(type) {
this.$emit('handleSetLineChartData', type)
}
@ -63,6 +120,44 @@ export default {
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.text {
font-size: 15px;
}
a{color:#333;text-decoration:none;}
a:hover{ color:#C81F1A; text-decoration:none;}
.item {
margin-bottom: 10px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.card-header {
font-family: STKaiti;
font-size: 20px;
padding: 5px 0px;
color: #333;
}
.separatorLine {
/* clear: both; */
/* height: 1px; */
padding-bottom: 2px;
margin-left: 20px;
margin-right: 20px;
border-width: 1px;
border-style: dashed;
border-color: #34bfa3;
border-top: 0;
font-size: 14px;
font-family: "microsoft yahei", arial, sans-serif;
border-left: none;
border-right: 0;
}
.panel-group {
margin-top: 18px;
.card-panel-col{
@ -91,7 +186,7 @@ export default {
.icon-money {
background: #f4516c;
}
.icon-shopping {
.icon-shoppingCard {
background: #34bfa3
}
}
@ -104,7 +199,7 @@ export default {
.icon-money {
color: #f4516c;
}
.icon-shopping {
.icon-shoppingCard {
color: #34bfa3
}
.card-panel-icon-wrapper {

View File

@ -23,7 +23,7 @@ export default {
])
},
created() {
if (!this.roles.includes('admin')) {
if (!this.roles.includes(0) && !this.roles.includes(1)) {
this.currentRole = 'editorDashboard'
}
}

View File

@ -6,13 +6,11 @@
<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>

87
src/views/form/create.vue Normal file
View File

@ -0,0 +1,87 @@
<template>
<div id="app">
<span>sfasf</span>
<fm-making-form>
<template slot="action"/>
</fm-making-form>
</div>
</template>
<script>
import 'form-making/dist/FormMaking.css'
export default {
name: 'CreateForm',
data() {
return {
}
},
created() {
},
methods: {
}
}
</script>
<style lang="scss">
.fm-header{
height: 50px;
box-shadow: 0 2px 10px rgba(70,160,252, 0.6);
padding: 0 10px;
background-image: linear-gradient(to right,#1278f6,#00b4aa);
position: relative;
.fm-logo{
height: 26px;
vertical-align: middle;
}
.fm-title{
display: inline-block;
line-height: 50px;
vertical-align: middle;
color: #fff;
font-size: 20px;
font-weight: 600;
opacity: 0.8;
margin-left: 6px;
}
.fm-link{
height: 50px;
float: right;
a{
color: #fff;
text-decoration: none;
font-size: 14px;
line-height: 50px;
font-weight: 500;
margin-left: 10px;
&:hover{
opacity: 0.8;
}
}
}
}
.fm-container{
height: calc(100% - 50px);
}
*, :after, :before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html,body{
height: 100%;
}
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
min-height: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,130 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="请假" width="40%">
<el-form ref="ruleForm" :model="ruleForm" :rules="rules" style="magin-top:-100px;" label-width="100px" class="demo-ruleForm">
<el-form-item label="请假类型">
<el-select v-model="ruleForm.type" class="filter-item" style="width:90%;">
<el-option v-for="item in leaveTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item label="开始时间" required>
<el-col style="width:60%;">
<el-form-item prop="date1">
<el-date-picker v-model="ruleForm.date1" type="date" placeholder="选择日期" style="width: 100%;"/>
</el-form-item>
</el-col>
<el-col style="width:30%;">
<el-form-item>
<el-select v-model="ruleForm.region" placeholder="请选择活动区域" style="magin-left:20px;">
<el-option label="上午" value="0"/>
<el-option label="下午" value="1/"/>
</el-select>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="结束时间" required>
<el-col style="width:60%;">
<el-form-item prop="date1">
<el-date-picker v-model="ruleForm.date1" type="date" placeholder="选择日期" style="width: 100%;"/>
</el-form-item>
</el-col>
<el-col style="width:30%;">
<el-form-item>
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="上午" value="0"/>
<el-option label="下午" value="1/"/>
</el-select>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="时长" prop="name">
<el-input v-model="ruleForm.name" style="width:90%;"/>
</el-form-item>
<el-form-item label="请假事由" prop="desc">
<el-input v-model="ruleForm.desc" type="textarea" style="width:90%;"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</div>
</el-dialog>
</template>
<script>
import waves from '@/directive/waves' //
const leaveTypeOptions = [
{ key: 0, display_name: '事假' },
{ key: 1, display_name: '年假' },
{ key: 2, display_name: '病假' },
{ key: 3, display_name: '产假' },
{ key: 4, display_name: '陪产假' },
{ key: 5, display_name: '婚假' },
{ key: 6, display_name: '丧假' }
]
export default {
name: 'ComplexTable',
directives: {
waves
},
data() {
return {
dialogFormVisible: false,
leaveTypeOptions,
ruleForm: {
name: '',
region: '0',
date1: '',
date2: '',
delivery: false,
type: 0,
resource: '',
desc: ''
},
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
region: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
],
date1: [
{ type: 'date', required: true, message: '请选择日期', trigger: 'change' }
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' }
],
type: [
{ type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
],
resource: [
{ required: true, message: '请选择活动资源', trigger: 'change' }
],
desc: [
{ required: true, message: '请填写活动形式', trigger: 'blur' }
]
}
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!')
} else {
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
showEditDialog() {
this.dialogFormVisible = true
}
}
}
</script>

234
src/views/form/list.vue Normal file
View File

@ -0,0 +1,234 @@
<template>
<div class="app-container">
<div class="filter-container" style="float:right; margin-top:-10px;">
<el-button class="filter-item" style="margin-right: 10px;" type="primary" icon="el-icon-edit" @click="createLeave()">新建</el-button>
</div>
<div style="margin-top:-10px">
<el-table v-loading.body="listLoading" :show-overflow-tooltip="true" :data="list" border fit highlight-current-row style="width: 100%">
<el-table-column align="center" label="ID" width="80">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column align="left" width="150px" label="发布者">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column width="200px" align="center" label="发布时间">
<template slot-scope="scope">
<span>{{ scope.row.modifyTime }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" max-width="500px" align="left" label="标题">
<template slot-scope="scope">
<router-link :to="'/leave/'+scope.row.id" class="link-type" target="_blank">
<span>{{ scope.row.title }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column width="300px" align="left" label="附件">
<template slot-scope="scope">
<span v-if="scope.row.articleAttachment && scope.row.articleAttachment.attachmentName" class="el-tag el-tag--info el-tag--small">
<a class="link-type" @click="download(scope.row.articleAttachment.url, scope.row.articleAttachment.attachmentName)">{{ scope.row.articleAttachment.attachmentName }}</a>
<i class="el-tag__close el-icon-close" @click="deleteAttachment(scope.row)"/>
</span>
</template>
</el-table-column>
<el-table-column :label="$t('action')" align="center" width="150">
<template slot-scope="scope">
<el-button style="margin:5px;float:right">
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<i style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<router-link :to="'/leave/edit/'+scope.row.id">
<el-dropdown-item>
{{ $t('edit') }}
</el-dropdown-item>
</router-link>
<el-dropdown-item v-if="scope.row.upload===1" divided>
<span style="display:block;" @click="showUploadData(scope.row)"> </span>
</el-dropdown-item>
<el-dropdown-item divided>
<span style="display:block;" @click="deleteArticle(scope.row)">{{ $t('delete') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-button>
<el-upload
v-if="scope.row.upload===1"
:action="importFileUrl"
:on-remove="handleRemove"
:data="uploadData"
:on-preview="handlePreview"
:on-exceed="handleExceed"
:on-success="handleSuccess"
:file-list="scope.row.attachmentList"
:show-file-list="false"
style="float:left;margin:5px;"
name="file"
><el-button size="mini" @click="handleUpdate(scope.row)"><i class="el-icon-upload el-icon--right"/>上传</el-button>
</el-upload>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
:current-page="listQuery.page"
:page-sizes="[10,20,30, 50]"
:page-size="listQuery.limit"
:total="total"
background
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"/>
</div>
</div>
<leaveEdit ref="leaveEdit"/>
</div>
</template>
<script>
import { fetchList, deleteArticle } from '@/api/article'
import { downloadFile, deleteAttachment } from '@/api/user'
import leaveEdit from '@/views/leave/leaveEdit'
export default {
name: 'ArticleList',
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
components: {
leaveEdit
},
data() {
return {
importFileUrl: window.UEDITOR_HOME_URL + 'ueditor/importFile',
uploadData: {
noticeId: undefined
},
attachmentList: [
{ name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100' }],
list: null,
total: 0,
limit: 1,
flag: false,
count: 123,
rowIndex: undefined,
showReviewer: false,
dialogPvVisible: false,
listLoading: true,
listQuery: {
fid: this.$store.getters.user.fid,
page: 1,
limit: 20
},
selectRow: undefined
}
},
created() {
this.getList()
},
methods: {
createLeave() {
this.$refs.leaveEdit.showEditDialog()
},
deleteArticle(row) {
deleteArticle(row.id).then(() => {
fetchList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}).catch((error) => {
alert(error)
})
})
},
download(url, name) {
downloadFile(url, name)
},
showUploadData(item) {
this.$refs.leaveEdit.handleModifyStatus(item)
},
deleteAttachment(row) {
this.$confirm('您确定删除吗?').then(_ => {
deleteAttachment(row.articleAttachment).then(() => {
row.articleAttachment = undefined
})
}).catch(_ => {
})
},
handleUpdate(row) {
this.uploadData.noticeId = row.id
this.selectRow = row
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}).catch((error) => {
alert(error)
})
},
handleRemove(file, attachmentList) {
alert(file, attachmentList)
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
showDetail() {
this.flag = !this.flag
},
handlePreview(file) {
this.$message.warning(`file url = ` + file.url)
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleSuccess(response, file, attachmentList) {
if (response == null) {
return
}
this.selectRow.attachmentList = []
this.selectRow.articleAttachment = response
this.showReviewer = true
},
handleExceed(files, attachmentList) {
this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + attachmentList.length} 个文件`)
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
.demo-block {
border: 1px solid #ebebeb;
border-radius: 3px;
transition: .2s;
margin:20px;
}
</style>

228
src/views/form/show.vue Normal file
View File

@ -0,0 +1,228 @@
<template>
<div class="app-container">
<span v-html="message"/>
</div>
</template>
<script>
import { fetchArticle } from '@/api/article'
export default {
name: 'Show',
data() {
return {
message: undefined
}
},
created() {
this.fetchArticle()
},
methods: {
fetchArticle() {
this.listLoading = true
fetchArticle(this.$route.params.id).then(response => {
if (response.data.code === 200) {
this.message = response.data.result.content
}
this.listLoading = false
})
}
}
}
</script>
<style rel="stylesheet/scss" 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>

270
src/views/form/showUser.vue Normal file
View File

@ -0,0 +1,270 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="收件人" width="60%" height="2200">
<el-tabs type="border-card" style="height: 630px;margin-top:-30px;margin-bottom:10px;" >
<el-tab-pane label="教师">
<teacherComplexTable ref="teacherComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane v-if="false" label="班级">
<gradeComplexTable ref="gradeComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane v-if="false" label="群组">
<groupComplexTable ref="groupComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button type="primary" @click="addUser">{{ $t('table.add') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
import groupComplexTable from '@/views/group/index'
import studentComplexTable from '@/views/student/complexTable'
import teacherComplexTable from '@/views/teacher/complexTable'
import gradeComplexTable from '@/views/grade/complexTable'
const calendarTypeOptions = [
{ key: 'CN', display_name: 'China' },
{ key: 'US', display_name: 'USA' },
{ key: 'JP', display_name: 'Japan' },
{ key: 'EU', display_name: 'Eurozone' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ShowUser',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
components: {
groupComplexTable,
studentComplexTable,
teacherComplexTable,
gradeComplexTable
},
data() {
return {
totalStuCount: 0,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
classId: undefined,
teacherName: undefined,
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
type: '',
status: 'published'
},
dialogFormVisible: true,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
downloadLoading: false,
userList: []
}
},
created() {
this.getList()
},
methods: {
addUser() {
var map = new Map()
map.set('user', this.$refs.teacherComplexTable.getSelectUser())
// map.set('class', this.$refs.gradeComplexTable.getSelectClass())
// map.set('group', this.$refs.groupComplexTable.getSelectGroup())
// this.userList = this.$refs.teacherComplexTable.getSelectUser().concat(this.$refs.studentComplexTable.getSelectUser())
this.dialogFormVisible = false
this.$emit('listenToChildEvent', map)
},
getTotalStu: function(data) {
this.totalStuCount = data
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.items
this.total = response.data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus() {
this.dialogFormVisible = true
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
status: 'published',
type: ''
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
createArticle(this.temp).then(() => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(() => {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -0,0 +1,331 @@
<template>
<div class="app-container">
<div class="filter-container">
<el-input v-model="listQuery.name" placeholder="年级名称" style="width: 250px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
<el-button v-if="$store.state.user.admin" class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleUpdate()">{{ $t('table.add') }}</el-button>
</div>
<el-table
v-loading="listLoading"
:key="tableKey"
:data="list"
border
fit
highlight-current-row
style="width: 100%;min-height:300px;">
<el-table-column :label="$t('table.id')" align="center" width="65">
<template slot-scope="scope">
<span>{{ scope.$index+1 }}</span>
</template>
</el-table-column>
<el-table-column label="年级名称" width="150px" align="center">
<template slot-scope="scope">
<el-tooltip placement="left" effect="light">
<div slot="content">{{ scope.row.showName }}</div>
<span>{{ scope.row.name }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="班级信息" min-width="150px">
<template slot-scope="scope">
<span v-for="item in scope.row.clazzList" :key="item.id" class="el-tag el-tag--info el-tag--small" style="margin-left:5px;">
<span class="link-type" @click="handleEditClass(item)">{{ item.name }}(班主任:{{ item.teacher.name }})</span>
</span>
</template>
</el-table-column>
<el-table-column label="状态" width="100px" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.graduationStatus==1" type="info"> 已毕业</el-tag>
<el-tag v-else>在读</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button v-if="$store.state.user.admin" type="primary" size="mini" @click="handleUpdate(scope.row, scope.$index, false)">{{ $t('table.edit') }}</el-button>
<el-button size="mini" type="success" @click="handleUpdate(scope.row, scope.$index, true)">查看</el-button>
<el-button v-if="$store.state.user.admin" size="mini" type="danger" @click="deleteGrade(scope.row)">{{ $t('table.delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination :current-page="listQuery.page" :page-sizes="[10,20,30, 50]" :page-size="listQuery.limit" :total="total" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"/>
</div>
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
<el-form-item :label="$t('table.type')" prop="type">
<el-select v-model="temp.type" class="filter-item" placeholder="Please select">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('table.date')" prop="timestamp">
<el-date-picker v-model="temp.timestamp" type="datetime" />
</el-form-item>
<el-form-item :label="$t('table.title')" prop="title">
<el-input v-model="temp.title"/>
</el-form-item>
<el-form-item :label="$t('table.status')">
<el-select v-model="temp.status" class="filter-item" >
<el-option v-for="item in statusOptions" :key="item" :label="item" :value="item"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('table.importance')">
<el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;"/>
</el-form-item>
<el-form-item :label="$t('table.remark')">
<el-input :autosize="{ minRows: 2, maxRows: 4}" v-model="temp.remark" type="textarea"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">{{ $t('table.confirm') }}</el-button>
<el-button v-else type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
<el-table :data="pvData" border fit highlight-current-row style="width: 100%">
<el-table-column prop="key" label="Channel"/>
<el-table-column prop="pv" label="Pv"/>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
</span>
</el-dialog>
<edit-grade ref="editGrade" @listenToChildEvent="updateGradeRow"/>
<edit-class ref="showClass"/>
</div>
</template>
<script>
import { createArticle, updateArticle } from '@/api/article'
import { fetchGradeList, deleteGrade } from '@/api/user'
import waves from '@/directive/waves' //
import editClass from '@/views/grade/editClass'
import editGrade from '@/views/grade/editGrade'
import { parseTime } from '@/utils'
const calendarTypeOptions = [
{ key: 'CN', display_name: 'China' },
{ key: 'US', display_name: 'USA' },
{ key: 'JP', display_name: 'Japan' },
{ key: 'EU', display_name: 'Eurozone' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
components: {
editClass,
editGrade
},
data() {
return {
hackReset: true,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
fid: this.$store.state.user.fid,
name: undefined,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
type: '',
status: 'published'
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
classId: undefined,
downloadLoading: false
}
},
created() {
this.getList()
},
methods: {
updateGradeRow: function(rowData, index) {
if (index > -1) {
this.list.splice(index, 1, rowData)
} else {
this.list.unshift(rowData)
}
},
getList() {
this.listLoading = true
fetchGradeList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, status) {
this.$message({
message: '操作成功',
type: 'success'
})
row.status = status
},
deleteGrade(row) {
deleteGrade(row.id).then(response => {
fetchGradeList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
})
})
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
status: 'published',
type: ''
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
createArticle(this.temp).then(response => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row, index, disabled) {
this.$refs.editGrade.handleModifyStatus(row, index, disabled)
},
handleEditClass(item) {
if (this.$refs.showClass) {
this.$refs.showClass.handleModifyStatus(item)
}
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(() => {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -0,0 +1,57 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="班级信息" width="60%" >
<el-tabs type="border-card" style="height: 600px;">
<el-tab-pane label="班级学生">
<studentComplexTable v-if="hackReset" :table-height="420 + 'px'" :class-id="classId" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane label="任课老师">
<teacherComplexTable v-if="hackReset" :table-height="500 + 'px'" :class-id="classId" :class-name="className" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane label="课程表">
<scheduleTab v-if="hackReset" :class-id="classId" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">确认</el-button>
</div>
</el-dialog></template>
<script>
import waves from '@/directive/waves' //
import teacherComplexTable from '@/views/teacher/complexTable'
import studentComplexTable from '@/views/student/complexTable'
import scheduleTab from '@/views/grade/scheduleTab'
export default {
name: 'ComplexTable',
directives: {
waves
},
components: {
teacherComplexTable,
studentComplexTable,
scheduleTab
},
data() {
return {
hackReset: false,
classId: undefined,
className: undefined,
dialogFormVisible: false
}
},
created() {
},
methods: {
handleModifyStatus(clazz) {
this.classId = clazz.id
this.className = clazz.name
this.dialogFormVisible = true
this.hackReset = false
this.$nextTick(() => {
this.hackReset = true
})
}
}
}
</script>

View File

@ -0,0 +1,366 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="编辑">
<el-form ref="dataForm" :disabled="disabled" :rules="rules" :model="temp" label-position="right" label-width="90px" style="width: 90%; margin-left:10px;">
<el-form-item label="年级名称" prop="name">
<el-input v-model="temp.name"/>
</el-form-item>
<el-form-item label="年级别名">
<el-input v-model="temp.showName"/>
</el-form-item>
<el-form-item label="状态" prop="graduationStatus">
<el-select v-model="temp.graduationStatus" filterable class="filter-item" placeholder="Please select" style="width: 100%;">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item label="班级">
<el-row v-for="(item,index) in temp.clazzList" :gutter="10" :key="item.id" type="flex" class="row-bg" justify="left" style="margin-top:5px;">
<el-col :span="12">
<el-popover
v-model="temp.clazzList[index].visiblePopover"
:disabled="disabled"
placement="top"
width="300"
trigger="click">
<el-form :rules="rules" :model="formLabelAlign" label-position="right" label-width="80px">
<el-form-item label="班级名称" prop="name">
<el-input v-model="formLabelAlign.name"/>
</el-form-item>
<el-form-item label="班主任">
<el-select v-model="formLabelAlign.teacher" value-key="uid" filterable class="filter-item" placeholder="Please select" style="width: 100%;">
<el-option v-for="item in teacherList" :key="item.uid" :label="item.name" :value="item"/>
</el-select>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="temp.clazzList[index].visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateParent(index)">确定</el-button>
</div>
</el-form>
<div slot="reference">
<span class="el-tag el-tag--info el-tag--small" style="float:left;">
<span class="link-type" @click="editParent(item)">{{ item.name }} (班主任: {{ item.teacher.name }})</span>
<i v-if="!disabled" class="el-tag__close el-icon-close" @click="deleteParent(index)"/>
</span>
</div>
</el-popover>
</el-col>
</el-row>
<el-popover
v-model="formLabelAlign.visiblePopover"
placement="top"
width="300"
trigger="click">
<el-form ref="popoverForm" :rules="rules" :model="formLabelAlign" label-position="right" label-width="80px">
<el-form-item label="班级名称" prop="name">
<el-input v-model="formLabelAlign.name"/>
</el-form-item>
<el-form-item label="班主任">
<el-select v-model="formLabelAlign.teacher" value-key="uid" filterable class="filter-item" style="width: 100%;">
<el-option v-for="item in teacherList" :key="item.uid" :label="item.name" :value="item"/>
</el-select>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="formLabelAlign.visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateParent(-1)">确定</el-button>
</div>
</el-form>
<el-button slot="reference" icon="el-icon-circle-plus-outline" size="mini" round @click="createParent()">添加</el-button>
</el-popover>
</el-form-item>
<el-form-item label="描述">
<el-input :autosize="{ minRows: 3, maxRows: 5}" v-model="temp.remark" type="textarea"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">{{ $t('table.confirm') }}</el-button>
<el-button v-else type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { fetchList, fetchPv } from '@/api/article'
import { fetchTeacherList, updateGrade, fetchCourseList } from '@/api/user'
import { isvalidStr } from '@/utils/validate'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
const calendarTypeOptions = [
{ key: 0, display_name: '在读' },
{ key: 1, display_name: '已毕业' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
data() {
return {
disabled: true,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: undefined,
fid: this.$store.state.user.fid,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
teacherList: [],
courseList: [],
formLabelAlign: {
name: '',
teacher: {
uid: undefined,
name: undefined
},
course: {
id: undefined,
name: undefined
}
},
index: undefined,
calendarTypeOptions,
temp: {
id: undefined,
name: '',
clazzList: [],
graduationStatus: 0
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
name: [{ required: true, message: '名称必填', trigger: 'blur' }],
teacherName1: [{ required: true, message: '班主任必填', trigger: 'change' }],
teacherName: [{ validate: isvalidStr, trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
downloadLoading: false
}
},
created() {
this.getList()
},
methods: {
updateParent(index) {
this.$refs['popoverForm'].validate((valid) => {
if (valid) {
if (index > -1) {
this.formLabelAlign.visiblePopover = false
this.temp.clazzList.splice(index, 1, this.formLabelAlign)
} else {
this.formLabelAlign.visiblePopover = false
this.temp.clazzList.push(this.formLabelAlign)
}
}
})
},
deleteParent(index) {
this.temp.clazzList.splice(index, 1)
},
editParent(item) {
this.formLabelAlign = JSON.parse(JSON.stringify(item))
item.visiblePopover = !this.disabled
},
resetParent() {
this.formLabelAlign = {
name: undefined,
teacher: {
uid: undefined,
name: undefined
},
visiblePopover: true
}
},
createParent() {
this.resetParent()
this.$nextTick(() => {
this.$refs['popoverForm'].clearValidate()
})
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.items
this.total = response.data.total
this.listLoading = false
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, index, disabled) {
this.resetTemp()
this.dialogFormVisible = true
this.index = index
this.disabled = disabled
if (row) {
this.temp = JSON.parse(JSON.stringify(row))
}
this.getTeacherList()
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
getTeacherList() {
this.listLoading = true
fetchTeacherList(this.listQuery).then(response => {
this.teacherList = response.data.result.list
})
},
getCourseList() {
this.listLoading = true
fetchCourseList(this.listQuery).then(response => {
this.courseList = response.data.result.list
})
},
resetTemp() {
this.temp = {
id: undefined,
clazzList: [],
fid: this.$store.state.user.fid,
name: undefined,
graduationStatus: 0
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
updateGrade(this.temp).then(response => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateGrade(tempData).then(response => {
if (response.data.code === 200 && response.data.result) {
this.$emit('listenToChildEvent', response.data.result, this.index)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -0,0 +1,259 @@
<template>
<div class="app-container">
<!---->
<div class="tr_top">
<div class="td_top_title">{{ getMonth() }}</div>
<div v-for="(value, key, index) in ['周一','周二','周三','周四','周五','周六','周日']" :key="index">
<div :class="{td_top_data_change:setWeeks(value)}" class="td_top_data">{{ value }}({{ time[key] }})</div>
</div>
</div>
<!--课程-->
<div class="content" style="padding-bottom: 20px;">
<!---->
<div class="tr_week">
<div class="td_week_title">
<div class="td_week_title_content">早自习</div>
<div v-for="n in 8" :key="n" class="td_week_title_content">{{ n }}</div>
<div class="td_week_title_content">晚自习1</div>
<div class="td_week_title_content">晚自习2</div>
<div class="td_week_title_content">晚自习3</div>
</div>
</div>
<!--课程内容-->
<div v-for="(value, key, index) in schedule" :key="index" class="tr_week">
<div class="td_week_data">
<div v-for="(value1, key1, index1) in value" :key="index1">
<span v-if="value1" @click="updateParent(key, key1, value1)">
<div class="td_week_data_content" style="justify-content: center;display: flex;align-items: center;font-size: 10px;">
<span> {{ value1.courseName }}<span v-if="classId"> ({{ value1.teacherName }})</span><br><span v-if="!classId">{{ value1.className }}</span></span>
</div>
</span>
<div v-if="!value1" class="td_week_data_content" @click="updateParent(key, key1, value1)">
<span v-if="!value1"/>
</div>
</div>
</div>
</div>
</div>
<el-dialog
:visible.sync="dialogVisible"
width="20%"
append-to-body
center>
<el-form ref="ruleForm" :model="formLabelAlign" :rules="rules" label-position="right" label-width="60px">
<el-form-item label="课程" prop="course">
<el-select v-model="formLabelAlign.course" value-key="id" class="filter-item" style="width: 100%;">
<el-option v-for="item in courseList" :key="item.id" :label="item.courseName + '(' + item.teacherName + ')'" :value="item"/>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="saveParent()"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { formatMonth, getWeeks, formatDay, getDays } from '@/utils'
import { fetchScheduleList, fetchCourseByClassId, updateSchedule } from '@/api/user'
import waves from '@/directive/waves' //
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
props: {
type: {
type: Boolean,
default: true
},
tableHeight: {
type: String,
default: window.innerHeight - 240 + 'px'
},
classId: {
type: Number,
default: undefined
},
teacherId: {
type: String,
default: undefined
}
},
data() {
return {
disabled: true,
dialogVisible: false,
list: null,
total: null,
listLoading: true,
listQuery: {
fid: this.$store.state.user.fid,
year: 2018,
semester: 2,
classId: this.classId,
teacherId: this.teacherId,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
importanceOptions: [1, 2, 3],
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: [{ name: '在读', id: 1 }, { name: '转学', id: 0 }],
showReviewer: false,
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
gradeList: undefined,
classList: undefined,
props: {
label: 'name',
value: 'id',
children: 'clazzList'
},
dialogPvVisible: false,
pvData: [],
rules: {
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
stuNo: [{ required: true, message: '学号不能为空', trigger: 'blur' }],
course: [{ required: true, message: '必须选择一门课程', trigger: 'change' }]
},
downloadLoading: false,
time: [],
schedule: [[], [], [], [], [], [], []],
courseList: [],
formLabelAlign: {
class: {},
classId: [],
course: {},
courseName: undefined
}
}
},
created() {
this.getTimes()
if (this.classId) {
this.fetchCourseByClassId()
}
this.get('2018', '2')
},
methods: {
resetParent() {
this.formLabelAlign = {
class: {},
course: undefined,
fid: this.$store.state.user.fid,
id: undefined,
year: 2018,
semester: 2,
teacherId: undefined,
week: undefined,
courseId: undefined,
sequence: undefined
}
},
updateParent(week, sequence, item) {
if (this.classId) {
this.resetParent()
if (item) {
this.formLabelAlign.id = item.id
this.formLabelAlign.course = item.courseName + '(' + item.teacherName + ')'
}
this.formLabelAlign.week = week
this.formLabelAlign.sequence = sequence
this.dialogVisible = true
this.$nextTick(() => {
this.$refs['ruleForm'].clearValidate()
})
}
},
saveParent(item) {
this.$refs['ruleForm'].validate((valid) => {
if (valid) {
this.formLabelAlign.courseId = this.formLabelAlign.course.id
if (this.formLabelAlign.courseId) {
this.formLabelAlign.teacherId = this.formLabelAlign.course.teacherId
updateSchedule(this.formLabelAlign).then(response => {
this.get('2018', '2')
this.dialogVisible = false
})
} else {
this.dialogVisible = false
}
}
}
)
},
fetchCourseByClassId: function() {
fetchCourseByClassId(this.classId).then(response => {
this.courseList = response.data.result
})
},
get: function(year, semester) {
fetchScheduleList(this.listQuery)
.then(response => {
var tempSchedule = [[], [], [], [], [], [], []]
var result = response.data.result
tempSchedule[0][11] = undefined
tempSchedule[1][11] = undefined
tempSchedule[2][11] = undefined
tempSchedule[3][11] = undefined
tempSchedule[4][11] = undefined
tempSchedule[5][11] = undefined
tempSchedule[6][11] = undefined
for (var i = 0; i < result.length; i++) {
var week = result[i].week
var sequence = result[i].sequence
if (week === 0) {
tempSchedule[0][sequence] = result[i]
} else if (week === 1) {
tempSchedule[1][sequence] = result[i]
} else if (week === 2) {
tempSchedule[2][sequence] = result[i]
} else if (week === 3) {
tempSchedule[3][sequence] = result[i]
} else if (week === 4) {
tempSchedule[4][sequence] = result[i]
}
}
this.schedule = tempSchedule
})
},
getDate: function(data) {
return formatDay(data)
},
getTimes: function() {
// this.time=getDays();
var day = getDays()
for (var i = 0; i < 7; i++) {
this.time[i] = day[i]
}
},
setWeeks: function(data) {
return getWeeks(data)
},
getMonth: function() {
return formatMonth()
}
}
}
</script>

435
src/views/group/index.vue Normal file
View File

@ -0,0 +1,435 @@
<template>
<div class="app-container">
<div class="filter-container" style="float: right;">
<el-button v-if="type" class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">{{ $t('group.add') }}</el-button>
</div>
<el-table
v-loading="listLoading"
:data="list"
:height="tableHeight"
:row-key="getRowKeys"
max-height="700px"
border
fit
highlight-current-row
style="width:100%;overflow:auto;"
@selection-change="handleSelectionChange">
<el-table-column :label="$t('id')" align="center" width="60px">
<template slot-scope="scope">
<span>{{ (listQuery.page-1) * listQuery.limit + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('group.name')" width="150px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('createDate')" width="150px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.createDate }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('comment')" min-width="30%" align="center">
<template slot-scope="scope">
<span>{{ scope.row.comment }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="80px" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button>
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<i style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
<span style="display:block;" @click="handleUpdate(scope.row, false)"> </span>
</el-dropdown-item>
<el-dropdown-item v-if="type" divided>
<span style="display:block;" @click="handleUpdate(scope.row, true)">{{ $t('edit') }}</span>
</el-dropdown-item>
<el-dropdown-item v-if="type" divided>
<span style="display:block;" @click="handleDeleteGroup(scope.row)">{{ $t('delete') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination :current-page="listQuery.page" :page-sizes="[10,20,30,50]" :page-size="listQuery.limit" :total="total" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"/>
</div>
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" append-to-body width="40%">
<el-form ref="dataForm" :rules="rules" :model="temp" :disabled="disabled" label-position="right">
<el-form-item label="组名" label-width="60px">
<el-input v-model="temp.name" :rows="1" :minlength="4" :maxlength="50" type="text" placeholder="请输入标题(少于50字)" style="width:95%;"/>
</el-form-item>
<el-form-item :label="$t('comment')" label-width="60px">
<el-input :autosize="{ minRows: 2, maxRows: 4}" v-model="temp.comment" type="textarea" placeholder="描述..." style="width:95%;"/>
</el-form-item>
</el-form>
<el-button v-if="!disabled" type="success" size="mini" @click="selectUser">添加成员</el-button>
<el-table
v-loading="listLoading"
:data="temp.userList"
:height="300"
border
style="width:100%;overflow:auto;">
<el-table-column :label="$t('id')" align="center" min-width="10%">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="姓名" min-width="30%" align="center">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="角色" min-width="30%" align="center">
<template slot-scope="scope">
<span>{{ scope.row.roles.includes(1)? "教师" : "学生" }}</span>
</template>
</el-table-column>
<el-table-column v-if="!disabled" :label="$t('table.actions')" align="center" min-width="30%" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="handleDeleteUser(scope.row)">{{ $t('delete') }}</el-button>
</template>
</el-table-column>
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
</div>
</el-dialog>
<showUser v-if="hackReset" ref="showUser" @listenToChildEvent="getSelectUser"/>
</div>
</template>
<script>
import { fetchGroupList, fetchPv, fetchMemberList, updateArticle, deleteGroup } from '@/api/group'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
import showUser from '@/views/group/showUser'
const calendarTypeOptions = [
{ key: '1', display_name: '老师' },
{ key: '2', display_name: '学生' },
{ key: '3', display_name: '家长' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ComplexTable',
components: { showUser },
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
props: {
type: {
type: Boolean,
default: true
},
tableHeight: {
type: String,
default: window.innerHeight - 240 + 'px'
}
},
data() {
return {
disabled: true,
hackReset: false,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
importance: undefined,
title: undefined,
fid: this.$store.state.user.fid,
type: undefined,
sort: '+id'
},
userList: null,
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
groupId: undefined,
name: undefined,
userList: [],
fid: this.$store.state.user.fid,
comment: ''
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
downloadLoading: false,
groupList: []
}
},
created() {
this.getList()
},
methods: {
handleSelectionChange(val) {
this.groupList = val
},
getRowKeys(row) {
return row.groupId
},
getSelectGroup() {
return this.groupList
},
selectUser() {
this.hackReset = false
if (this.$refs.showUser) {
this.$refs.showUser.handleModifyStatus()
}
this.$nextTick(() => {
this.hackReset = true
})
},
getSelectUser: function(data) {
for (const v of data) {
var flag = true
for (const userData of this.temp.userList) {
if (v.uid === userData.uid) {
flag = false
break
}
}
if (flag) {
this.temp.userList.push(v)
}
}
},
getList() {
this.listLoading = true
fetchGroupList(this.listQuery).then(response => {
if (response.data.code === 200) {
this.list = response.data.result.list
this.total = response.data.result.total
this.dialogFormVisible = false
this.listLoading = false
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
},
getMemberList() {
this.listLoading = true
fetchMemberList(this.listQuery).then(response => {
if (response.data.code === 200) {
this.memberList.push(response.data.result)
this.dialogFormVisible = false
this.listLoading = false
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, status) {
this.$message({
message: '操作成功',
type: 'success'
})
row.status = status
},
resetTemp() {
this.temp = {
groupId: undefined,
name: undefined,
userList: [],
fid: this.$store.state.user.fid,
comment: ''
}
},
handleCreate() {
this.disabled = false
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
}
})
},
handleUpdate(row, disabled) {
this.disabled = !disabled
fetchMemberList(row.groupId).then(response => {
if (response.data.code === 200) {
this.temp.userList = response.data.result
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
if (!this.disabled) {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(response => {
if (tempData.groupId) {
for (const v of this.list) {
if (v.groupId === this.temp.groupId) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
} else {
this.list.unshift(response.data.result)
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
} else {
this.dialogFormVisible = false
}
},
handleDeleteUser(row) {
var index = this.temp.userList.indexOf(row)
this.temp.userList.splice(index, 1)
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
},
handleDeleteGroup(row) {
deleteGroup(row.groupId).then(response => {
this.getList()
})
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.el-table .cell {
white-space: nowrap !important;
}
/** style (注意不要设为scoped) */
/** configurationTable和afterRenderClass都是为了标记仅这个组件内修改 */
.configurationTable .el-table__body-wrapper {
overflow: auto;
}
.afterRenderClass {
.el-table__body-wrapper {
overflow: auto;
}
}
</style>

View File

@ -0,0 +1,258 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="收件人" width="60%" height="2200">
<el-tabs type="border-card" style="height: 610px;margin-top:-10px;margin-bottom:10px;" >
<el-tab-pane label="教师">
<teacherComplexTable ref="teacherComplexTable" :table-height="520 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane label="学生">
<studentComplexTable ref="studentComplexTable" :table-height="480 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button type="primary" @click="addUser">{{ $t('table.add') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
import studentComplexTable from '@/views/student/complexTable'
import teacherComplexTable from '@/views/teacher/complexTable'
const calendarTypeOptions = [
{ key: 'CN', display_name: 'China' },
{ key: 'US', display_name: 'USA' },
{ key: 'JP', display_name: 'Japan' },
{ key: 'EU', display_name: 'Eurozone' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ShowUser',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
components: {
studentComplexTable,
teacherComplexTable
},
data() {
return {
totalStuCount: 0,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
classId: undefined,
teacherName: undefined,
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
type: '',
status: 'published'
},
dialogFormVisible: true,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
downloadLoading: false,
userList: []
}
},
created() {
this.getList()
},
methods: {
addUser() {
this.userList = this.$refs.teacherComplexTable.getSelectUser().concat(this.$refs.studentComplexTable.getSelectUser())
this.dialogFormVisible = false
this.$emit('listenToChildEvent', this.userList)
},
getTotalStu: function(data) {
this.totalStuCount = data
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.items
this.total = response.data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus() {
this.dialogFormVisible = true
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
status: 'published',
type: ''
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
createArticle(this.temp).then(() => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(() => {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -3,47 +3,31 @@
<hamburger :toggle-click="toggleSideBar" :is-active="sidebar.opened" class="hamburger-container"/>
<breadcrumb class="breadcrumb-container"/>
<div class="right-menu">
<template v-if="device!=='mobile'">
<error-log class="errLog-container right-menu-item"/>
<el-tooltip :content="$t('navbar.screenfull')" effect="dark" placement="bottom">
<screenfull class="screenfull right-menu-item"/>
</el-tooltip>
<el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
<size-select class="international right-menu-item"/>
</el-tooltip>
<lang-select class="international right-menu-item"/>
<el-tooltip :content="$t('navbar.theme')" effect="dark" placement="bottom">
<theme-picker class="theme-switch right-menu-item"/>
</el-tooltip>
</template>
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<div class="avatar-wrapper">
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
<i class="el-icon-caret-bottom"/>
<div>
<span style="color: slategray;">{{ $store.state.user.name }}</span>
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<i style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<router-link to="/">
<el-dropdown-item>
{{ $t('navbar.dashboard') }}
</el-dropdown-item>
</router-link>
<router-link to="/">
<el-dropdown-item>
个人中心
</el-dropdown-item>
</router-link>
<el-dropdown-item divided>
<span style="display:block;" @click="logout">{{ $t('navbar.logOut') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/">
<el-dropdown-item>
{{ $t('navbar.dashboard') }}
</el-dropdown-item>
</router-link>
<a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">
<el-dropdown-item>
{{ $t('navbar.github') }}
</el-dropdown-item>
</a>
<el-dropdown-item divided>
<span style="display:block;" @click="logout">{{ $t('navbar.logOut') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</div>
</div>
</template>
@ -90,6 +74,31 @@ export default {
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.Botton {
display: inline-block;
text-align:center;
color: slategray;
}
.title {
position:absolute;
left:40%;
}
.item {
margin-top: -30px;
margin-right: 1px;
}
.el-badge__content.is-dot {
height: 10px !important;
width: 10px !important;
top: 12px !important;
}
.el-badge__content.is-fixed {
position: absolute;
top: 12px !important;
right: 10px;
-webkit-transform: translateY(-50%) translateX(100%);
transform: translateY(-50%) translateX(100%);
}
.navbar {
height: 50px;
line-height: 50px;

134
src/views/leave/create.vue Normal file
View File

@ -0,0 +1,134 @@
<template>
<div id="app">
<div class="fm-header">
<img class="fm-logo" src="./assets/logo.png">
<div class="fm-title">表单设计器</div>
<div style="color: #fff; font-size: 13px; position: absolute; top: 24px; left: 200px;">
QQ交流群902048874
</div>
<div class="fm-link">
<a href="https://github.com/GavinZhuLei/vue-form-making">GitHub</a>
<a href="https://gitee.com/gavinzhulei/vue-form-making">码云</a>
<a href="http://www.xiaoyaoji.cn" target="_blank">小幺鸡接口文档</a>
</div>
</div>
<div class="fm-container"><router-view/></div>
</div>
</template>
<script>
import FormMaking from 'form-making'
import 'form-making/dist/FormMaking.css'
export default {
name: 'CreateForm',
components: { FormMaking },
data() {
return {
hackReset: false,
disabled: false,
dialogFormVisible: false,
userList: [],
articleId: this.$route.params.id,
article: {
id: undefined,
fid: this.$store.state.user.fid,
title: undefined,
upload: 0,
type: '',
content: '',
group: undefined,
attachmentList: [],
receiverList: [],
status: 'published'
},
receiverList: [],
listQuery: {
fid: this.$store.state.user.fid,
importance: undefined,
name: undefined,
type: undefined,
sort: '+id'
},
input: '',
users: undefined,
groups: undefined,
value7: '',
rules: {
title: [
{ required: true, message: '请输入标题', trigger: 'blur' },
{ min: 4, max: 50, message: '长度必须在4到50个字符之间', trigger: 'blur' }
]
}
}
},
created() {
this.fetchArticle()
},
methods: {
handleDeleteUser(index) {
this.article.receiverList.splice(index, 1)
},
getSelectUser: function(data) {
var tempList = []
var userList = data.get('user')
for (var index in userList) {
var userReceiver = {}
userReceiver.uid = userList[index].uid
userReceiver.name = userList[index].name
userReceiver.roles = [1]
tempList.push(userReceiver)
}
var groupList = data.get('group')
for (var i in groupList) {
var groupReceiver = {}
groupReceiver.uid = groupList[i].groupId
groupReceiver.name = groupList[i].name
groupReceiver.roles = [3]
tempList.push(groupReceiver)
}
for (const v of tempList) {
var flag = true
for (const userData of this.article.receiverList) {
if (v.uid === userData.uid && v.roles[0] === userData.roles[0]) {
flag = false
break
}
}
if (flag) {
this.article.receiverList.push(v)
}
}
},
showSelectUser() {
this.dialogFormVisible = true
},
selectUser() {
this.hackReset = false
if (this.$refs.showUser) {
this.$refs.showUser.handleModifyStatus()
}
this.$nextTick(() => {
this.hackReset = true
})
},
ready(editorInstance) {
console.log(`编辑器实例${editorInstance.key}: `, editorInstance)
// setInterval(this.getUEContent,10000)
},
getUEContent: function() {
console.log(this.msg)
},
draft: function() {
console.log(this.msg)
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,130 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="请假" width="40%">
<el-form ref="ruleForm" :model="ruleForm" :rules="rules" style="magin-top:-100px;" label-width="100px" class="demo-ruleForm">
<el-form-item label="请假类型">
<el-select v-model="ruleForm.type" class="filter-item" style="width:90%;">
<el-option v-for="item in leaveTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item label="开始时间" required>
<el-col style="width:60%;">
<el-form-item prop="date1">
<el-date-picker v-model="ruleForm.date1" type="date" placeholder="选择日期" style="width: 100%;"/>
</el-form-item>
</el-col>
<el-col style="width:30%;">
<el-form-item>
<el-select v-model="ruleForm.region" placeholder="请选择活动区域" style="magin-left:20px;">
<el-option label="上午" value="0"/>
<el-option label="下午" value="1/"/>
</el-select>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="结束时间" required>
<el-col style="width:60%;">
<el-form-item prop="date1">
<el-date-picker v-model="ruleForm.date1" type="date" placeholder="选择日期" style="width: 100%;"/>
</el-form-item>
</el-col>
<el-col style="width:30%;">
<el-form-item>
<el-select v-model="ruleForm.region" placeholder="请选择活动区域">
<el-option label="上午" value="0"/>
<el-option label="下午" value="1/"/>
</el-select>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="时长" prop="name">
<el-input v-model="ruleForm.name" style="width:90%;"/>
</el-form-item>
<el-form-item label="请假事由" prop="desc">
<el-input v-model="ruleForm.desc" type="textarea" style="width:90%;"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</div>
</el-dialog>
</template>
<script>
import waves from '@/directive/waves' //
const leaveTypeOptions = [
{ key: 0, display_name: '事假' },
{ key: 1, display_name: '年假' },
{ key: 2, display_name: '病假' },
{ key: 3, display_name: '产假' },
{ key: 4, display_name: '陪产假' },
{ key: 5, display_name: '婚假' },
{ key: 6, display_name: '丧假' }
]
export default {
name: 'ComplexTable',
directives: {
waves
},
data() {
return {
dialogFormVisible: false,
leaveTypeOptions,
ruleForm: {
name: '',
region: '0',
date1: '',
date2: '',
delivery: false,
type: 0,
resource: '',
desc: ''
},
rules: {
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
],
region: [
{ required: true, message: '请选择活动区域', trigger: 'change' }
],
date1: [
{ type: 'date', required: true, message: '请选择日期', trigger: 'change' }
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' }
],
type: [
{ type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
],
resource: [
{ required: true, message: '请选择活动资源', trigger: 'change' }
],
desc: [
{ required: true, message: '请填写活动形式', trigger: 'blur' }
]
}
}
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
alert('submit!')
} else {
console.log('error submit!!')
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
showEditDialog() {
this.dialogFormVisible = true
}
}
}
</script>

234
src/views/leave/list.vue Normal file
View File

@ -0,0 +1,234 @@
<template>
<div class="app-container">
<div class="filter-container" style="float:right; margin-top:-10px;">
<el-button class="filter-item" style="margin-right: 10px;" type="primary" icon="el-icon-edit" @click="createLeave()">新建</el-button>
</div>
<div style="margin-top:-10px">
<el-table v-loading.body="listLoading" :show-overflow-tooltip="true" :data="list" border fit highlight-current-row style="width: 100%">
<el-table-column align="center" label="ID" width="80">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column align="left" width="150px" label="发布者">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column width="200px" align="center" label="发布时间">
<template slot-scope="scope">
<span>{{ scope.row.modifyTime }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" max-width="500px" align="left" label="标题">
<template slot-scope="scope">
<router-link :to="'/leave/'+scope.row.id" class="link-type" target="_blank">
<span>{{ scope.row.title }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column width="300px" align="left" label="附件">
<template slot-scope="scope">
<span v-if="scope.row.articleAttachment && scope.row.articleAttachment.attachmentName" class="el-tag el-tag--info el-tag--small">
<a class="link-type" @click="download(scope.row.articleAttachment.url, scope.row.articleAttachment.attachmentName)">{{ scope.row.articleAttachment.attachmentName }}</a>
<i class="el-tag__close el-icon-close" @click="deleteAttachment(scope.row)"/>
</span>
</template>
</el-table-column>
<el-table-column :label="$t('action')" align="center" width="150">
<template slot-scope="scope">
<el-button style="margin:5px;float:right">
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<i style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<router-link :to="'/leave/edit/'+scope.row.id">
<el-dropdown-item>
{{ $t('edit') }}
</el-dropdown-item>
</router-link>
<el-dropdown-item v-if="scope.row.upload===1" divided>
<span style="display:block;" @click="showUploadData(scope.row)"> </span>
</el-dropdown-item>
<el-dropdown-item divided>
<span style="display:block;" @click="deleteArticle(scope.row)">{{ $t('delete') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-button>
<el-upload
v-if="scope.row.upload===1"
:action="importFileUrl"
:on-remove="handleRemove"
:data="uploadData"
:on-preview="handlePreview"
:on-exceed="handleExceed"
:on-success="handleSuccess"
:file-list="scope.row.attachmentList"
:show-file-list="false"
style="float:left;margin:5px;"
name="file"
><el-button size="mini" @click="handleUpdate(scope.row)"><i class="el-icon-upload el-icon--right"/>上传</el-button>
</el-upload>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
:current-page="listQuery.page"
:page-sizes="[10,20,30, 50]"
:page-size="listQuery.limit"
:total="total"
background
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"/>
</div>
</div>
<leaveEdit ref="leaveEdit"/>
</div>
</template>
<script>
import { fetchList, deleteArticle } from '@/api/article'
import { downloadFile, deleteAttachment } from '@/api/user'
import leaveEdit from '@/views/leave/leaveEdit'
export default {
name: 'ArticleList',
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
components: {
leaveEdit
},
data() {
return {
importFileUrl: window.UEDITOR_HOME_URL + 'ueditor/importFile',
uploadData: {
noticeId: undefined
},
attachmentList: [
{ name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100' }],
list: null,
total: 0,
limit: 1,
flag: false,
count: 123,
rowIndex: undefined,
showReviewer: false,
dialogPvVisible: false,
listLoading: true,
listQuery: {
fid: this.$store.getters.user.fid,
page: 1,
limit: 20
},
selectRow: undefined
}
},
created() {
this.getList()
},
methods: {
createLeave() {
this.$refs.leaveEdit.showEditDialog()
},
deleteArticle(row) {
deleteArticle(row.id).then(() => {
fetchList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}).catch((error) => {
alert(error)
})
})
},
download(url, name) {
downloadFile(url, name)
},
showUploadData(item) {
this.$refs.leaveEdit.handleModifyStatus(item)
},
deleteAttachment(row) {
this.$confirm('您确定删除吗?').then(_ => {
deleteAttachment(row.articleAttachment).then(() => {
row.articleAttachment = undefined
})
}).catch(_ => {
})
},
handleUpdate(row) {
this.uploadData.noticeId = row.id
this.selectRow = row
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}).catch((error) => {
alert(error)
})
},
handleRemove(file, attachmentList) {
alert(file, attachmentList)
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
showDetail() {
this.flag = !this.flag
},
handlePreview(file) {
this.$message.warning(`file url = ` + file.url)
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleSuccess(response, file, attachmentList) {
if (response == null) {
return
}
this.selectRow.attachmentList = []
this.selectRow.articleAttachment = response
this.showReviewer = true
},
handleExceed(files, attachmentList) {
this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + attachmentList.length} 个文件`)
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
.demo-block {
border: 1px solid #ebebeb;
border-radius: 3px;
transition: .2s;
margin:20px;
}
</style>

228
src/views/leave/show.vue Normal file
View File

@ -0,0 +1,228 @@
<template>
<div class="app-container">
<span v-html="message"/>
</div>
</template>
<script>
import { fetchArticle } from '@/api/article'
export default {
name: 'Show',
data() {
return {
message: undefined
}
},
created() {
this.fetchArticle()
},
methods: {
fetchArticle() {
this.listLoading = true
fetchArticle(this.$route.params.id).then(response => {
if (response.data.code === 200) {
this.message = response.data.result.content
}
this.listLoading = false
})
}
}
}
</script>
<style rel="stylesheet/scss" 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>

View File

@ -0,0 +1,270 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="收件人" width="60%" height="2200">
<el-tabs type="border-card" style="height: 630px;margin-top:-30px;margin-bottom:10px;" >
<el-tab-pane label="教师">
<teacherComplexTable ref="teacherComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane v-if="false" label="班级">
<gradeComplexTable ref="gradeComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane v-if="false" label="群组">
<groupComplexTable ref="groupComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button type="primary" @click="addUser">{{ $t('table.add') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
import groupComplexTable from '@/views/group/index'
import studentComplexTable from '@/views/student/complexTable'
import teacherComplexTable from '@/views/teacher/complexTable'
import gradeComplexTable from '@/views/grade/complexTable'
const calendarTypeOptions = [
{ key: 'CN', display_name: 'China' },
{ key: 'US', display_name: 'USA' },
{ key: 'JP', display_name: 'Japan' },
{ key: 'EU', display_name: 'Eurozone' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ShowUser',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
components: {
groupComplexTable,
studentComplexTable,
teacherComplexTable,
gradeComplexTable
},
data() {
return {
totalStuCount: 0,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
classId: undefined,
teacherName: undefined,
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
type: '',
status: 'published'
},
dialogFormVisible: true,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
downloadLoading: false,
userList: []
}
},
created() {
this.getList()
},
methods: {
addUser() {
var map = new Map()
map.set('user', this.$refs.teacherComplexTable.getSelectUser())
// map.set('class', this.$refs.gradeComplexTable.getSelectClass())
// map.set('group', this.$refs.groupComplexTable.getSelectGroup())
// this.userList = this.$refs.teacherComplexTable.getSelectUser().concat(this.$refs.studentComplexTable.getSelectUser())
this.dialogFormVisible = false
this.$emit('listenToChildEvent', map)
},
getTotalStu: function(data) {
this.totalStuCount = data
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.items
this.total = response.data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus() {
this.dialogFormVisible = true
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
status: 'published',
type: ''
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
createArticle(this.temp).then(() => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(() => {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -1,15 +1,26 @@
<template>
<div class="login-container">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form card-box" auto-complete="on" label-position="left">
<div class="title-container">
<h3 class="title">{{ $t('login.title') }}</h3>
<lang-select class="set-language"/>
<h3 class="title">登录</h3>
</div>
<el-form-item v-if="false">
<span class="svg-container svg-container_login">
<svg-icon icon-class="school" />
</span>
<el-input
v-model="loginForm.fid"
placeholder="学校名称"
name="fid"
type="text"
auto-complete="on"
/>
</el-form-item>
<el-form-item prop="username">
<span class="svg-container">
<span class="svg-container svg-container_login">
<svg-icon icon-class="user" />
</span>
<el-input
@ -39,21 +50,9 @@
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">{{ $t('login.logIn') }}</el-button>
<div style="position:relative">
<div class="tips">
<span>{{ $t('login.username') }} : admin</span>
<span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
</div>
<div class="tips">
<span style="margin-right:18px;">{{ $t('login.username') }} : editor</span>
<span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
</div>
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">{{ $t('login.thirdparty') }}</el-button>
</div>
</el-form>
<el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog">
<el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog" append-to-body>
{{ $t('login.thirdpartyTips') }}
<br>
<br>
@ -65,7 +64,6 @@
</template>
<script>
import { isvalidUsername } from '@/utils/validate'
import LangSelect from '@/components/LangSelect'
import SocialSign from './socialsignin'
@ -74,23 +72,24 @@ export default {
components: { LangSelect, SocialSign },
data() {
const validateUsername = (rule, value, callback) => {
if (!isvalidUsername(value)) {
callback(new Error('Please enter the correct user name'))
if (value.match(/^[ ]*$/)) {
callback(new Error('用户名错误'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
if (value.length < 6 || value.match(/^[ ]*$/)) {
callback(new Error('密码错误'))
} else {
callback()
}
}
return {
loginForm: {
username: 'admin',
password: '1111111'
username: undefined,
password: undefined,
fid: undefined
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
@ -129,6 +128,7 @@ export default {
if (valid) {
this.loading = true
this.$store.dispatch('LoginByUsername', this.loginForm).then(() => {
sessionStorage.setItem('store', JSON.stringify(this.$store.state))
this.loading = false
this.$router.push({ path: this.redirect || '/' })
}).catch(() => {
@ -166,9 +166,9 @@ export default {
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#eee;
$cursor: #fff;
$bg:#f4f3f3;
$light_gray:#8e928d;
$cursor: #050505;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input{
@ -193,7 +193,7 @@ export default {
padding: 12px 5px 12px 15px;
color: $light_gray;
height: 47px;
caret-color: $cursor;
// caret-color: $cursor;
&:-webkit-autofill {
-webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
@ -204,7 +204,7 @@ export default {
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
color: #454545;
// color: #454545;
}
}
</style>
@ -217,7 +217,7 @@ $light_gray:#eee;
.login-container {
min-height: 100%;
width: 100%;
background-color: $bg;
background: left top #f4f3f3;
overflow: hidden;
.login-form {
position: relative;
@ -248,7 +248,7 @@ $light_gray:#eee;
position: relative;
.title {
font-size: 26px;
color: $light_gray;
color: #333333;
margin: 0px auto 40px auto;
text-align: center;
font-weight: bold;
@ -274,5 +274,18 @@ $light_gray:#eee;
right: 0;
bottom: 6px;
}
.card-box {
padding:20px;
margin-top: 200px !important;
box-shadow:0 0px 8px 0 rgba(0,0,0,0.06),0 1px 0px 0 rgba(0,0,0,0.02);
-webkit-border-radius:5px;
border-radius:5px;
-moz-border-radius:5px;
background-clip:padding-box;
margin-bottom:20px;
background-color:#ffffff;
}
}
</style>

View File

@ -0,0 +1,10 @@
<template>
<div class="app-container">
发发发
</div>
</template>
<script>
</script>

View File

@ -0,0 +1,300 @@
<template>
<div class="app-container">
<el-table
v-loading="listLoading"
:key="tableKey"
:data="list"
border
fit
highlight-current-row
style="width: 100%;min-height:300px;">
<el-table-column :label="$t('table.id')" align="center" width="65">
<template slot-scope="scope">
<span>{{ scope.$index+1 }}</span>
</template>
</el-table-column>
<el-table-column label="年级名称" width="150px" align="center">
<template slot-scope="scope">
<el-tooltip placement="left" effect="light">
<div slot="content">{{ scope.row.showName }}</div>
<span>{{ scope.row.name }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="执教班级" min-width="150px">
<template slot-scope="scope">
<span v-for="item in scope.row.clazzList" :key="item.id" class="el-tag el-tag--info el-tag--small" style="margin-left:5px;">
<span class="link-type" @click="handleEditClass(item)">{{ item.name }}(班主任:{{ item.teacher.name }})</span>
</span>
</template>
</el-table-column>
<el-table-column label="执教科目" min-width="200px" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.graduationStatus==1" type="info"> 已毕业</el-tag>
<el-tag v-else>在读</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button v-if="$store.state.user.admin" type="primary" size="mini" @click="handleUpdate(scope.row, scope.$index, false)">{{ $t('table.edit') }}</el-button>
<el-button size="mini" type="success" @click="handleUpdate(scope.row, scope.$index, true)">查看</el-button>
<el-button v-if="$store.state.user.admin" size="mini" type="danger" @click="deleteGrade(scope.row)">{{ $t('table.delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
<el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
<el-form-item :label="$t('table.type')" prop="type">
<el-select v-model="temp.type" class="filter-item" placeholder="Please select">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('table.date')" prop="timestamp">
<el-date-picker v-model="temp.timestamp" type="datetime" />
</el-form-item>
<el-form-item :label="$t('table.title')" prop="title">
<el-input v-model="temp.title"/>
</el-form-item>
<el-form-item :label="$t('table.status')">
<el-select v-model="temp.status" class="filter-item" >
<el-option v-for="item in statusOptions" :key="item" :label="item" :value="item"/>
</el-select>
</el-form-item>
<el-form-item :label="$t('table.importance')">
<el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;"/>
</el-form-item>
<el-form-item :label="$t('table.remark')">
<el-input :autosize="{ minRows: 2, maxRows: 4}" v-model="temp.remark" type="textarea"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">{{ $t('table.confirm') }}</el-button>
<el-button v-else type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
<el-table :data="pvData" border fit highlight-current-row style="width: 100%">
<el-table-column prop="key" label="Channel"/>
<el-table-column prop="pv" label="Pv"/>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
</span>
</el-dialog>
<edit-grade ref="editGrade" @listenToChildEvent="updateGradeRow"/>
<edit-class ref="showClass"/>
</div>
</template>
<script>
import { createArticle, updateArticle } from '@/api/article'
import { fetchGradeList, deleteGrade } from '@/api/user'
import waves from '@/directive/waves' //
import editClass from '@/views/grade/editClass'
import editGrade from '@/views/grade/editGrade'
import { parseTime } from '@/utils'
export default {
name: 'ComplexTable',
directives: {
waves
},
components: {
editClass,
editGrade
},
props: {
teacherId: {
type: String,
default: undefined
}
},
data() {
return {
hackReset: true,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
fid: this.$store.state.user.fid,
name: undefined,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
importanceOptions: [1, 2, 3],
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
type: '',
status: 'published'
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
classId: undefined,
downloadLoading: false
}
},
created() {
this.getList()
},
methods: {
updateGradeRow: function(rowData, index) {
if (index > -1) {
this.list.splice(index, 1, rowData)
} else {
this.list.unshift(rowData)
}
},
getList() {
this.listLoading = true
fetchGradeList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, status) {
this.$message({
message: '操作成功',
type: 'success'
})
row.status = status
},
deleteGrade(row) {
deleteGrade(row.id).then(response => {
fetchGradeList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
})
})
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
status: 'published',
type: ''
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
createArticle(this.temp).then(response => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row, index, disabled) {
this.$refs.editGrade.handleModifyStatus(row, index, disabled)
},
handleEditClass(item) {
if (this.$refs.showClass) {
this.$refs.showClass.handleModifyStatus(item)
}
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(() => {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -0,0 +1,71 @@
<template>
<div id="app">
<complexTable ref="complexTable" :type="false" :table-height="600 + 'px'" :class-id="classId" @listenToChildEvent="getTotalStu"/>
<div>
<el-tag>班主任 {{ teacherName }}</el-tag>
</div>
</div>
</template>
<script>
import complexTable from '@/views/student/complexTable'
export default {
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
components: {
complexTable
},
props: {
classId: {
type: Number,
default: undefined
},
teacherName: {
type: String,
default: undefined
}
},
data() {
return {
total: null,
importanceOptions: [1, 2, 3],
calendarTypeOptions: [
{ key: '1', display_name: '县外' },
{ key: '2', display_name: '镇外' },
{ key: '3', display_name: '凉森村' },
{ key: '4', display_name: '跃进村' }
],
listQuery: {
classId: this.classId,
fid: this.$store.state.user.fid,
sort: '+id'
},
loading: false
}
},
created() {
// this.getList()
},
methods: {
getTotalStu: function(data) {
this.total = data
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleCreate() {
}
}
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<div class="tab-container">
<el-tabs v-model="activeName" style="margin-top:15px;" type="border-card">
<el-tab-pane label="执教班级" name="first">
<complexTable :teacher-id="uid"/>
</el-tab-pane>
<el-tab-pane label="课程表" name="second">
<scheduleTab :teacher-id="uid" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import tabPane from './components/tabPane'
import complexTable from './components/complexTable'
import scheduleTab from '@/views/grade/scheduleTab'
export default {
name: 'Tab',
components: {
tabPane,
scheduleTab,
complexTable
},
data() {
return {
classList: '',
activeName: 'first',
uid: this.$store.getters.user.uid,
listQuery: {
uid: this.$store.getters.user.uid
}
}
},
created() {
},
methods: {
}
}
</script>
<style scoped>
.tab-container{
margin: 15px;
}
</style>

View File

@ -0,0 +1,50 @@
<template>
<div class="bdsharebuttonbox bdshare-button-style0-16">
<a href="#" class="bds_more" data-cmd="more"/>
<a href="#" class="bds_qzone" data-cmd="qzone"/>
<a href="#" class="bds_tsina" data-cmd="tsina"/>
<a href="#" class="bds_tqq" data-cmd="tqq"/>
<a href="#" class="bds_renren" data-cmd="renren"/>
<a href="#" class="bds_weixin" data-cmd="weixin"/>
</div>
</template>
<script>
export default {
beforeCreate() {
const _this = this
setTimeout(() => {
_this.setup()
}, 0)
},
methods: {
setup() {
window._bd_share_config = {
common: {
bdSnsKey: {},
bdText: '',
bdMini: '2',
bdPic: '',
bdStyle: '0',
bdSize: '16'
},
share: {},
image: {
viewList: ['qzone', 'tsina', 'tqq', 'renren', 'weixin'],
viewText: '分享到:',
viewSize: '16'
},
selectShare: {
bdContainerClass: null,
bdSelectMiniList: ['qzone', 'tsina', 'tqq', 'renren', 'weixin']
}
}
const s = document.createElement('script')
s.type = 'text/javascript'
s.src =
'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' +
~(-new Date() / 36e5)
document.body.appendChild(s)
}
}
}
</script>

236
src/views/notice/list.vue Normal file
View File

@ -0,0 +1,236 @@
<template>
<div class="app-container">
<div v-if="flag">
<div id="dg" style="position: fixed;right: 20px;bottom: 50px;">
<el-button style="margin-left: 10px;" type="mini" size="small" @click="showDetail">返回</el-button>
</div>
<div style="margin-top:-20px;">
<span v-html="list[2].content"/>
</div>
</div>
<div v-if="!flag">
<el-table v-loading.body="listLoading" :show-overflow-tooltip="true" :data="list" border fit highlight-current-row style="width: 100%">
<el-table-column align="center" label="ID" width="80">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column align="left" width="150px" label="发布者">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column width="200px" align="center" label="发布时间">
<template slot-scope="scope">
<span>{{ scope.row.modifyTime }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" max-width="500px" align="left" label="标题">
<template slot-scope="scope">
<router-link :to="{path: '/notice/'+scope.row.articleId}" class="link-type" target="_blank">
<span>{{ scope.row.title }}</span>
</router-link>
</template>
</el-table-column>
<el-table-column width="300px" align="left" label="附件">
<template slot-scope="scope">
<span v-if="scope.row.articleAttachment && scope.row.articleAttachment.attachmentName" class="el-tag el-tag--info el-tag--small">
<a class="link-type" @click="download(scope.row.articleAttachment.url, scope.row.articleAttachment.attachmentName)">{{ scope.row.articleAttachment.attachmentName }}</a>
<i class="el-tag__close el-icon-close" @click="deleteAttachment(scope.row)"/>
</span>
</template>
</el-table-column>
<el-table-column :label="$t('action')" align="center" width="150">
<template slot-scope="scope">
<el-button style="margin:5px;float:right">
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<i style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<router-link :to="'/notice/edit/'+scope.row.articleId">
<el-dropdown-item>
{{ $t('edit') }}
</el-dropdown-item>
</router-link>
<el-dropdown-item divided>
<span style="display:block;" @click="showUploadData(scope.row)"> </span>
</el-dropdown-item>
<el-dropdown-item divided>
<span style="display:block;" @click="deleteArticle(scope.row)">{{ $t('delete') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-button>
<el-upload
v-if="scope.row.upload===1"
:action="importFileUrl"
:on-remove="handleRemove"
:data="uploadData"
:on-preview="handlePreview"
:on-exceed="handleExceed"
:on-success="handleSuccess"
:file-list="scope.row.attachmentList"
:show-file-list="false"
style="float:left;margin:5px;"
name="file"
><el-button size="mini" @click="handleUpdate(scope.row)"><i class="el-icon-upload el-icon--right"/>上传</el-button>
</el-upload>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
:current-page="listQuery.page"
:page-sizes="[10,20,30, 50]"
:page-size="listQuery.limit"
:total="total"
background
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"/>
</div>
</div>
<uploadUser ref="uploadUser"/>
</div>
</template>
<script>
import { fetchList, deleteArticle } from '@/api/article'
import { downloadFile, deleteAttachment } from '@/api/user'
import uploadUser from '@/views/notice/uploadUser'
export default {
name: 'ArticleList',
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
components: {
uploadUser
},
data() {
return {
importFileUrl: window.UEDITOR_HOME_URL + 'ueditor/importFile',
uploadData: {
noticeId: undefined
},
attachmentList: [
{ name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100' }],
list: null,
total: 0,
limit: 1,
flag: false,
count: 123,
rowIndex: undefined,
showReviewer: false,
dialogPvVisible: false,
listLoading: true,
listQuery: {
fid: this.$store.getters.user.fid,
page: 1,
limit: 20
},
selectRow: undefined
}
},
created() {
this.getList()
},
methods: {
deleteArticle(row) {
deleteArticle(row.id).then(() => {
fetchList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}).catch((error) => {
alert(error)
})
})
},
download(url, name) {
downloadFile(url, name)
},
showUploadData(item) {
this.$refs.uploadUser.handleModifyStatus(item)
},
deleteAttachment(row) {
this.$confirm('您确定删除吗?').then(_ => {
deleteAttachment(row.articleAttachment).then(() => {
row.articleAttachment = undefined
})
}).catch(_ => {
})
},
handleUpdate(row) {
this.uploadData.noticeId = row.id
this.selectRow = row
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}).catch((error) => {
alert(error)
})
},
handleRemove(file, attachmentList) {
alert(file, attachmentList)
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
showDetail() {
this.flag = !this.flag
},
handlePreview(file) {
this.$message.warning(`file url = ` + file.url)
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleSuccess(response, file, attachmentList) {
if (response == null) {
return
}
this.selectRow.attachmentList = []
this.selectRow.articleAttachment = response
this.showReviewer = true
},
handleExceed(files, attachmentList) {
this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + attachmentList.length} 个文件`)
}
}
}
</script>
<style scoped>
.edit-input {
padding-right: 100px;
}
.cancel-btn {
position: absolute;
right: 15px;
top: 10px;
}
.demo-block {
border: 1px solid #ebebeb;
border-radius: 3px;
transition: .2s;
margin:20px;
}
</style>

266
src/views/notice/show.vue Normal file
View File

@ -0,0 +1,266 @@
<template>
<div class="app-container cuhksz-detail">
<div class="caption-3_nUnnKX">
<h1 class="topic-_XJ6ViSR">{{ notice.title }}</h1>
<p><span class="date-3fxruanH">发布时间: &nbsp; {{ notice.createTime }}</span><span class="source-1Pn6hUH2">&nbsp;&nbsp;发布人:&nbsp;{{ notice.name }}</span></p>
</div>
<span v-html="message"/>
</div>
</template>
<script>
import { fetchArticle } from '@/api/article'
export default {
name: 'Show',
data() {
return {
notice: {
title: undefined,
createTime: undefined,
name: undefined
},
message: undefined
}
},
created() {
this.fetchArticle()
},
methods: {
fetchArticle() {
this.listLoading = true
fetchArticle(this.$route.params.id).then(response => {
if (response.data.code === 200) {
this.notice = response.data.result
this.message = response.data.result.content
}
this.listLoading = false
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.date-3fxruanH, .source-1Pn6hUH2 {
font: 14px Microsoft YaHei;
color: #999;
margin-right: 10px;
}
.topic-_XJ6ViSR {
text-align: center;
font: 32px Microsoft YaHei;
color: #222;
}
p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
}
.caption-3_nUnnKX {
position: relative;
padding: 40px 0 10px;
border-bottom: 1px solid #e2e2e2;
}
.cuhksz-detail {
max-width:1000px;
margin:0 auto;
position:relative;
overflow:visible;
}
.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>

View File

@ -0,0 +1,270 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="收件人" width="60%" height="2200">
<el-tabs type="border-card" style="height: 610px;margin-top:-10px;margin-bottom:10px;" >
<el-tab-pane label="教师">
<teacherComplexTable ref="teacherComplexTable" :table-height="520 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane v-if="false" label="班级">
<gradeComplexTable ref="gradeComplexTable" :table-height="450 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
<el-tab-pane label="群组">
<groupComplexTable ref="groupComplexTable" :table-height="430 + 'px'" :type="false" style="margin-top:-20px;"/>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button type="primary" @click="addUser">{{ $t('table.add') }}</el-button>
</div>
</el-dialog>
</template>
<script>
import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
import groupComplexTable from '@/views/group/index'
import studentComplexTable from '@/views/student/complexTable'
import teacherComplexTable from '@/views/teacher/complexTable'
import gradeComplexTable from '@/views/grade/complexTable'
const calendarTypeOptions = [
{ key: 'CN', display_name: 'China' },
{ key: 'US', display_name: 'USA' },
{ key: 'JP', display_name: 'Japan' },
{ key: 'EU', display_name: 'Eurozone' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ShowUser',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
components: {
groupComplexTable,
studentComplexTable,
teacherComplexTable,
gradeComplexTable
},
data() {
return {
totalStuCount: 0,
tableKey: 0,
list: null,
total: null,
listLoading: true,
listQuery: {
page: 1,
limit: 20,
importance: undefined,
title: undefined,
type: undefined,
sort: '+id'
},
classId: undefined,
teacherName: undefined,
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: ['published', 'draft', 'deleted'],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
type: '',
status: 'published'
},
dialogFormVisible: true,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
title: [{ required: true, message: 'title is required', trigger: 'blur' }]
},
downloadLoading: false,
userList: []
}
},
created() {
this.getList()
},
methods: {
addUser() {
var map = new Map()
map.set('user', this.$refs.teacherComplexTable.getSelectUser())
// map.set('class', this.$refs.gradeComplexTable.getSelectClass())
map.set('group', this.$refs.groupComplexTable.getSelectGroup())
// this.userList = this.$refs.teacherComplexTable.getSelectUser().concat(this.$refs.studentComplexTable.getSelectUser())
this.dialogFormVisible = false
this.$emit('listenToChildEvent', map)
},
getTotalStu: function(data) {
this.totalStuCount = data
},
getList() {
this.listLoading = true
fetchList(this.listQuery).then(response => {
this.list = response.data.items
this.total = response.data.total
// Just to simulate the time of the request
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus() {
this.dialogFormVisible = true
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
title: '',
status: 'published',
type: ''
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
this.temp.author = 'vue-element-admin'
createArticle(this.temp).then(() => {
this.list.unshift(this.temp)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
this.temp.timestamp = new Date(this.temp.timestamp)
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const tempData = Object.assign({}, this.temp)
tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
updateArticle(tempData).then(() => {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -0,0 +1,435 @@
<template>
<el-dialog :visible.sync="dialogFormVisible" title="上传信息">
<el-tabs tab-position="top" style="height: 500px;margin-top:-30px;">
<el-tab-pane :label="'已上传('+submittedtotal + '人)'">
<div class="filter-container">
<el-input v-model="listQuery.name" placeholder="姓名" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-download" @click="downloadZip">批量下载</el-button>
</div>
<el-table
v-loading="listLoading"
:key="tableKey"
:data="submittedlist"
:show-overflow-tooltip="true"
:height="400"
border
style="width:100%; 100px;"
highlight-current-row>
<el-table-column :label="$t('table.id')" align="center" width="60px">
<template slot-scope="scope">
<span>{{ scope.$index+1 }}</span>
</template>
</el-table-column>
<el-table-column label="姓名" width="150px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.userName }}</span>
</template>
</el-table-column>
<el-table-column label="上传时间" width="180px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.createTime }}</span>
</template>
</el-table-column>
<el-table-column label="附件" min-width="250px">
<template slot-scope="scope">
<span>{{ scope.row.attachmentName }}</span>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane :label="'未上传('+uncommittedtotal + '人)'">
<div class="filter-container">
<el-input v-model="listQuery.name" placeholder="姓名" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
</div>
<el-table
v-loading="listLoading"
:key="tableKey"
:data="uncommittedlist"
:show-overflow-tooltip="true"
:height="400"
border
style="width:100%; 100px;"
highlight-current-row>
<el-table-column :label="$t('table.id')" align="center" width="60px">
<template slot-scope="scope">
<span>{{ scope.$index+1 }}</span>
</template>
</el-table-column>
<el-table-column label="姓名" width="150px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.userName }}</span>
</template>
</el-table-column>
<el-table-column label="上传时间" width="180px" align="center">
<template slot-scope="scope">
<span/>
</template>
</el-table-column>
<el-table-column label="附件" min-width="250px">
<template slot-scope="scope">
<span/>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogFormVisible = false">{{ $t('table.confirm') }}</el-button>
</span>
</el-dialog>
</template>
<script>
import { fetchPv } from '@/api/article'
import { fetchUploadUserList, updateStudent, createStudent, downloadZip } from '@/api/user'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
const calendarTypeOptions = [
{ key: 'CN', display_name: 'China' },
{ key: 'US', display_name: 'USA' },
{ key: 'JP', display_name: 'Japan' },
{ key: 'EU', display_name: 'Eurozone' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
props: {
type: {
type: Boolean,
default: true
},
tableHeight: {
type: String,
default: '100%'
},
classId: {
type: Number,
default: undefined
}
},
data() {
return {
tableKey: 0,
submittedlist: [],
uncommittedlist: [],
submittedtotal: 0,
uncommittedtotal: 0,
fid: this.$store.state.user.fid,
listLoading: true,
articleName: undefined,
listQuery: {
id: undefined
},
formLabelAlign: {
name: '',
tel: '',
role: ''
},
importanceOptions: [1, 2, 3],
calendarTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: [{ name: '在读', id: 1 }, { name: '转学', id: 0 }],
showReviewer: true,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
class: undefined,
name: undefined,
user: undefined,
parentStuList: [],
selectedOptions2: undefined,
status: undefined
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
gradeList: undefined,
props: {
label: 'name',
value: 'id',
children: 'clazzList'
},
dialogPvVisible: false,
pvData: [],
rules: {
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
stuNo: [{ required: true, message: '学号不能为空', trigger: 'blur' }]
},
downloadLoading: false
}
},
methods: {
resetParent() {
this.formLabelAlign = {
name: undefined,
role: undefined,
tel: undefined,
fid: this.fid,
visiblePopover: true
}
},
createParent() {
this.resetParent()
},
updateParent(index) {
this.$refs['popoverForm'].validate((valid) => {
if (valid) {
if (index > -1) {
this.formLabelAlign.visiblePopover = false
this.temp.parentStuList.splice(index, 1, this.formLabelAlign)
} else {
this.formLabelAlign.visiblePopover = false
this.temp.parentStuList.push(this.formLabelAlign)
}
}
})
},
editParent(item) {
this.formLabelAlign = JSON.parse(JSON.stringify(item))
item.visiblePopover = true
this.$nextTick(() => {
this.$refs['popoverForm'].clearValidate()
})
},
downloadZip() {
downloadZip(this.submittedlist[0].noticeId, this.articleName)
},
getList() {
this.listLoading = true
fetchUploadUserList(this.listQuery).then(response => {
this.submittedlist = []
this.uncommittedlist = []
if (response.data.code === 200) {
var result = response.data.result
for (var index in response.data.result) {
if (result[index].attachmentName) {
this.submittedlist.push(result[index])
} else {
this.uncommittedlist.push(result[index])
}
}
}
this.submittedtotal = this.submittedlist.length
this.uncommittedtotal = this.uncommittedlist.length
this.listLoading = false
})
},
deleteParent(index) {
this.temp.parentStuList.splice(index, 1)
},
handleChange(value) {
if (this.temp.clazz == null) {
this.temp.clazz = {}
}
if (value != null && value.length > 1) {
this.temp.clazz.id = value[1]
} else {
this.temp.clazz.id = null
}
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row) {
this.listQuery.id = row.id
this.articleName = row.title
this.getList()
this.dialogFormVisible = true
},
resetTemp() {
this.temp = {
id: undefined,
graduationStatus: 1,
enrollmentDate: new Date(),
user: undefined,
name: undefined,
status: 1,
parentStuList: [],
address: undefined
}
},
handleCreate() {
this.resetTemp()
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
if (this.temp.user == null) {
this.temp.user = {}
}
if (this.temp.clazz == null) {
this.temp.clazz = {}
}
this.temp.enrollmentDate = parseTime(this.temp.enrollmentDate, '{y}-{m}-{d}')
this.temp.user.name = this.temp.name
this.temp.user.loginName = this.temp.name
this.temp.user.sex = this.temp.sex
this.temp.user.fid = this.fid
this.temp.user.status = 1
this.temp.user.address = this.temp.address
this.temp.user.roles = 2
createStudent(this.temp).then(response => {
if (response.data.code === 200) {
this.list.unshift(response.data.result)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
}
})
},
handleUpdate(row) {
this.temp = Object.assign({}, row) // copy obj
var clazz = ''
var grade = ''
if (this.temp.clazz != null) {
clazz = this.temp.clazz.id
if (this.temp.clazz != null) {
grade = this.temp.clazz.grade.id
}
}
this.temp.selectedOptions2 = [grade, clazz]
this.temp.enrollmentDate = new Date(this.temp.enrollmentDate)
//
this.temp.parentStuList = JSON.parse(JSON.stringify(this.temp.parentStuList))
this.temp.user = JSON.parse(JSON.stringify(this.temp.user))
this.temp.address = this.temp.user.address
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.user.name = this.temp.name
this.temp.user.address = this.temp.address
this.temp.enrollmentDate = parseTime(this.temp.enrollmentDate, '{y}-{m}-{d}')
const tempData = Object.assign({}, this.temp)
updateStudent(tempData).then(response => {
if (response.data.code === 200) {
for (const v of this.list) {
if (v.id === response.data.result.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, response.data.result)
break
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -0,0 +1,630 @@
<template>
<div class="app-container">
<div class="filter-container" style="margin-top:-10px;">
<el-input v-model="listQuery.name" placeholder="学生姓名" style="width: 100px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-input v-model="listQuery.address" placeholder="地址" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-select v-model="listQuery.sex" placeholder="性别" clearable class="filter-item" style="width: 75px">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
<el-select v-if="!classId" v-model="listQuery.gradeId" placeholder="年级" clearable class="filter-item" style="width: 130px" @change="updateClass">
<el-option v-for="item in gradeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-select v-if="!classId" v-model="listQuery.classId" placeholder="班级" clearable class="filter-item" style="width: 150px">
<el-option v-for="item in classList" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
<el-button v-if="$store.state.user.admin && type" class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">{{ $t('table.add') }}</el-button>
<el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">显示家长</el-checkbox>
</div>
<el-table
v-loading="listLoading"
:key="tableKey"
:data="list"
:show-overflow-tooltip="true"
:row-key="getRowKeys"
:height="tableHeight"
border
fit
highlight-current-row
style="width: 100%;min-height:300px;ellipsis;margin-top:-10px;"
@selection-change="handleSelectionChange">
<el-table-column
:reserve-selection="true"
type="selection"
width="35"/>
<el-table-column :label="$t('table.id')" align="center" width="50px">
<template slot-scope="scope">
<span>{{ scope.$index+1 }}</span>
</template>
</el-table-column>
<el-table-column label="学生姓名" width="100px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="学籍号" width="180px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.stuNo }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="身份证号" width="180px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.idCard }}</span>
</template>
</el-table-column>
<el-table-column label="性别" width="50px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.sex == 0 ? '男' : '女' }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="籍贯" width="120px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.nativePlace }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="民族" width="60px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.folk }}</span>
</template>
</el-table-column>
<el-table-column v-if="false" :show-overflow-tooltip="true" label="角色" width="60px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.position }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="家庭地址" min-width="220px">
<template slot-scope="scope">
<span class="link-type" style="text-overflow:ellipsis;" @click="handleUpdate(scope.row, true)">{{ scope.row.address }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="联系电话" width="110px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.tel }}</span>
</template>
</el-table-column>
<el-table-column v-if="!classId" label="入学时间" width="95px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.enrollmentDate }}</span>
</template>
</el-table-column>
<el-table-column v-if="!classId" :show-overflow-tooltip="true" label="年级" width="100px" align="center">
<template slot-scope="scope">
<span>
{{ scope.row.clazz == null ? '' : (scope.row.clazz.grade == null ? '' : scope.row.clazz.grade.name) }}
</span>
</template>
</el-table-column>
<el-table-column v-if="!classId" :show-overflow-tooltip="true" label="班级" width="120px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.clazz == null ? '' : scope.row.clazz.name }}</span>
</template>
</el-table-column>
<el-table-column v-if="showReviewer" label="家长" align="center" min-width="120px">
<template slot-scope="scope">
<div v-for="(item) in scope.row.parentStuList" :gutter="1" :key="item.id" type="flex" class="row-bg" justify="left" style="margin-top:2px;">
<div :span="12" style="float:left;margin:2px;">
<div class="grid-content "/>
<el-tooltip placement="left-start">
<div slot="content">电话: {{ item.tel== null? '无' : item.tel }}</div>
<span class="el-tag el-tag--info el-tag--small" style="float:left;">
<span class="link-type" @click="handleEditClass(scope.row)"><svg-icon v-if="item.openid" icon-class="weixin"/>{{ item.name }} {{ item.role ? '(' + item.role + ')' : '' }} </span>
</span>
</el-tooltip>
</div>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="60">
<template slot-scope="scope">
<el-dropdown class="avatar-container right-menu-item" trigger="click">
<el-button style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-if="$store.state.user.admin">
<span style="display:block;" @click="handleUpdate(scope.row, false)">{{ $t('edit') }}</span>
</el-dropdown-item>
<el-dropdown-item divided>
<span v-if="!classId" style="display:block;" @click="handleDelete(scope.row,'deleted')">{{ $t('delete') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<div class="pagination-container" style="margin-top:10px;">
<el-pagination :current-page="listQuery.page" :page-sizes="[10,20,30, 50]" :page-size="listQuery.limit" :total="total" background layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange"/>
</div>
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" append-to-body width="40%">
<el-form ref="dataForm" :rules="rules" :model="temp" :disabled="disabled" label-position="right" label-width="20%" style="width: 90%; margin-left:10px;">
<el-form-item label="学生姓名" prop="name">
<el-input v-model="temp.name" :maxlength="20"/>
</el-form-item>
<el-form-item label="学籍号" prop="stuNo">
<el-input v-model="temp.stuNo"/>
</el-form-item>
<el-form-item label="身份证件号" prop="idCard">
<el-input v-model="temp.idCard"/>
</el-form-item>
<el-form-item label="性别">
<el-select v-model="temp.sex" class="filter-item">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item label="籍贯" prop="stuNo">
<el-input v-model="temp.nativePlace"/>
</el-form-item>
<el-form-item label="民族" prop="stuNo">
<el-input v-model="temp.folk"/>
</el-form-item>
<el-form-item label="班级" prop="code">
<el-cascader
v-model="temp.selectedOptions2"
:options="gradeList"
:props="props"
clearable
expand-trigger="hover"
style="width: 100%;"
@change="handleChange"/>
</el-form-item>
<el-form-item label="家庭地址" prop="address">
<el-input v-model="temp.address"/>
</el-form-item>
<el-form-item label="联系电话" prop="address">
<el-input v-model="temp.tel"/>
</el-form-item>
<el-form-item label="入学时间">
<el-date-picker v-model="temp.enrollmentDate" type="date" placeholder="入学时间" style="width: 100%;"/>
</el-form-item>
<el-form-item label="家长" prop="address">
<el-row v-for="(item,index) in temp.parentStuList" :gutter="10" :key="item.id" type="flex" class="row-bg" justify="left" style="margin-top:5px;">
<el-col :span="12">
<el-popover
:disabled="disabled || item.openid"
v-model="item.visiblePopover"
placement="top"
width="300"
trigger="click">
<el-form :model="formLabelAlign" label-position="right" label-width="60px">
<el-form-item label="姓名">
<el-input v-model="formLabelAlign.name"/>
</el-form-item>
<el-form-item label="角色">
<el-input v-model="formLabelAlign.role"/>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="formLabelAlign.tel"/>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="item.visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateParent(index)">确定</el-button>
</div>
</el-form>
<div slot="reference">
<span class="el-tag el-tag--info el-tag--small" style="float:left;">
<span class="link-type" @click="editParent(item)"><svg-icon v-if="item.openid" icon-class="weixin"/>{{ item.role }} ({{ item.name }}-{{ item.tel }})</span>
<i v-if="!disabled" class="el-tag__close el-icon-close" @click="deleteParent(index)"/>
</span>
</div>
</el-popover>
</el-col>
</el-row>
<el-popover
v-model="formLabelAlign.visiblePopover"
placement="top"
width="300"
trigger="click">
<el-form ref="popoverForm" :rules="rules" :model="formLabelAlign" label-position="right" label-width="60px">
<el-form-item label="姓名" prop="name">
<el-input v-model="formLabelAlign.name"/>
</el-form-item>
<el-form-item label="角色">
<el-input v-model="formLabelAlign.role"/>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="formLabelAlign.tel"/>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="formLabelAlign.visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateParent(-1)">确定</el-button>
</div>
</el-form>
<el-button slot="reference" icon="el-icon-circle-plus-outline" size="mini" round @click="createParent()">添加</el-button>
</el-popover>
</el-form-item>
<el-form-item :label="$t('table.status')">
<el-select v-model="temp.graduationStatus" value-key="id" class="filter-item" style="width: 100%;">
<el-option v-for="item in statusOptions" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-form-item>
<el-form-item label="说明">
<el-input :autosize="{ minRows: 3, maxRows: 6}" v-model="temp.comment" type="textarea"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button v-if="dialogStatus=='create' && !disabled" type="primary" @click="createData">{{ $t('table.confirm') }}</el-button>
<el-button v-else-if="!disabled" type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { fetchPv } from '@/api/article'
import { fetchStuList, fetchGradeList, updateStudent, createStudent, deleteStudent } from '@/api/user'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
const calendarTypeOptions = [
{ key: 0, display_name: '男' },
{ key: 1, display_name: '女' }
]
const areaTypeOptions = [
{ key: '1', display_name: '外县' },
{ key: '2', display_name: '外镇' },
{ key: '3', display_name: '凉森村' },
{ key: '4', display_name: '跃进村' }
]
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
}
},
props: {
type: {
type: Boolean,
default: true
},
tableHeight: {
type: String,
default: window.innerHeight - 200 + 'px'
},
classId: {
type: Number,
default: undefined
}
},
data() {
return {
disabled: true,
tableKey: 0,
list: null,
total: null,
fid: this.$store.state.user.fid,
listLoading: true,
listQuery: {
page: 1,
fid: this.$store.state.user.fid,
limit: 20,
status: 1,
address: undefined,
gradeId: undefined,
classId: this.classId,
importance: undefined,
title: undefined,
type: undefined,
name: undefined,
area: undefined,
sort: '+id'
},
formLabelAlign: {
name: '',
tel: '',
role: ''
},
importanceOptions: [1, 2, 3],
calendarTypeOptions,
areaTypeOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
statusOptions: [{ name: '在读', id: 1 }, { name: '转学', id: 0 }],
showReviewer: false,
temp: {
id: undefined,
importance: 1,
remark: '',
timestamp: new Date(),
class: undefined,
name: undefined,
sex: 0,
parentStuList: [],
selectedOptions2: undefined,
status: undefined
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
gradeList: undefined,
classList: undefined,
props: {
label: 'name',
value: 'id',
children: 'clazzList'
},
dialogPvVisible: false,
pvData: [],
rules: {
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
stuNo: [{ required: true, message: '学号不能为空', trigger: 'blur' }]
},
downloadLoading: false,
userList: []
}
},
created() {
this.getList()
this.fetchGradeList()
},
methods: {
getSelectUser() {
return this.userList
},
updateClass() {
for (const index in this.gradeList) {
const grade = this.gradeList[index]
if (grade.id === this.listQuery.gradeId) {
this.classList = grade.clazzList
}
}
},
fetchGradeList() {
fetchGradeList(this.listQuery).then(response => {
this.gradeList = response.data.result.list
})
},
handleSelectionChange(val) {
this.userList = val
},
getRowKeys(row) {
return row.uid
},
resetParent() {
this.formLabelAlign = {
name: undefined,
role: undefined,
tel: undefined,
fid: this.fid,
visiblePopover: true
}
},
createParent() {
this.resetParent()
},
updateParent(index) {
this.$refs['popoverForm'].validate((valid) => {
if (valid) {
if (index > -1) {
this.temp.parentStuList.splice(index, 1, this.formLabelAlign)
} else {
this.temp.parentStuList.push(this.formLabelAlign)
}
this.formLabelAlign.visiblePopover = false
}
})
},
editParent(item) {
if (!item.openid) {
this.formLabelAlign = JSON.parse(JSON.stringify(item))
item.visiblePopover = !this.disabled
this.$nextTick(() => {
this.$refs['popoverForm'].clearValidate()
})
}
},
getList() {
this.listLoading = true
fetchStuList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
})
},
deleteParent(index) {
this.temp.parentStuList.splice(index, 1)
},
handleChange(value) {
if (this.temp.clazz == null) {
this.temp.clazz = {}
}
if (value != null && value.length > 1) {
this.temp.clazz.id = value[1]
} else {
this.temp.clazz.id = null
}
},
handleFilter() {
this.multipleSelection = []
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, status) {
this.$message({
message: '操作成功',
type: 'success'
})
row.status = status
},
resetTemp() {
this.temp = {
id: undefined,
graduationStatus: 1,
enrollmentDate: '',
sex: 0,
name: undefined,
status: 1,
parentStuList: [],
address: undefined
}
},
handleCreate() {
this.resetTemp()
this.disabled = false
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
if (this.temp.clazz == null) {
this.temp.clazz = {}
}
this.temp.enrollmentDate = parseTime(this.temp.enrollmentDate, '{y}-{m}-{d}')
this.temp.username = this.temp.name
this.temp.fid = this.fid
this.temp.graduationStatus = 1
this.temp.address = this.temp.address
this.temp.roles = [2]
createStudent(this.temp).then(response => {
if (response.data.code === 200) {
fetchStuList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
})
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
}
})
},
handleUpdate(row, disabled) {
this.disabled = disabled
this.temp = Object.assign({}, row) // copy obj
var clazz = ''
var grade = ''
if (this.temp.clazz != null) {
clazz = this.temp.clazz.id
if (this.temp.clazz != null) {
grade = this.temp.clazz.grade.id
}
}
this.temp.selectedOptions2 = [grade, clazz]
if (this.temp.enrollmentDate) {
this.temp.enrollmentDate = new Date(this.temp.enrollmentDate)
}
//
this.temp.parentStuList = JSON.parse(JSON.stringify(this.temp.parentStuList))
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.temp.enrollmentDate = parseTime(this.temp.enrollmentDate, '{y}-{m}-{d}')
const tempData = Object.assign({}, this.temp)
updateStudent(tempData).then(response => {
if (response.data.code === 200) {
fetchStuList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
})
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '添加成功',
type: 'success',
duration: 2000
})
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
})
}
})
},
handleDelete(row) {
deleteStudent(row).then(response => {
fetchStuList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
})
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
})
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>

View File

@ -5,6 +5,12 @@
</a>
</p>
<div class="icons-wrapper">
<i class="iconfont icon-weixin"/>
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-weixin"/>
</svg>
<svg-icon icon-class="school" />
<svg-icon icon-class="nianjiguanli" />年级管理
<div v-for="item of iconsMap" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
<el-tooltip placement="top">
<div slot="content">

View File

@ -0,0 +1,80 @@
<template>
<div class="app-container">
<div style="z-index: 1; height: 50px;">
<div class="draft" style="top: 0px; z-index: 1;height: 45px;margin-top:-5px;">
<el-button class="filter-item" style="margin-right: 10px;float:right;" @click="cancelSchoolData()">取消</el-button>
<el-button v-if="!disabled" type="primary" class="filter-item el-button--mini" style="margin-right: 10px;float:right;" icon="el-icon-edit" @click="updateSchoolData()">{{ $t('save') }}</el-button>
<el-button v-if="disabled" class="filter-item el-button--mini el-button--success" style="margin-right: 10px;float:right;" icon="el-icon-edit" @click="disabled = false">{{ $t('edit') }}</el-button>
</div>
</div>
<el-form ref="form" :model="form" :disabled="disabled" :rules="rules" label-width="150px">
<el-form-item label="学校名称" prop="schoolName">
<el-input v-model="form.schoolName"/>
</el-form-item>
<el-form-item label="地区编号" prop="areaCode">
<el-input v-model="form.areaCode"/>
</el-form-item>
<el-form-item label="学校代码" prop="schoolCode">
<el-input v-model="form.schoolCode"/>
</el-form-item>
<el-form-item label="微信公众号应用ID">
<el-input v-model="form.appid"/>
</el-form-item>
<el-form-item label="微信公众号应用密钥">
<el-input v-model="form.appsecret"/>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { fetchSchool, updateSchool } from '@/api/user'
export default {
data() {
return {
disabled: true,
listQuery: {
fid: this.$store.state.user.fid
},
data: null,
form: {
schoolName: '',
areaCode: '',
schoolCode: '',
appid: '',
appsecret: ''
},
rules: {
schoolName: [{ required: true, message: '学校名称必填', trigger: 'change' }],
areaCode: [{ required: true, message: '学校地区编号必填', trigger: 'blur' }],
schoolCode: [{ required: true, message: '学校代码必填', trigger: 'blur' }]
}
}
},
created() {
this.getSchoolData()
},
methods: {
getSchoolData() {
fetchSchool(this.listQuery).then(response => {
this.data = response.data.result
this.form = JSON.parse(JSON.stringify(this.data))
})
},
updateSchoolData() {
updateSchool(this.form).then(response => {
this.data = response.data.result
this.disabled = true
this.form = JSON.parse(JSON.stringify(this.data))
})
},
cancelSchoolData() {
this.form = JSON.parse(JSON.stringify(this.data))
this.disabled = true
},
onSubmit() {
console.log('submit!')
}
}
}
</script>

View File

@ -0,0 +1,87 @@
<template>
<div class="app-container">
<div class="filter-container" style="margin-top:-10px;">
<el-button class="filter-item" icon="el-icon-refresh" style="float:right;margin-left:15px;">拉取模板</el-button>
</div>
<el-table
:data="list"
:show-overflow-tooltip="true"
border
fit
highlight-current-row
style="width: 100%;min-height:300px;ellipsis;margin-top:-10px;">
<el-table-column :label="$t('table.id')" align="center" width="50px">
<template slot-scope="scope">
<span>{{ scope.$index+1 }}</span>
</template>
</el-table-column>
<el-table-column label="模板ID" width="200px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.templateId }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="模板标题" width="150px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="模板格式" min-width="250px" align="center">
<template slot-scope="scope">
<span><div v-html="$options.filters.msg(scope.row.content)"/></span>
</template>
</el-table-column>
<el-table-column :show-overflow-tooltip="true" label="模板所属应用ID" width="200px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.appid }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="300" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button type="primary" size="mini">编辑用户</el-button>
<el-button size="mini" type="success" >查看</el-button>
<el-button size="mini" type="danger" >{{ $t('table.delete') }}</el-button>
<el-button size="mini" type="success" >禁用</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { fetchTemplateList } from '@/api/user'
import waves from '@/directive/waves' //
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
msg: function(msg) {
// .replace(/\{[^}]+}}/g, 'abc')
return msg.replace(/\\n/gm, '<br/>')
}
},
data() {
return {
list: null,
total: null,
listQuery: {
fid: this.$store.state.user.fid
}
}
},
created() {
this.getList()
},
methods: {
getList() {
fetchTemplateList(this.listQuery).then(response => {
this.list = response.data.result
this.total = response.data.result.total
})
}
}
}
</script>

View File

@ -91,13 +91,13 @@
</el-select>
</el-form-item>
<el-form-item :label="$t('table.date')" prop="timestamp">
<el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date"/>
<el-date-picker v-model="temp.timestamp" type="datetime"/>
</el-form-item>
<el-form-item :label="$t('table.title')" prop="title">
<el-input v-model="temp.title"/>
</el-form-item>
<el-form-item :label="$t('table.status')">
<el-select v-model="temp.status" class="filter-item" placeholder="Please select">
<el-select v-model="temp.status" class="filter-item" >
<el-option v-for="item in statusOptions" :key="item" :label="item" :value="item"/>
</el-select>
</el-form-item>
@ -105,7 +105,7 @@
<el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;"/>
</el-form-item>
<el-form-item :label="$t('table.remark')">
<el-input :autosize="{ minRows: 2, maxRows: 4}" v-model="temp.remark" type="textarea" placeholder="Please input"/>
<el-input :autosize="{ minRows: 2, maxRows: 4}" v-model="temp.remark" type="textarea"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
@ -194,8 +194,8 @@ export default {
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: 'Edit',
create: 'Create'
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
@ -227,6 +227,14 @@ export default {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, status) {
this.$message({
message: '操作成功',

View File

@ -0,0 +1,701 @@
<template>
<div class="app-container">
<div class="filter-container" style="margin-top:-10px;">
<el-input v-model="listQuery.name" placeholder="姓名" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/>
<el-select v-model="listQuery.sex" placeholder="性别" clearable class="filter-item" style="width: 130px">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button>
<el-button v-if="$store.state.user.admin && !classId" class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">{{ $t('table.add') }}</el-button>
<el-popover
v-model="courseData.visiblePopover"
placement="top"
width="300"
trigger="click">
<el-form ref="popoverForm" :rules="rules" :model="courseData" label-position="right" label-width="120px">
<el-form-item label="课程" prop="name">
<el-select v-model="courseData.course" value-key="id" filterable class="filter-item" style="width: 100%;">
<el-option v-for="item in courseList" :key="item.id" :label="item.name" :value="item"/>
</el-select>
</el-form-item>
<el-form-item label="教师名称" prop="name">
<el-select v-model="courseData.teacher" value-key="uid" filterable class="filter-item" style="width: 100%;">
<el-option v-for="item in allList" :key="item.uid" :label="item.name" :value="item"/>
</el-select>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="courseData.visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateCourse()">确定</el-button>
</div>
</el-form>
<el-button v-if="classId" slot="reference" class="filter-item" icon="el-icon-edit" style="margin-left: 10px;" type="primary" @click="addCourseForTeacher()">添加任课老师</el-button>
</el-popover>
</div>
<el-table
v-loading="listLoading"
:key="tableKey"
:data="list"
:height="tableHeight"
:row-key="getRowKeys"
border
fit
highlight-current-row
style="width: 100%;min-height:300px;margin-top:-10px;"
@selection-change="handleSelectionChange">
<el-table-column
:reserve-selection="true"
type="selection"
width="35"/>
<el-table-column :label="$t('table.id')" align="center" width="60">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="姓名" width="160px" align="left">
<template slot-scope="scope">
<span class="link-type" style="text-overflow:ellipsis;" @click="handleUpdate(scope.row, true)">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column label="编号" width="200px">
<template slot-scope="scope">
<span>{{ scope.row.code }}</span>
</template>
</el-table-column>
<el-table-column v-if="!classId" label="入职时间" width="160px" align="center">
<template slot-scope="scope">
<span>{{ scope.row.enrollmentDate }}</span>
</template>
</el-table-column>
<el-table-column v-if="!classId" label="性别" align="center" width="70">
<template slot-scope="scope">
<span>{{ scope.row.sex == 0 ? "男" : "女" }}</span>
</template>
</el-table-column>
<el-table-column label="电话号码" width="150px" align="left">
<template slot-scope="scope">
<span>{{ scope.row.tel }}</span>
</template>
</el-table-column>
<el-table-column v-if="false" :label="$t('table.status')" class-name="status-col" width="80">
<template slot-scope="scope">
<el-tag v-if="scope.row.teacherStatus==1"> 在职</el-tag>
<el-tag v-if="scope.row.teacherStatus==2" type="warning">离职</el-tag>
<el-tag v-if="scope.row.teacherStatus==3" type="info"> 退休</el-tag>
</template>
</el-table-column>
<el-table-column label="执教班级" min-width="250" align="center">
<template slot-scope="scope">
<div v-for="(item,index) in scope.row.classMap" v-if="index%2 != 1" :gutter="1" :key="item.id" class="link-type row-bg" style="text-overflow:ellipsis;" type="flex" justify="left" @click="handleUpdate(scope.row, false)">
<el-tag v-if="index%2 != 1" style="float:left;margin:2px;" >{{ item.className }}({{ item.courseName }})</el-tag>
<el-tag v-if="scope.row.classMap[index+1] != null" style="float:left;margin:2px;">{{ scope.row.classMap[index+1].className }}({{ scope.row.classMap[index+1].courseName }})</el-tag>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('table.actions')" align="center" width="70" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-dropdown trigger="click">
<!-- <svg-icon icon-class="action" style="width: 1.2em;height: 1.2em;cursor:pointer"/> -->
<el-button style="cursor:pointer" class="el-icon-caret-bottom"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-if="$store.state.user.admin">
<span style="display:block;" @click="handleUpdate(scope.row, false)">{{ $t('edit') }}</span>
</el-dropdown-item>
<el-dropdown-item v-if="$store.state.user.admin" divided>
<span style="display:block;" @click="handleModifyStatus(scope.row,scope.$index)">{{ $t('delete') }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialogFormVisible" :title="textMap[dialogStatus]" append-to-body width="40%">
<el-form ref="dataForm" :disabled="disabled" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
<el-form-item label="编号" prop="code">
<el-input v-model="temp.code"/>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="temp.name"/>
</el-form-item>
<el-form-item label="登录名" prop="username">
<el-input v-model="temp.username" placeholder="默认为姓名"/>
</el-form-item>
<el-form-item label="手机号码" prop="tel">
<el-input v-model="temp.tel"/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="temp.sex" class="filter-item" placeholder="Please select">
<el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
<el-form-item label="执教课程">
<el-row v-for="(item,index) in temp.classMap" :gutter="10" :key="item.id" type="flex" class="row-bg" justify="left" style="margin-top:5px;">
<el-col :span="12">
<el-popover
:disabled="disabled"
v-model="temp.classMap[index].visiblePopover"
placement="top"
width="300"
trigger="click">
<el-form :model="formLabelAlign" label-position="left" label-width="60px">
<el-form-item label="班级">
<el-cascader
v-model="formLabelAlign.classId"
:options="gradeList"
:props="props"
clearable
expand-trigger="hover"
style="width: 100%;"
@change="handleChange"/>
</el-form-item>
<el-form-item label="课程">
<el-select v-model="formLabelAlign.course" value-key="id" filterable class="filter-item" style="width: 100%;">
<el-option v-for="item in courseList" :key="item.id" :label="item.name" :value="item"/>
</el-select>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="temp.classMap[index].visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateParent(index)">确定</el-button>
</div>
</el-form>
<div slot="reference">
<span class="el-tag el-tag--info el-tag--small" style="float:left;">
<span class="link-type" @click="editParent(item)">{{ item.className }} ({{ item.courseName }})</span>
<i v-if="!disabled" class="el-tag__close el-icon-close" @click="deleteParent(index)"/>
</span>
</div>
</el-popover>
</el-col>
</el-row>
<el-popover
v-model="formLabelAlign.visiblePopover"
placement="top"
width="300"
trigger="click">
<el-form ref="popoverForm" :model="formLabelAlign" label-position="right" label-width="60px">
<el-form-item label="班级">
<el-cascader
v-model="formLabelAlign.classId"
:options="gradeList"
:props="props"
clearable
expand-trigger="hover"
style="width: 100%;"
@change="handleChange"/>
</el-form-item>
<el-form-item label="课程">
<el-select v-model="formLabelAlign.course" value-key="id" filterable class="filter-item" style="width: 100%;">
<el-option v-for="item in courseList" :key="item.id" :label="item.name" :value="item"/>
</el-select>
</el-form-item>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="formLabelAlign.visiblePopover = false">取消</el-button>
<el-button type="primary" size="mini" @click="updateParent(-1)">确定</el-button>
</div>
</el-form>
<el-button slot="reference" icon="el-icon-circle-plus-outline" size="mini" round @click="createParent()">添加</el-button>
</el-popover>
</el-form-item>
<el-form-item :label="$t('table.date')">
<el-date-picker v-model="temp.enrollmentDate" type="date"/>
</el-form-item>
<el-form-item :label="$t('table.status')">
<el-select v-model="temp.teacherStatus" class="filter-item">
<el-option v-for="item in statusOptions" :key="item.key" :label="item.display_name" :value="item.key"/>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
<el-button v-if="dialogStatus=='create' && !disabled" type="primary" @click="createData">{{ $t('table.confirm') }}</el-button>
<el-button v-else-if="!disabled" type="primary" @click="updateData">{{ $t('table.confirm') }}</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { fetchTeacherList, fetchPv, updateTeacher, deleteTeacher, fetchGradeList, fetchCourseList, addCourseClass } from '@/api/user'
import waves from '@/directive/waves' //
import { parseTime } from '@/utils'
const calendarTypeOptions = [
{ key: 0, display_name: '男' },
{ key: 1, display_name: '女' }
]
const statusOptions = [
{ key: 1, display_name: '在职' },
{ key: 2, display_name: '离职' },
{ key: 3, display_name: '退休' }
]
// arr to obj ,such as { CN : "China", US : "USA" }
const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
acc[cur.key] = cur.display_name
return acc
}, {})
export default {
name: 'ComplexTable',
directives: {
waves
},
filters: {
statusFilter(status) {
const statusMap = {
published: 'success',
draft: 'info',
deleted: 'danger'
}
return statusMap[status]
},
typeFilter(type) {
return calendarTypeKeyValue[type]
}
},
props: {
type: {
type: Boolean,
default: true
},
tableHeight: {
type: String,
default: window.innerHeight - 160 + 'px'
},
classId: {
type: Number,
default: undefined
},
className: {
type: String,
default: undefined
}
},
data() {
return {
tableKey: 0,
list: null,
allList: [],
total: null,
listLoading: true,
listQuery: {
page: 1,
courseId: undefined,
gradeId: undefined,
classId: this.classId,
fid: this.$store.state.user.fid,
sex: undefined,
name: undefined,
type: undefined,
sort: '+id'
},
gradeQuery: {
page: 1,
fid: this.$store.state.user.fid
},
importanceOptions: [1, 2, 3],
calendarTypeOptions,
statusOptions,
sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
showReviewer: false,
formLabelAlign: {
class: {},
classId: [],
course: {}
},
courseData: {
class: {},
classId: [],
course: {}
},
props: {
label: 'name',
value: 'id',
children: 'clazzList'
},
classList: [],
courseList: [],
temp: {
id: undefined,
importance: 1,
remark: '',
enrollmentDate: '',
title: '',
sex: 0,
classMap: [],
loginName: undefined,
type: ''
},
dialogFormVisible: false,
dialogStatus: '',
textMap: {
update: this.$t('edit'),
create: this.$t('create')
},
dialogPvVisible: false,
pvData: [],
rules: {
type: [{ required: true, message: 'type is required', trigger: 'change' }],
code: [{ required: true, message: '教师编号必填', trigger: 'blur' }],
name: [{ required: true, message: '教师姓名必填', trigger: 'blur' }]
},
downloadLoading: false,
multipleSelection: [],
gradeList: [],
userList: [],
disabled: true
}
},
created() {
this.getList()
if (this.classId) {
var tempQuery = {
fid: this.$store.state.user.fid
}
fetchTeacherList(tempQuery).then(response => {
this.allList = response.data.result.list
}
)
}
this.fetchGradeList()
this.fetchCourseList()
},
methods: {
deleteParent(index) {
this.temp.classMap.splice(index, 1)
},
editParent(item) {
this.formLabelAlign = JSON.parse(JSON.stringify(item))
this.formLabelAlign.classId = [item.gradeId, item.classId]
this.formLabelAlign.course = {}
this.formLabelAlign.course.name = this.formLabelAlign.courseName
this.formLabelAlign.course.id = this.formLabelAlign.courseId
item.visiblePopover = !this.disabled
},
updateParent(index) {
if (index > -1) {
this.formLabelAlign.visiblePopover = false
const courseMap = {}
for (const index in this.gradeList) {
const grade = this.gradeList[index]
if (grade.id === this.formLabelAlign.classId[0]) {
const classList = grade.clazzList
for (const i in classList) {
const clazz = classList[i]
if (clazz.id === this.formLabelAlign.classId[1]) {
courseMap.className = clazz.name
courseMap.classId = clazz.id
break
}
}
break
}
}
courseMap.courseName = this.formLabelAlign.course.name
courseMap.courseId = this.formLabelAlign.course.id
this.temp.classMap.splice(index, 1, courseMap)
} else {
this.formLabelAlign.visiblePopover = false
const courseMap = {}
for (const index in this.gradeList) {
var grade = this.gradeList[index]
if (grade.id === this.formLabelAlign.classId[0]) {
var classList = grade.clazzList
for (var i in classList) {
var clazz = classList[i]
if (clazz.id === this.formLabelAlign.classId[1]) {
courseMap.className = clazz.name
courseMap.classId = clazz.id
break
}
}
break
}
}
courseMap.courseName = this.formLabelAlign.course.name
courseMap.courseId = this.formLabelAlign.course.id
this.temp.classMap.push(courseMap)
}
},
updateCourse() {
const courseMap = {}
courseMap.courseName = this.courseData.course.name
courseMap.className = this.className
courseMap.courseId = this.courseData.course.id
courseMap.classId = this.classId
this.temp = this.courseData.teacher
this.temp.classMap = []
this.temp.classMap.push(courseMap)
this.updateCourseData()
},
resetParent() {
this.formLabelAlign = {
class: {},
classId: undefined,
course: {},
visiblePopover: true
}
},
createParent() {
this.resetParent()
},
addCourseForTeacher() {
this.courseData = {
class: {},
classId: [],
course: {},
visiblePopover: true
}
},
handleChange(value) {
if (this.formLabelAlign.class == null) {
this.formLabelAlign.class = {}
}
if (value != null && value.length > 1) {
this.formLabelAlign.class.id = value[1]
} else {
this.formLabelAlign.class.id = null
}
},
getSelectUser() {
return this.userList
},
updateClass() {
for (const index in this.gradeList) {
const grade = this.gradeList[index]
if (grade.id === this.listQuery.gradeId) {
this.classList = grade.clazzList
}
}
},
fetchGradeList() {
fetchGradeList(this.gradeQuery).then(response => {
this.gradeList = response.data.result.list
})
},
fetchCourseList() {
fetchCourseList(this.gradeQuery).then(response => {
this.courseList = response.data.result
})
},
handleSelectionChange(val) {
this.userList = val
},
getRowKeys(row) {
return row.uid
},
getList() {
this.multipleSelection = []
this.listLoading = true
fetchTeacherList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
this.listLoading = false
}
)
},
handleFilter() {
this.listQuery.page = 1
this.getList()
},
handleSizeChange(val) {
this.listQuery.limit = val
this.getList()
},
handleCurrentChange(val) {
this.listQuery.page = val
this.getList()
},
handleModifyStatus(row, index) {
deleteTeacher({ id: row.teacherId }).then(() => {
fetchTeacherList(this.listQuery).then(response => {
this.list = response.data.result.list
this.total = response.data.result.total
})
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
}).catch(function(error) {
console.log(error)
})
},
resetTemp() {
this.temp = {
id: undefined,
importance: 1,
remark: '',
enrollmentDate: '',
title: '',
fid: this.$store.state.user.fid,
teacherStatus: 1,
uid: undefined,
classMap: [],
sex: 0,
loginName: undefined
}
},
handleCreate() {
this.resetTemp()
this.disabled = false
this.dialogStatus = 'create'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
this.updateTeacherData()
}
})
},
updateTeacherData() {
const tempData = Object.assign({}, this.temp)
tempData.enrollmentDate = parseTime(tempData.enrollmentDate, '{y}-{m}-{d}')
this.temp.enrollmentDate = tempData.enrollmentDate
if (!this.temp.username) {
this.temp.username = this.temp.name
}
updateTeacher(this.temp).then(response => {
this.list.unshift(response.data.result)
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
}
)
},
updateCourseData() {
const tempData = Object.assign({}, this.temp)
tempData.enrollmentDate = parseTime(tempData.enrollmentDate, '{y}-{m}-{d}')
this.temp.enrollmentDate = tempData.enrollmentDate
if (!this.temp.username) {
this.temp.username = this.temp.name
}
addCourseClass(this.temp).then(response => {
if (this.classId) {
this.getList()
this.courseData.visiblePopover = false
}
this.$notify({
title: '成功',
message: '创建成功',
type: 'success',
duration: 2000
})
}
)
},
handleUpdate(row, disabled) {
this.disabled = disabled
this.temp = Object.assign({}, row) // copy obj
//
this.temp.classMap = JSON.parse(JSON.stringify(this.temp.classMap))
if (this.temp.enrollmentDate != null) {
this.temp.enrollmentDate = new Date(this.temp.enrollmentDate)
}
this.dialogStatus = 'update'
this.dialogFormVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
updateData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
if (this.temp.enrollmentDate != null) {
this.temp.enrollmentDate = new Date(this.temp.enrollmentDate)
}
if (!this.temp.username) {
this.temp.username = this.temp.name
}
const tempData = Object.assign({}, this.temp)
tempData.enrollmentDate = parseTime(tempData.enrollmentDate, '{y}-{m}-{d}')
this.temp.enrollmentDate = tempData.enrollmentDate
updateTeacher(tempData).then(response => {
if (response.data.code === 200) {
if (this.classId) {
this.getList()
} else {
for (const v of this.list) {
if (v.id === this.temp.id) {
const index = this.list.indexOf(v)
this.list.splice(index, 1, this.temp)
break
}
}
}
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '更新成功',
type: 'success',
duration: 2000
})
} else {
this.$notify({
title: '失败',
message: response.data.message,
type: 'error',
duration: 5000
})
}
}).catch(function(error) {
console.log(error)
})
}
})
},
handleDelete(row) {
this.$notify({
title: '成功',
message: '删除成功',
type: 'success',
duration: 2000
})
const index = this.list.indexOf(row)
this.list.splice(index, 1)
},
handleFetchPv(pv) {
fetchPv(pv).then(response => {
this.pvData = response.data.pvData
this.dialogPvVisible = true
})
},
handleDownload() {
this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => {
const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
const data = this.formatJson(filterVal, this.list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: 'table-list'
})
this.downloadLoading = false
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => {
if (j === 'timestamp') {
return parseTime(v[j])
} else {
return v[j]
}
}))
}
}
}
</script>