离校前端框架,包括数据字典、工作队伍、新闻公告模块
diff --git a/leave-school-vue/src/App.vue b/leave-school-vue/src/App.vue
new file mode 100644
index 0000000..812eef2
--- /dev/null
+++ b/leave-school-vue/src/App.vue
@@ -0,0 +1,11 @@
+<template>
+ <div id="app">
+ <router-view></router-view>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'App'
+}
+</script>
diff --git a/leave-school-vue/src/api/auditscope-api.js b/leave-school-vue/src/api/auditscope-api.js
new file mode 100644
index 0000000..b24dab5
--- /dev/null
+++ b/leave-school-vue/src/api/auditscope-api.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/auditscope/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/auditscope/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createAuditScope(data) {
+ return request({
+ url: '/api/system/auditscope/create-auditscope',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteAuditScope(data) {
+ return request({
+ url: '/api/system/auditscope/delete-auditscope',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/autoaudittype-api.js b/leave-school-vue/src/api/autoaudittype-api.js
new file mode 100644
index 0000000..03829f2
--- /dev/null
+++ b/leave-school-vue/src/api/autoaudittype-api.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/autoaudittype/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/autoaudittype/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createAutoAuditType(data) {
+ return request({
+ url: '/api/system/autoaudittype/create-autoaudittype',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteAutoAuditType(data) {
+ return request({
+ url: '/api/system/autoaudittype/delete-autoaudittype',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/class-api.js b/leave-school-vue/src/api/class-api.js
new file mode 100644
index 0000000..44d271d
--- /dev/null
+++ b/leave-school-vue/src/api/class-api.js
@@ -0,0 +1,39 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/class/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getAllList(params) {
+ return request({
+ url: '/api/system/class/all-list',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/class/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createClass(data) {
+ return request({
+ url: '/api/system/class/create-class',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteClass(data) {
+ return request({
+ url: '/api/system/class/delete-class',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/department-api.js b/leave-school-vue/src/api/department-api.js
new file mode 100644
index 0000000..b8cbc29
--- /dev/null
+++ b/leave-school-vue/src/api/department-api.js
@@ -0,0 +1,40 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/department/list-api',
+ // url: 'http://localhost:8080/leaveschool/api/v1/base/department',
+ method: 'get',
+ params
+ })
+}
+export function getAllList(params) {
+ return request({
+ url: '/api/system/department/all-list',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/department/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createDepartment(data) {
+ return request({
+ url: '/api/system/department/create-department',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteDepartment(data) {
+ return request({
+ url: '/api/system/department/delete-department',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/departmentleader-api.js b/leave-school-vue/src/api/departmentleader-api.js
new file mode 100644
index 0000000..0fe7ee0
--- /dev/null
+++ b/leave-school-vue/src/api/departmentleader-api.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/workteam/departmentleader/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/workteam/departmentleader/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createDepartmentleader(data) {
+ return request({
+ url: '/api/workteam/departmentleader/create-departmentleader',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteDepartmentleader(data) {
+ return request({
+ url: '/api/workteam/departmentleader/delete-departmentleader',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/dictionary-api.js b/leave-school-vue/src/api/dictionary-api.js
new file mode 100644
index 0000000..586820c
--- /dev/null
+++ b/leave-school-vue/src/api/dictionary-api.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getDicList(params) {
+ return request({
+ url: '/api/system/dictionary/getdiclist',
+ method: 'get',
+ params
+ })
+}
diff --git a/leave-school-vue/src/api/instructor-api.js b/leave-school-vue/src/api/instructor-api.js
new file mode 100644
index 0000000..312169b
--- /dev/null
+++ b/leave-school-vue/src/api/instructor-api.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/workteam/instructor/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/workteam/instructor/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createInstructor(data) {
+ return request({
+ url: '/api/workteam/instructor/create-instructor',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteInstructor(data) {
+ return request({
+ url: '/api/workteam/instructor/delete-instructor',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/login.js b/leave-school-vue/src/api/login.js
new file mode 100644
index 0000000..c9558cf
--- /dev/null
+++ b/leave-school-vue/src/api/login.js
@@ -0,0 +1,27 @@
+import request from '@/utils/request'
+
+export function login(username, password) {
+ return request({
+ url: '/api/login/login',
+ method: 'post',
+ data: {
+ username,
+ password
+ }
+ })
+}
+
+export function getInfo(token) {
+ return request({
+ url: '/api/system/user/info',
+ method: 'get',
+ params: { token }
+ })
+}
+
+export function logout() {
+ return request({
+ url: '/api/login/logout-api',
+ method: 'post'
+ })
+}
diff --git a/leave-school-vue/src/api/major-api.js b/leave-school-vue/src/api/major-api.js
new file mode 100644
index 0000000..2318b22
--- /dev/null
+++ b/leave-school-vue/src/api/major-api.js
@@ -0,0 +1,39 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/major/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getZyListByYx(params) {
+ return request({
+ url: '/api/system/major/list-byyx-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/major/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createMajor(data) {
+ return request({
+ url: '/api/system/major/create-major',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteMajor(data) {
+ return request({
+ url: '/api/system/major/delete-major',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/menulist-api.js b/leave-school-vue/src/api/menulist-api.js
new file mode 100644
index 0000000..3735e5d
--- /dev/null
+++ b/leave-school-vue/src/api/menulist-api.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getMenuList(params) {
+ return request({
+ url: '/api/system/menu/list',
+ method: 'get',
+ params
+ })
+}
diff --git a/leave-school-vue/src/api/newspublish-api.js b/leave-school-vue/src/api/newspublish-api.js
new file mode 100644
index 0000000..44c7368
--- /dev/null
+++ b/leave-school-vue/src/api/newspublish-api.js
@@ -0,0 +1,40 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/news/newspublish/list-api',
+ // url: 'http://localhost:8080/leaveschool/api/v1/base/newspublish',
+ method: 'get',
+ params
+ })
+}
+export function getAllList(params) {
+ return request({
+ url: '/api/news/newspublish/all-list',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/news/newspublish/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createNewspublish(data) {
+ return request({
+ url: '/api/news/newspublish/create-newspublish',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteNewspublish(data) {
+ return request({
+ url: '/api/news/newspublish/delete-newspublish',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/rostersyncinterface-api.js b/leave-school-vue/src/api/rostersyncinterface-api.js
new file mode 100644
index 0000000..949955f
--- /dev/null
+++ b/leave-school-vue/src/api/rostersyncinterface-api.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/rostersyncinterface/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/rostersyncinterface/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createRosterSyncInterface(data) {
+ return request({
+ url: '/api/system/rostersyncinterface/create-rostersyncinterface',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteRosterSyncInterface(data) {
+ return request({
+ url: '/api/system/rostersyncinterface/delete-rostersyncinterface',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/schoolyear-api.js b/leave-school-vue/src/api/schoolyear-api.js
new file mode 100644
index 0000000..01bf016
--- /dev/null
+++ b/leave-school-vue/src/api/schoolyear-api.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/schoolyear/list-api',
+ method: 'get',
+ params
+ })
+}
+export function getItem(params) {
+ return request({
+ url: '/api/system/schoolyear/get-item',
+ method: 'get',
+ params
+ })
+}
+
+export function createSchoolyear(data) {
+ return request({
+ url: '/api/system/schoolyear/create-schoolyear',
+ method: 'post',
+ data
+ })
+}
+
+export function deleteSchoolyear(data) {
+ return request({
+ url: '/api/system/schoolyear/delete-schoolyear',
+ method: 'delete',
+ data
+ })
+}
diff --git a/leave-school-vue/src/api/user-api.js b/leave-school-vue/src/api/user-api.js
new file mode 100644
index 0000000..9b237f3
--- /dev/null
+++ b/leave-school-vue/src/api/user-api.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getList(params) {
+ return request({
+ url: '/api/system/user/list-api',
+ method: 'get',
+ params
+ })
+}
diff --git a/leave-school-vue/src/assets/404_images/404.png b/leave-school-vue/src/assets/404_images/404.png
new file mode 100644
index 0000000..3d8e230
--- /dev/null
+++ b/leave-school-vue/src/assets/404_images/404.png
Binary files differ
diff --git a/leave-school-vue/src/assets/404_images/404_cloud.png b/leave-school-vue/src/assets/404_images/404_cloud.png
new file mode 100644
index 0000000..c6281d0
--- /dev/null
+++ b/leave-school-vue/src/assets/404_images/404_cloud.png
Binary files differ
diff --git a/leave-school-vue/src/components/Breadcrumb/index.vue b/leave-school-vue/src/components/Breadcrumb/index.vue
new file mode 100644
index 0000000..a1da13b
--- /dev/null
+++ b/leave-school-vue/src/components/Breadcrumb/index.vue
@@ -0,0 +1,51 @@
+<template>
+ <el-breadcrumb class="app-breadcrumb" separator="/">
+ <transition-group name="breadcrumb">
+ <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path" v-if="item.meta.title">
+ <span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{item.meta.title}}</span>
+ <router-link v-else :to="item.redirect||item.path">{{item.meta.title}}</router-link>
+ </el-breadcrumb-item>
+ </transition-group>
+ </el-breadcrumb>
+</template>
+
+<script>
+export default {
+ created() {
+ this.getBreadcrumb()
+ },
+ data() {
+ return {
+ levelList: null
+ }
+ },
+ watch: {
+ $route() {
+ this.getBreadcrumb()
+ }
+ },
+ methods: {
+ getBreadcrumb() {
+ let matched = this.$route.matched.filter(item => item.name)
+ const first = matched[0]
+ if (first && first.name !== 'Dashboard') {
+ matched = [{ path: '/dashboard', meta: { title: '离校系统' }}].concat(matched)
+ }
+ this.levelList = matched
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+ .app-breadcrumb.el-breadcrumb {
+ display: inline-block;
+ font-size: 14px;
+ line-height: 50px;
+ margin-left: 10px;
+ .no-redirect {
+ color: #97a8be;
+ cursor: text;
+ }
+ }
+</style>
diff --git a/leave-school-vue/src/components/Hamburger/index.vue b/leave-school-vue/src/components/Hamburger/index.vue
new file mode 100644
index 0000000..fbdf72c
--- /dev/null
+++ b/leave-school-vue/src/components/Hamburger/index.vue
@@ -0,0 +1,44 @@
+<template>
+ <div>
+ <svg t="1492500959545" @click="toggleClick" class="hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
+ version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
+ <path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
+ p-id="1692"></path>
+ <path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
+ p-id="1693"></path>
+ <path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
+ p-id="1694"></path>
+ </svg>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'hamburger',
+ props: {
+ isActive: {
+ type: Boolean,
+ default: false
+ },
+ toggleClick: {
+ type: Function,
+ default: null
+ }
+ }
+}
+</script>
+
+<style scoped>
+.hamburger {
+ display: inline-block;
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+ transform: rotate(90deg);
+ transition: .38s;
+ transform-origin: 50% 50%;
+}
+.hamburger.is-active {
+ transform: rotate(0deg);
+}
+</style>
diff --git a/leave-school-vue/src/components/ScrollPane/index.vue b/leave-school-vue/src/components/ScrollPane/index.vue
new file mode 100644
index 0000000..1ce68c1
--- /dev/null
+++ b/leave-school-vue/src/components/ScrollPane/index.vue
@@ -0,0 +1,72 @@
+<template>
+ <div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll">
+ <div class="scroll-wrapper" ref="scrollWrapper" :style="{left: left + 'px'}">
+ <slot></slot>
+ </div>
+ </div>
+</template>
+
+<script>
+const padding = 15 // tag's padding
+
+export default {
+ name: 'scrollPane',
+ data() {
+ return {
+ left: 0
+ }
+ },
+ methods: {
+ handleScroll(e) {
+ const eventDelta = e.wheelDelta || -e.deltaY * 3
+ const $container = this.$refs.scrollContainer
+ const $containerWidth = $container.offsetWidth
+ const $wrapper = this.$refs.scrollWrapper
+ const $wrapperWidth = $wrapper.offsetWidth
+
+ if (eventDelta > 0) {
+ this.left = Math.min(0, this.left + eventDelta)
+ } else {
+ if ($containerWidth - padding < $wrapperWidth) {
+ if (this.left < -($wrapperWidth - $containerWidth + padding)) {
+ this.left = this.left
+ } else {
+ this.left = Math.max(this.left + eventDelta, $containerWidth - $wrapperWidth - padding)
+ }
+ } else {
+ this.left = 0
+ }
+ }
+ },
+ moveToTarget($target) {
+ const $container = this.$refs.scrollContainer
+ const $containerWidth = $container.offsetWidth
+ const $targetLeft = $target.offsetLeft
+ const $targetWidth = $target.offsetWidth
+
+ if ($targetLeft < -this.left) {
+ // tag in the left
+ this.left = -$targetLeft + padding
+ } else if ($targetLeft + padding > -this.left && $targetLeft + $targetWidth < -this.left + $containerWidth - padding) {
+ // tag in the current view
+ // eslint-disable-line
+ } else {
+ // tag in the right
+ this.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)
+ }
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.scroll-container {
+ white-space: nowrap;
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+ .scroll-wrapper {
+ position: absolute;
+ }
+}
+</style>
diff --git a/leave-school-vue/src/components/SvgIcon/index.vue b/leave-school-vue/src/components/SvgIcon/index.vue
new file mode 100644
index 0000000..e331a27
--- /dev/null
+++ b/leave-school-vue/src/components/SvgIcon/index.vue
@@ -0,0 +1,42 @@
+<template>
+ <svg :class="svgClass" aria-hidden="true">
+ <use :xlink:href="iconName"></use>
+ </svg>
+</template>
+
+<script>
+export default {
+ name: 'svg-icon',
+ props: {
+ iconClass: {
+ type: String,
+ required: true
+ },
+ className: {
+ type: String
+ }
+ },
+ computed: {
+ iconName() {
+ return `#icon-${this.iconClass}`
+ },
+ svgClass() {
+ if (this.className) {
+ return 'svg-icon ' + this.className
+ } else {
+ return 'svg-icon'
+ }
+ }
+ }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+ width: 1em;
+ height: 1em;
+ vertical-align: -0.15em;
+ fill: currentColor;
+ overflow: hidden;
+}
+</style>
diff --git a/leave-school-vue/src/components/UEditor/index.vue b/leave-school-vue/src/components/UEditor/index.vue
new file mode 100644
index 0000000..6f44fc1
--- /dev/null
+++ b/leave-school-vue/src/components/UEditor/index.vue
@@ -0,0 +1,64 @@
+<template>
+ <div>
+ <script id="editor" type="text/plain"></script>
+ </div>
+</template>
+<script>
+ export default {
+ name: 'UE',
+ data() {
+ return {
+ editor: null,
+ isReady: false,
+ isInit: false
+ }
+ },
+ props: {
+ value: {
+ type: String
+ },
+ config: {
+ type: Object
+ }
+ },
+ mounted() {
+ const _this = this
+ window.UE.delEditor('editor')
+ this.editor = window.UE.getEditor('editor', this.config) // 初始化UE
+ // this.editor.addListener('ready', function() {
+ // _this.editor.setContent(_this.defaultMsg) // 确保UE加载完成后,放入内容。
+ // })
+ this.editor.ready(() => {
+ _this.setContent(_this.value) // 确保UE加载完成后,放入内容。
+ _this.editor.addListener('contentChange', () => {
+ const content = _this.editor.getContent()
+ _this.$emit('input', content)
+ })
+
+ _this.$emit('ready', this.editor)
+ _this.isReady = true
+ })
+ },
+ methods: {
+ setContent(value) {
+ this.editor.setContent(value || '')
+ },
+ getUEContent() { // 获取内容方法
+ return this.editor.getContent()
+ }
+ },
+ watch: {
+ value(val) {
+ this.setContent(val)
+ }
+ },
+ destroyed() {
+ this.editor.destroy()
+ }
+ }
+</script>
+<style>
+.edui-editor-toolbarbox{
+ line-height:22px
+}
+</style>
diff --git a/leave-school-vue/src/directive/clipboard/clipboard.js b/leave-school-vue/src/directive/clipboard/clipboard.js
new file mode 100644
index 0000000..49c9b39
--- /dev/null
+++ b/leave-school-vue/src/directive/clipboard/clipboard.js
@@ -0,0 +1,49 @@
+// Inspired by https://github.com/Inndy/vue-clipboard2
+const Clipboard = require('clipboard')
+if (!Clipboard) {
+ throw new Error('you shold npm install `clipboard` --save at first ')
+}
+
+export default {
+ bind(el, binding) {
+ if (binding.arg === 'success') {
+ el._v_clipboard_success = binding.value
+ } else if (binding.arg === 'error') {
+ el._v_clipboard_error = binding.value
+ } else {
+ const clipboard = new Clipboard(el, {
+ text() { return binding.value },
+ action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+ })
+ clipboard.on('success', e => {
+ const callback = el._v_clipboard_success
+ callback && callback(e) // eslint-disable-line
+ })
+ clipboard.on('error', e => {
+ const callback = el._v_clipboard_error
+ callback && callback(e) // eslint-disable-line
+ })
+ el._v_clipboard = clipboard
+ }
+ },
+ update(el, binding) {
+ if (binding.arg === 'success') {
+ el._v_clipboard_success = binding.value
+ } else if (binding.arg === 'error') {
+ el._v_clipboard_error = binding.value
+ } else {
+ el._v_clipboard.text = function() { return binding.value }
+ el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
+ }
+ },
+ unbind(el, binding) {
+ if (binding.arg === 'success') {
+ delete el._v_clipboard_success
+ } else if (binding.arg === 'error') {
+ delete el._v_clipboard_error
+ } else {
+ el._v_clipboard.destroy()
+ delete el._v_clipboard
+ }
+ }
+}
diff --git a/leave-school-vue/src/directive/clipboard/index.js b/leave-school-vue/src/directive/clipboard/index.js
new file mode 100644
index 0000000..02c9816
--- /dev/null
+++ b/leave-school-vue/src/directive/clipboard/index.js
@@ -0,0 +1,13 @@
+import Clipboard from './clipboard'
+
+const install = function(Vue) {
+ Vue.directive('Clipboard', Clipboard)
+}
+
+if (window.Vue) {
+ window.clipboard = Clipboard
+ Vue.use(install); // eslint-disable-line
+}
+
+Clipboard.install = install
+export default Clipboard
diff --git a/leave-school-vue/src/directive/el-dragDialog/drag.js b/leave-school-vue/src/directive/el-dragDialog/drag.js
new file mode 100644
index 0000000..68e0852
--- /dev/null
+++ b/leave-school-vue/src/directive/el-dragDialog/drag.js
@@ -0,0 +1,77 @@
+export default{
+ bind(el, binding, vnode) {
+ const dialogHeaderEl = el.querySelector('.el-dialog__header')
+ const dragDom = el.querySelector('.el-dialog')
+ dialogHeaderEl.style.cssText += ';cursor:move;'
+ dragDom.style.cssText += ';top:0px;'
+
+ // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
+ const getStyle = (function() {
+ if (window.document.currentStyle) {
+ return (dom, attr) => dom.currentStyle[attr]
+ } else {
+ return (dom, attr) => getComputedStyle(dom, false)[attr]
+ }
+ })()
+
+ dialogHeaderEl.onmousedown = (e) => {
+ // 鼠标按下,计算当前元素距离可视区的距离
+ const disX = e.clientX - dialogHeaderEl.offsetLeft
+ const disY = e.clientY - dialogHeaderEl.offsetTop
+
+ const dragDomWidth = dragDom.offsetWidth
+ const dragDomheight = dragDom.offsetHeight
+
+ const screenWidth = document.body.clientWidth
+ const screenHeight = document.body.clientHeight
+
+ const minDragDomLeft = dragDom.offsetLeft
+ const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
+
+ const minDragDomTop = dragDom.offsetTop
+ const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight
+
+ // 获取到的值带px 正则匹配替换
+ let styL = getStyle(dragDom, 'left')
+ let styT = getStyle(dragDom, 'top')
+
+ if (styL.includes('%')) {
+ styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
+ styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
+ } else {
+ styL = +styL.replace(/\px/g, '')
+ styT = +styT.replace(/\px/g, '')
+ }
+
+ document.onmousemove = function(e) {
+ // 通过事件委托,计算移动的距离
+ let left = e.clientX - disX
+ let top = e.clientY - disY
+
+ // 边界处理
+ if (-(left) > minDragDomLeft) {
+ left = -minDragDomLeft
+ } else if (left > maxDragDomLeft) {
+ left = maxDragDomLeft
+ }
+
+ if (-(top) > minDragDomTop) {
+ top = -minDragDomTop
+ } else if (top > maxDragDomTop) {
+ top = maxDragDomTop
+ }
+
+ // 移动当前元素
+ dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
+
+ // emit onDrag event
+ vnode.child.$emit('dragDialog')
+ }
+
+ document.onmouseup = function(e) {
+ document.onmousemove = null
+ document.onmouseup = null
+ }
+ }
+ }
+}
diff --git a/leave-school-vue/src/directive/el-dragDialog/index.js b/leave-school-vue/src/directive/el-dragDialog/index.js
new file mode 100644
index 0000000..29facbf
--- /dev/null
+++ b/leave-school-vue/src/directive/el-dragDialog/index.js
@@ -0,0 +1,13 @@
+import drag from './drag'
+
+const install = function(Vue) {
+ Vue.directive('el-drag-dialog', drag)
+}
+
+if (window.Vue) {
+ window['el-drag-dialog'] = drag
+ Vue.use(install); // eslint-disable-line
+}
+
+drag.install = install
+export default drag
diff --git a/leave-school-vue/src/directive/permission/index.js b/leave-school-vue/src/directive/permission/index.js
new file mode 100644
index 0000000..e5dadd3
--- /dev/null
+++ b/leave-school-vue/src/directive/permission/index.js
@@ -0,0 +1,13 @@
+import permission from './permission'
+
+const install = function(Vue) {
+ Vue.directive('permission', permission)
+}
+
+if (window.Vue) {
+ window['permission'] = permission
+ Vue.use(install); // eslint-disable-line
+}
+
+permission.install = install
+export default permission
diff --git a/leave-school-vue/src/directive/permission/permission.js b/leave-school-vue/src/directive/permission/permission.js
new file mode 100644
index 0000000..17b85d7
--- /dev/null
+++ b/leave-school-vue/src/directive/permission/permission.js
@@ -0,0 +1,23 @@
+
+import store from '@/store'
+
+export default{
+ inserted(el, binding, vnode) {
+ const { value } = binding
+ const roles = store.getters && store.getters.roles
+
+ if (value && value instanceof Array && value.length > 0) {
+ const permissionRoles = value
+
+ const hasPermission = roles.some(role => {
+ return permissionRoles.includes(role)
+ })
+
+ if (!hasPermission) {
+ el.parentNode && el.parentNode.removeChild(el)
+ }
+ } else {
+ throw new Error(`need roles! Like v-permission="['admin','editor']"`)
+ }
+ }
+}
diff --git a/leave-school-vue/src/directive/sticky.js b/leave-school-vue/src/directive/sticky.js
new file mode 100644
index 0000000..bc23466
--- /dev/null
+++ b/leave-school-vue/src/directive/sticky.js
@@ -0,0 +1,91 @@
+const vueSticky = {}
+let listenAction
+vueSticky.install = Vue => {
+ Vue.directive('sticky', {
+ inserted(el, binding) {
+ const params = binding.value || {}
+ const stickyTop = params.stickyTop || 0
+ const zIndex = params.zIndex || 1000
+ const elStyle = el.style
+
+ elStyle.position = '-webkit-sticky'
+ elStyle.position = 'sticky'
+ // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
+ // if (~elStyle.position.indexOf('sticky')) {
+ // elStyle.top = `${stickyTop}px`;
+ // elStyle.zIndex = zIndex;
+ // return
+ // }
+ const elHeight = el.getBoundingClientRect().height
+ const elWidth = el.getBoundingClientRect().width
+ elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
+
+ const parentElm = el.parentNode || document.documentElement
+ const placeholder = document.createElement('div')
+ placeholder.style.display = 'none'
+ placeholder.style.width = `${elWidth}px`
+ placeholder.style.height = `${elHeight}px`
+ parentElm.insertBefore(placeholder, el)
+
+ let active = false
+
+ const getScroll = (target, top) => {
+ const prop = top ? 'pageYOffset' : 'pageXOffset'
+ const method = top ? 'scrollTop' : 'scrollLeft'
+ let ret = target[prop]
+ if (typeof ret !== 'number') {
+ ret = window.document.documentElement[method]
+ }
+ return ret
+ }
+
+ const sticky = () => {
+ if (active) {
+ return
+ }
+ if (!elStyle.height) {
+ elStyle.height = `${el.offsetHeight}px`
+ }
+
+ elStyle.position = 'fixed'
+ elStyle.width = `${elWidth}px`
+ placeholder.style.display = 'inline-block'
+ active = true
+ }
+
+ const reset = () => {
+ if (!active) {
+ return
+ }
+
+ elStyle.position = ''
+ placeholder.style.display = 'none'
+ active = false
+ }
+
+ const check = () => {
+ const scrollTop = getScroll(window, true)
+ const offsetTop = el.getBoundingClientRect().top
+ if (offsetTop < stickyTop) {
+ sticky()
+ } else {
+ if (scrollTop < elHeight + stickyTop) {
+ reset()
+ }
+ }
+ }
+ listenAction = () => {
+ check()
+ }
+
+ window.addEventListener('scroll', listenAction)
+ },
+
+ unbind() {
+ window.removeEventListener('scroll', listenAction)
+ }
+ })
+}
+
+export default vueSticky
+
diff --git a/leave-school-vue/src/directive/waves/index.js b/leave-school-vue/src/directive/waves/index.js
new file mode 100644
index 0000000..65f9b30
--- /dev/null
+++ b/leave-school-vue/src/directive/waves/index.js
@@ -0,0 +1,13 @@
+import waves from './waves'
+
+const install = function(Vue) {
+ Vue.directive('waves', waves)
+}
+
+if (window.Vue) {
+ window.waves = waves
+ Vue.use(install); // eslint-disable-line
+}
+
+waves.install = install
+export default waves
diff --git a/leave-school-vue/src/directive/waves/waves.css b/leave-school-vue/src/directive/waves/waves.css
new file mode 100644
index 0000000..af7a7ef
--- /dev/null
+++ b/leave-school-vue/src/directive/waves/waves.css
@@ -0,0 +1,26 @@
+.waves-ripple {
+ position: absolute;
+ border-radius: 100%;
+ background-color: rgba(0, 0, 0, 0.15);
+ background-clip: padding-box;
+ pointer-events: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-transform: scale(0);
+ -ms-transform: scale(0);
+ transform: scale(0);
+ opacity: 1;
+}
+
+.waves-ripple.z-active {
+ opacity: 0;
+ -webkit-transform: scale(2);
+ -ms-transform: scale(2);
+ transform: scale(2);
+ -webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+ transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
+ transition: opacity 1.2s ease-out, transform 0.6s ease-out;
+ transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
+}
\ No newline at end of file
diff --git a/leave-school-vue/src/directive/waves/waves.js b/leave-school-vue/src/directive/waves/waves.js
new file mode 100644
index 0000000..ac1d861
--- /dev/null
+++ b/leave-school-vue/src/directive/waves/waves.js
@@ -0,0 +1,42 @@
+import './waves.css'
+
+export default{
+ bind(el, binding) {
+ el.addEventListener('click', e => {
+ const customOpts = Object.assign({}, binding.value)
+ const opts = Object.assign({
+ ele: el, // 波纹作用元素
+ type: 'hit', // hit点击位置扩散center中心点扩展
+ color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
+ }, customOpts)
+ const target = opts.ele
+ if (target) {
+ target.style.position = 'relative'
+ target.style.overflow = 'hidden'
+ const rect = target.getBoundingClientRect()
+ let ripple = target.querySelector('.waves-ripple')
+ if (!ripple) {
+ ripple = document.createElement('span')
+ ripple.className = 'waves-ripple'
+ ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
+ target.appendChild(ripple)
+ } else {
+ ripple.className = 'waves-ripple'
+ }
+ switch (opts.type) {
+ case 'center':
+ ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
+ ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
+ break
+ default:
+ ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
+ ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
+ }
+ ripple.style.backgroundColor = opts.color
+ ripple.className = 'waves-ripple z-active'
+ return false
+ }
+ }, false)
+ }
+}
+
diff --git a/leave-school-vue/src/icons/index.js b/leave-school-vue/src/icons/index.js
new file mode 100644
index 0000000..14e2e13
--- /dev/null
+++ b/leave-school-vue/src/icons/index.js
@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg组件
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+const req = require.context('./svg', false, /\.svg$/)
+requireAll(req)
diff --git a/leave-school-vue/src/icons/svg/auditscope.svg b/leave-school-vue/src/icons/svg/auditscope.svg
new file mode 100644
index 0000000..caeee14
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/auditscope.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534236379796" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6232" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M853.333333 597.333333a108.8 108.8 0 1 0 108.373334 108.8A108.8 108.8 0 0 0 853.333333 597.333333z m-341.333333-336.64a109.226667 109.226667 0 1 0-108.373333-108.8A108.8 108.8 0 0 0 512 260.693333z m361.813333 270.506667a170.666667 170.666667 0 0 1 66.986667 23.04v-4.693333a432.213333 432.213333 0 0 0-256-393.813334 170.666667 170.666667 0 0 1-14.933333 67.413334 364.373333 364.373333 0 0 1 203.946666 308.053333z m-593.066666 173.653333A108.373333 108.373333 0 1 0 170.666667 813.653333a108.8 108.8 0 0 0 110.08-108.8z m-130.56-173.653333a365.226667 365.226667 0 0 1 202.24-308.48 167.253333 167.253333 0 0 1-14.933334-66.986667 432.213333 432.213333 0 0 0-256 393.813334A17.493333 17.493333 0 0 0 85.333333 554.666667a164.693333 164.693333 0 0 1 64.853334-23.466667z m361.813333 384a359.253333 359.253333 0 0 1-224-78.506667 172.8 172.8 0 0 1-61.44 35.413334 426.666667 426.666667 0 0 0 570.88 0 172.8 172.8 0 0 1-61.44-35.413334A359.253333 359.253333 0 0 1 512 914.346667z" p-id="6233" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/autoaudittype.svg b/leave-school-vue/src/icons/svg/autoaudittype.svg
new file mode 100644
index 0000000..6571bd9
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/autoaudittype.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534317281622" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5281" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M982.426224 413.309681h-41.254217c-8.250843-49.505059-33.067333-90.759275-57.755902-132.013491l33.003373-33.003373a39.783136 39.783136 0 0 0 0-57.755903l-82.508432-82.572392a39.847096 39.847096 0 0 0-57.755903 0l-33.003373 33.003373c-41.318176-24.75253-82.572392-41.254216-132.013491-57.755902v-41.318177c0-24.75253-16.565646-41.254216-41.318177-41.254216h-115.575765c-24.75253 0-41.254216 16.501686-41.254216 41.254216v41.318177c-49.505059 16.501686-90.759275 33.003373-132.013491 57.755902l-33.003373-33.003373a39.847096 39.847096 0 0 0-57.755903 0l-82.572392 82.572392a39.911056 39.911056 0 0 0 0 57.755903l33.003373 33.003373c-24.75253 41.254216-41.254216 82.508432-57.755903 132.013491h-41.318176c-24.75253 0-41.254216 16.501686-41.254216 41.254217v115.575765c0 24.75253 16.501686 41.318176 41.254216 41.318176h41.318176c8.250843 49.441099 33.003373 90.759275 57.755903 132.013491l-33.003373 33.003373a39.847096 39.847096 0 0 0 0 57.755903l82.572392 82.508432a39.783136 39.783136 0 0 0 57.755903 0l33.003373-33.003373c41.254216 24.75253 82.508432 41.254216 132.013491 57.755903v41.254216c0 24.81649 16.501686 41.318176 41.254216 41.318176h115.575765c24.75253 0 41.318176-16.501686 41.318177-41.318176v-41.254216c49.441099-8.250843 90.759275-33.067333 132.013491-57.755903l33.003373 33.003373a39.783136 39.783136 0 0 0 57.755903 0l82.508432-82.508432a39.783136 39.783136 0 0 0 0-57.755903l-33.003373-33.003373c24.75253-41.318176 41.254216-82.572392 57.755902-132.013491h41.254217c24.81649 0 41.318176-16.565646 41.318176-41.318176v-115.575765c0-24.81649-16.501686-41.254216-41.318176-41.254217zM512.0642 867.233979c-198.084197 0-354.850219-156.829981-354.850219-354.914179s156.829981-354.850219 354.850219-354.850218 354.914179 156.829981 354.914179 354.850218-156.829981 354.914179-354.914179 354.914179z" p-id="5282" fill="#bfcbd9"></path><path d="M521.530284 630.390006s1.599001-70.803748 1.599-92.869956c-127.40837-28.334291-209.277202 125.809369-228.209369 166.679825-1.407121-309.950281 228.273329-295.687196 228.273329-295.687195V320.439725l206.015241 155.806621-207.678201 154.14366z" p-id="5283" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/class.svg b/leave-school-vue/src/icons/svg/class.svg
new file mode 100644
index 0000000..8a34e00
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/class.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534126168778" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4526" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M314.88 331.264c0 48.64-22.016 91.648-56.32 120.832 5.632-1.536 11.264-3.072 17.408-4.096 30.72-6.656 59.904-9.728 84.48-9.216l97.792-133.632c27.136-36.864 76.8-47.104 110.592-22.528l15.36 11.264c34.304 24.576 39.936 74.752 12.8 111.616l-118.272 161.792c-3.072 2.56-6.144 5.12-9.728 8.192-66.048 62.464-108.032 8.192-112.128 83.456h-0.512V742.4h312.832c-17.408 0-31.232-13.824-31.232-31.232v-21.504c0-16.896 13.824-30.72 31.232-30.72h120.32c17.408 0 31.232 13.824 31.232 30.72v21.504c0 16.896-13.824 31.232-31.232 31.232h101.888c38.912 0 70.144-30.72 70.144-68.608V198.656c0-37.888-31.744-68.608-70.144-68.608H188.416C158.208 129.536 132.608 148.48 122.88 174.592c9.728-2.048 19.968-3.072 30.72-3.072 89.088 0 161.28 71.68 161.28 159.744z m-158.72 109.568c58.88 0 106.496-47.616 106.496-107.008S215.04 227.328 156.16 227.328s-106.496 48.128-106.496 107.008 47.616 106.496 106.496 106.496zM440.32 545.792c1.536-1.536 12.288-19.456 13.312-20.992l102.4-141.824c12.288-17.408 9.728-40.96-6.144-52.224l-7.168-5.12c-15.872-11.776-38.912-6.656-51.712 10.752l-99.328 137.216-164.864 20.992c-0.512 0-0.512 0.512-1.024 0.512-2.56-0.512-5.12-0.512-7.68-0.512H117.248m1.024 0h-24.064c-49.152 0-88.576 39.936-88.576 89.088v222.72c0 39.936 26.112 73.216 62.464 84.48 5.12 2.56 11.264 4.608 17.408 4.608h0.512c0-0.512-0.512-0.512-0.512-1.024 3.072 0.512 5.632 1.024 8.704 1.024h124.416c49.152 0 88.576-39.936 88.576-89.088v-220.16l116.224-27.648c8.192-4.608 12.8-8.192 16.384-12.288m541.696 251.904H360.96c-0.512 6.144-0.512 12.288-1.536 18.944-3.584 28.672-13.312 55.296-27.136 77.824h649.216c20.992 0 37.888-16.896 37.888-37.376v-22.528c-0.512-19.968-17.408-36.864-37.888-36.864z" fill="#bfcbd9" p-id="4527"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/department.svg b/leave-school-vue/src/icons/svg/department.svg
new file mode 100644
index 0000000..42683bd
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/department.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1533692675234" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="698" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M955.712 277.312 955.712 0 68.288 0 68.288 277.312 0 277.312 0 1024 204.8 1024 204.8 277.312 136.512 277.312 136.512 68.288 477.888 68.288 477.888 277.312 409.6 277.312 409.6 1024 614.4 1024 614.4 277.312 546.112 277.312 546.112 68.288 887.488 68.288 887.488 277.312 819.2 277.312 819.2 1024 1024 1024 1024 277.312Z" p-id="699" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/departmentleader.svg b/leave-school-vue/src/icons/svg/departmentleader.svg
new file mode 100644
index 0000000..3846008
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/departmentleader.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534323504305" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14427" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M753.031484 302.44078c-5.629185-8.69965-12.793603-14.84058-18.934532-18.934533 0-10.746627-0.511744-26.098951-3.070465-44.009995 1.535232-20.981509 7.676162-137.65917-63.456272-189.857072-44.009995-32.751624-93.137431-49.63918-141.753124-49.63918C486.412794 0 449.055472 11.258371 419.886057 31.728136c-26.098951 18.422789-40.427786 38.38081-47.592204 52.197901-22.516742 1.023488-68.573713 9.723138-89.043478 69.085457-19.446277 55.78011-3.582209 90.578711 7.676162 106.442779-0.511744 9.211394-1.023488 17.3993-1.023489 24.051974-6.652674 4.093953-13.305347 10.234883-18.934532 18.934533-12.793603 19.958021-14.84058 46.568716-6.652674 78.808595C280.17991 442.146927 317.537231 455.452274 337.495252 458.010995c12.281859 24.563718 38.892554 74.202899 66.014993 99.27836 10.746627 10.234883 24.563718 18.422789 41.451274 25.075463 21.493253 8.69965 44.009995 12.793603 67.038481 12.793603s46.056972-4.093953 67.038481-12.793603c16.887556-6.652674 30.704648-15.352324 41.451274-25.075463 27.122439-25.075462 53.733133-75.226387 66.014993-99.27836 19.958021-2.558721 56.803598-15.864068 73.17941-77.273364 8.69965-32.23988 6.14093-58.850575-6.652674-78.296851z m-38.892553 67.03848c-9.723138 37.357321-27.122439 42.474763-36.333834 42.474763h-1.535232c-10.746627-2.558721-20.981509 3.070465-25.587206 13.305347-9.211394 19.958021-38.38081 76.249875-61.92104 98.254873-6.652674 6.14093-15.352324 11.258371-26.610694 15.864068-31.728136 12.793603-68.061969 12.793603-99.790105 0-11.258371-4.605697-20.469765-9.723138-26.610695-15.864068C411.698151 501.509245 382.528736 445.217391 373.317341 425.25937c-4.093953-8.69965-11.770115-13.817091-19.958021-13.817091-1.535232 0-3.582209 0-5.629185 0.511744h-1.535232c-9.211394 0-26.610695-5.629185-36.333834-42.474763-4.605697-18.422789-4.605697-32.751624 0-40.93953 3.070465-4.605697 6.652674-6.14093 8.187907-6.652674 12.793603-1.535232 19.958021-12.281859 18.934532-25.075462 0-0.511744-1.023488-11.258371 0-27.634183 15.864068-7.164418 41.963018-20.469765 63.456272-44.009995 11.258371-11.770115 18.934533-26.610695 25.075462-39.916042 15.864068 12.793603 37.869065 27.634183 67.038481 40.939531 50.150925 22.516742 150.964518 32.751624 193.43928 36.333833 1.535232 19.958021 0.511744 33.775112 0.511745 34.286856-1.023488 12.793603 6.652674 23.54023 18.934532 25.075462 1.535232 0.511744 5.117441 2.046977 8.187906 6.652674 5.629185 7.676162 5.629185 22.516742 0.511745 40.93953z m150.452773 312.675663l-204.697651-81.879061c-5.629185-2.558721-12.281859-2.046977-18.422789 0.511744-5.629185 2.558721-10.234883 7.676162-12.281859 13.305348l-51.686157 142.264867-10.234882-29.169415 16.375812-39.404298c3.070465-7.164418 2.046977-15.352324-2.046977-22.004998-4.093953-6.652674-11.770115-10.234883-19.446276-10.234882H461.849075c-7.676162 0-14.84058 4.093953-19.446276 10.234882-4.605697 6.652674-5.117441 14.84058-2.046977 22.004998l16.375812 39.404298-10.234882 29.169415L394.810595 614.092954c-2.046977-6.14093-6.652674-10.746627-12.281859-13.305348-5.629185-2.558721-12.281859-2.558721-18.422789-0.511744l-204.697651 81.879061c-62.944528 25.075462-103.372314 84.949525-103.372314 153.011494v165.293353c0 12.793603 10.746627 23.54023 23.54023 23.54023h865.35932c12.793603 0 23.54023-10.746627 23.54023-23.54023v-165.293353c-0.511744-68.061969-40.93953-127.936032-103.884058-153.011494z m-7.164418 220.049975c0 12.793603-10.234883 23.54023-23.54023 23.540229h-157.105447c-12.793603 0-23.54023-10.746627-23.54023-23.540229V829.025487c0-12.793603 10.234883-23.54023 23.54023-23.54023h157.105447c12.793603 0 23.54023 10.234883 23.54023 23.54023v73.179411z" p-id="14428" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/dictionary.svg b/leave-school-vue/src/icons/svg/dictionary.svg
new file mode 100644
index 0000000..8ba8165
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/dictionary.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1533692171706" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2009" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M966.4 147.2V57.6h-83.2v192h83.2zM883.2 326.4h57.6v192h-57.6zM0 70.4v857.6c0 57.6 44.8 96 96 96h729.6v-57.6H96c-19.2 0-32-12.8-32-32s12.8-32 32-32h729.6V0H70.4C38.4 6.4 6.4 38.4 0 70.4z m268.8 147.2h416v70.4H268.8V217.6z m0 192h416v70.4H268.8V409.6z m0 198.4h416v70.4H268.8V608zM128 217.6h70.4v70.4H128V217.6z m0 192h70.4v70.4H128V409.6z m0 198.4h70.4v70.4H128V608zM883.2 601.6h121.6v198.4h-121.6z" fill="#bfcbd9" p-id="2010"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/example.svg b/leave-school-vue/src/icons/svg/example.svg
new file mode 100644
index 0000000..19cd9ed
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/example.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1511504199105" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1815" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M770.56 460.8h250.88C998.4 220.16 803.84 25.6 563.2 2.56v250.88c104.96 20.48 186.88 102.4 207.36 207.36z m0 0M460.8 253.44V2.56C220.16 25.6 25.6 220.16 2.56 460.8h250.88c20.48-104.96 102.4-186.88 207.36-207.36z m0 0M563.2 770.56v250.88c243.2-23.04 435.2-217.6 460.8-460.8H773.12C750.08 668.16 668.16 750.08 563.2 770.56z m0 0M253.44 563.2H2.56c23.04 243.2 217.6 435.2 460.8 460.8V773.12C355.84 750.08 273.92 668.16 253.44 563.2z m0 0" fill="" p-id="1816"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/eye.svg b/leave-school-vue/src/icons/svg/eye.svg
new file mode 100644
index 0000000..194aa45
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/eye.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503993826520" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7878" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M941.677063 391.710356c9.337669-14.005992 6.224772-32.68133-6.224772-43.575447-14.005992-10.894118-32.68133-7.78122-43.575447 6.224771-1.556449 1.556449-174.300768 205.426673-379.727441 205.426673-199.200878 0-379.727441-205.426673-381.28389-206.982098-10.894118-12.450567-31.124881-14.005992-43.575448-3.112898-12.450567 10.894118-14.005992 31.124881-3.112897 43.575448 3.112897 4.668323 40.46255 46.687322 99.600439 93.375667l-79.369676 82.48155c-12.450567 12.450567-10.894118 32.68133 1.556449 43.575448 3.112897 6.224772 10.894118 9.337669 18.675338 9.337669 7.78122 0 15.562441-3.112897 21.787213-9.337669l85.594447-88.706321c40.46255 28.013007 88.706321 54.469566 141.619438 73.14388L340.959485 707.631586c-4.668323 17.118889 4.669346 34.237779 21.787213 38.906101h9.337669c14.005992 0 26.456558-9.337669 29.568432-23.343661l32.68133-110.494556c24.90011 4.668323 51.356668 7.78122 77.813227 7.78122s52.913117-3.112897 77.813227-7.78122l32.68133 108.938108c3.112897 14.005992 17.118889 23.343661 29.569456 23.343661 3.112897 0 6.224772 0 7.78122-1.556449 17.118889-4.669346 26.456558-21.787212 21.788236-38.906102l-32.68133-108.938108c52.913117-18.675338 101.156888-45.131897 141.619438-73.14388l84.037998 87.150896c6.224772 6.224772 14.005992 9.337669 21.787212 9.337669 7.78122 0 15.562441-3.112897 21.787212-9.337669 12.450567-12.450567 12.450567-31.124881 1.556449-43.575448l-79.369675-82.48155c63.808258-46.688345 101.158934-91.820242 101.158934-91.820242z" p-id="7879"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/form.svg b/leave-school-vue/src/icons/svg/form.svg
new file mode 100644
index 0000000..d848c8a
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/form.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1511504319223" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3230" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M942.827259 80.3367c-11.42419-11.406794-26.41051-17.117866-41.377386-17.117866-14.985296 0-29.952172 5.711072-41.358967 17.117866L719.392444 221.014696l-19.441794 19.441794L681.577187 258.832 569.516971 370.909611 375.99749 564.411697l0 0.019443 0 84.372619 81.145112 0 0.010233 0 95.418186-95.435583 213.398228-213.400275 3.14155-3.14155-0.019443 0 9.979282-9.977235 0 0L942.827259 163.073052C965.697129 140.259464 965.697129 103.186104 942.827259 80.3367z" p-id="3231"></path><path d="M793.542234 367.521444 580.14196 580.939115 484.72582 676.376745 473.299583 687.800935 457.152834 687.800935 375.99749 687.800935 337.000314 687.800935 337.000314 648.803759 337.000314 564.411697 337.000314 548.264948 348.424504 536.838711 541.943986 343.338672 654.004201 231.259014 665.428392 219.834824 64.020082 219.834824 64.020082 960.781166 804.966425 960.781166 804.966425 356.116697 796.607036 364.475062Z" p-id="3232"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/instructor.svg b/leave-school-vue/src/icons/svg/instructor.svg
new file mode 100644
index 0000000..3a353ce
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/instructor.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534323547622" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14768" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M913.8176 786.688C892.672 721.2032 860.16 660.48 820.224 623.104l-10.496-3.4304H332.2368l-114.176 1.1264h-9.6256l-7.4752 6.2976c-52.224 45.1584-82.8416 111.0528-100.6592 178.1248A789.2992 789.2992 0 0 0 76.8 985.856l-0.512 26.0096H936.96l8.96-17.0496c6.4-59.0848-9.8816-139.776-32.1024-208.128zM479.0784 670.72l1.3312-28.0064a509.7984 509.7984 0 0 1 73.1136 0l1.3312 28.0064-16.7424 27.392 49.92 177.408-68.2496 51.2-68.1984-51.2 44.1856-177.2544z" p-id="14769" fill="#bfcbd9"></path><path d="M762.0096 282.0096l-10.24-6.8608c-1.2288-0.8704-2.4576-1.6384-3.6864-2.3552-20.992-180.2752-19.5584-286.72-230.0416-255.1296C444.2112 28.6208 363.52 5.888 317.8496 39.2192 260.1472 93.0816 256 174.08 271.6672 268.9024a115.0976 115.0976 0 0 0-10.24 6.2976l-10.24 6.8608v12.1856c-0.512 31.5904 3.4816 58.3168 12.0832 78.7456a79.2576 79.2576 0 0 0 34.7648 40.96C316.0064 475.648 342.3232 522.24 375.296 555.5712a227.2256 227.2256 0 0 0 128 65.4336l4.352 0.6656 4.352-0.8704c54.1696-11.3664 97.28-32.9728 131.84-69.12 32-33.4848 55.8592-78.6432 73.3696-139.008a80.1792 80.1792 0 0 0 33.4336-40.96c8.2432-20.48 11.9808-46.4896 11.52-77.4656zM706.56 354.048c-4.1984 10.24-9.9328 16.9984-17.2032 19.5072l-11.9296 4.1984-3.2256 12.0832c-15.6672 57.9072-36.608 99.84-64.7168 129.28-26.5728 27.7504-60.16 44.8512-102.4 54.4256a179.2 179.2 0 0 1-97.28-50.8416c-29.2864-29.7472-52.6848-72.9088-68.9152-132.2496l-3.4304-12.6464-12.9536-4.0448c-7.3728-2.2528-13.2608-8.8576-17.5104-19.0976a121.6512 121.6512 0 0 1-7.9872-38.2464c11.6224-1.7408 24.576-5.12 30.72-0.8704 0.768-2.0992 1.4336-4.5568 2.2016-7.3728h0.3584l0.9216-5.12c3.4304-13.7216 7.3728-100.0448 10.8544-113.92a39.168 39.168 0 0 1 4.5568-11.9296c16.9472 22.9888 145.2544 25.6 219.7504-25.6l-13.9264 37.4784 14.1312 2.816 15.9232-25.2416-1.7408 17.664 15.0016 1.9456 9.3696-29.0304c18.4832 10.5472 38.912 24.6272 57.088 16.9984 6.144 13.6192 10.752 96.7168 13.824 112.64l3.9424 20.48 6.8608-0.4608 3.1744 10.752a201.8304 201.8304 0 0 1 22.1184-1.3312 124.5696 124.5696 0 0 1-7.5776 37.7344z" p-id="14770" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/major.svg b/leave-school-vue/src/icons/svg/major.svg
new file mode 100644
index 0000000..86f686d
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/major.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1533801155292" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2084" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M372.363636 0H93.090909C41.890909 0 0 41.890909 0 93.090909v279.272727c0 51.2 41.890909 93.090909 93.090909 93.090909h279.272727c51.2 0 93.090909-41.890909 93.090909-93.090909V93.090909c0-51.2-41.890909-93.090909-93.090909-93.090909z m0 558.545455H93.090909c-51.2 0-93.090909 41.890909-93.090909 93.090909v279.272727c0 51.2 41.890909 93.090909 93.090909 93.090909h279.272727c51.2 0 93.090909-41.890909 93.090909-93.090909V651.636364c0-51.2-41.890909-93.090909-93.090909-93.090909z m209.454546-418.909091h418.909091c13.963636 0 23.272727-9.309091 23.272727-23.272728s-9.309091-23.272727-23.272727-23.272727H581.818182c-13.963636 0-23.272727 9.309091-23.272727 23.272727s9.309091 23.272727 23.272727 23.272728z m418.909091 186.181818H581.818182c-13.963636 0-23.272727 9.309091-23.272727 23.272727s9.309091 23.272727 23.272727 23.272727h418.909091c13.963636 0 23.272727-9.309091 23.272727-23.272727s-9.309091-23.272727-23.272727-23.272727z m0 325.818182H581.818182c-13.963636 0-23.272727 9.309091-23.272727 23.272727s9.309091 23.272727 23.272727 23.272727h418.909091c13.963636 0 23.272727-9.309091 23.272727-23.272727s-9.309091-23.272727-23.272727-23.272727z m0 232.727272H581.818182c-13.963636 0-23.272727 9.309091-23.272727 23.272728s9.309091 23.272727 23.272727 23.272727h418.909091c13.963636 0 23.272727-9.309091 23.272727-23.272727s-9.309091-23.272727-23.272727-23.272728z" fill="#bfcbd9" p-id="2085"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/nested.svg b/leave-school-vue/src/icons/svg/nested.svg
new file mode 100644
index 0000000..f564197
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/nested.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1529559567446" class="icon" style="" viewBox="0 0 1167 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1767" xmlns:xlink="http://www.w3.org/1999/xlink" width="227.9296875" height="200"><defs><style type="text/css"></style></defs><path d="M0.015952 74.459413A2.286 2.286 1440 1 0 145.85218 74.459413 2.286 2.286 1440 1 0 0.015952 74.459413zM291.720312 1.525347 1166.801488 1.525347 1166.801488 147.361574 291.720312 147.361574zM291.720312 366.163773A2.286 2.286 1440 1 0 437.55654 366.163773 2.286 2.286 1440 1 0 291.720312 366.163773zM583.424672 293.229707 1166.801488 293.229707 1166.801488 439.065934 583.424672 439.065934zM291.720312 949.540588A2.286 2.286 1440 1 0 437.55654 949.540588 2.286 2.286 1440 1 0 291.720312 949.540588zM583.424672 876.638427 1166.801488 876.638427 1166.801488 1022.474654 583.424672 1022.474654zM583.424672 657.836228A2.286 2.286 1440 1 0 729.2609 657.836228 2.286 2.286 1440 1 0 583.424672 657.836228zM875.129032 584.934067 1166.801488 584.934067 1166.801488 730.770294 875.129032 730.770294z" p-id="1768"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/news.svg b/leave-school-vue/src/icons/svg/news.svg
new file mode 100644
index 0000000..9726ebc
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/news.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534323777905" class="icon" style="" viewBox="0 0 1026 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15549" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.390625" height="200"><defs><style type="text/css"></style></defs><path d="M93.676 1021.871H21.293c-12.773 0-21.289-8.515-21.289-21.289V229.921c0-12.773 8.516-21.289 21.29-21.289h70.253c12.773 0 21.289 8.516 21.289 21.289v770.661c2.129 12.774-8.516 21.29-19.16 21.29zM979.298 0H195.863c-23.418 0-42.578 19.16-42.578 42.578v938.844c0 23.418 19.16 42.578 42.578 42.578h785.563c23.418 0 42.578-19.16 42.578-42.578V42.578C1021.876 19.16 1004.844 0 979.298 0z m-504.55 172.44H625.9v38.32H513.07v57.481H625.9v38.32H513.07v57.48H625.9v38.32H474.75v-229.92z m-227.791 0h57.48l76.64 151.153V172.44h57.48v227.792h-57.48l-76.64-155.41 2.129 155.41h-57.48V172.44zM510.94 853.689H246.957v-57.48H510.94v57.48z m0-151.152H246.957v-57.48H510.94v57.48z m0-151.151H246.957v-57.48H510.94v57.48z m378.944 302.303H587.58V493.904h302.304v359.784z m0-453.455h-57.48l-40.45-172.44-36.19 172.44h-57.481L664.221 172.44h38.32l38.32 170.312 38.32-170.312h38.32l38.32 170.312 38.32-170.312h38.32l-42.577 227.792z" p-id="15550" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/newspublish.svg b/leave-school-vue/src/icons/svg/newspublish.svg
new file mode 100644
index 0000000..fc50604
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/newspublish.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534323833079" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15976" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M704 896h96v64h-96z" p-id="15977" fill="#bfcbd9"></path><path d="M736 960H64V64h544v64H128v768h608z" p-id="15978" fill="#bfcbd9"></path><path d="M640 64h64v704h-64zM576 64h64v64h-64z" p-id="15979" fill="#bfcbd9"></path><path d="M800 960c-89.6 0-160-80-160-176V480h320v307.2c0 96-73.6 172.8-160 172.8z m-96-172.8c0 60.8 44.8 108.8 96 108.8s96-48 96-108.8V544h-192v243.2zM448 569.6h-60.8c-76.8-108.8-115.2-166.4-118.4-172.8-6.4-12.8-12.8-19.2-16-25.6v198.4H198.4V304h64c73.6 108.8 112 166.4 115.2 169.6 9.6 12.8 12.8 22.4 16 25.6V304H448v265.6z" p-id="15980" fill="#bfcbd9"></path><path d="M454.4 576H384l-3.2-3.2c-112-166.4-115.2-169.6-118.4-172.8 0-3.2-3.2-3.2-3.2-6.4V576H192V297.6h73.6l3.2 3.2c89.6 134.4 112 166.4 115.2 169.6 0 3.2 3.2 3.2 3.2 6.4V297.6h67.2V576z m-64-12.8h51.2V310.4h-41.6V505.6h-12.8l-3.2-6.4-12.8-25.6c-3.2-6.4-41.6-60.8-112-169.6H204.8v252.8h41.6v-144-48l-3.2-35.2 16 28.8c3.2 6.4 9.6 12.8 16 25.6 3.2 12.8 19.2 38.4 115.2 179.2zM192 720h384v64H192z" p-id="15981" fill="#bfcbd9"></path><path d="M512 512h64v64h-64z" p-id="15982" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/newview.svg b/leave-school-vue/src/icons/svg/newview.svg
new file mode 100644
index 0000000..bc62b7e
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/newview.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534323895725" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16789" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1014.846412 968.747605l-40.735773 38.189787c-15.275915 15.275915-42.008766 15.275915-57.284681 0l-162.943093-152.759149c-39.46278 21.640879-85.290525 34.370809-133.664256 34.370809-143.848199 0-268.601504-114.569362-272.420483-249.506611L142.846268 639.042441l0-63.649646 212.589816 0c6.364965-22.913872 15.275915-44.554752 26.732851-63.649646L142.846268 511.74315l0-63.649646 292.788369 0-1.272993 1.272993c47.100738-40.735773 109.47739-66.195631 178.219008-66.195631 146.394185 0 273.693476 118.388341 273.693476 255.871575 0 47.100738-14.002922 91.65549-38.189787 128.572284l160.397107 152.759149C1025.030355 935.649789 1030.122326 954.744683 1014.846412 968.747605L1014.846412 968.747605zM612.580652 459.550441c-101.839433 0-183.310979 77.652568-183.310979 171.854043 0 95.474468 90.382497 179.492 190.948937 179.492 101.839433 0 183.310979-77.652568 183.310979-171.854043S713.147092 459.550441 612.580652 459.550441L612.580652 459.550441zM142.846268 192.22193l478.645334 0 0 63.649646L142.846268 255.871575 142.846268 192.22193 142.846268 192.22193zM620.218609 334.797136c-40.735773 11.456936-78.92556 26.732851-112.023376 49.646724L142.846268 384.443859l0-63.649646 478.645334 0 0 14.002922L620.218609 334.797136zM688.960226 322.067206 688.960226 127.299291 74.10465 127.299291l0 639.042441 288.969391 0c14.002922 47.100738 39.46278 90.382497 72.560596 127.299291L74.10465 893.641023c-38.189787 0-68.741617-28.005844-68.741617-63.649646L5.363033 63.649646c0-35.643802 30.55183-63.649646 68.741617-63.649646l614.855576 0c38.189787 0 68.741617 28.005844 68.741617 63.649646l0 258.417561c-11.456936-1.272993-22.913872-3.818979-34.370809-3.818979C711.874099 319.521221 700.417163 322.067206 688.960226 322.067206L688.960226 322.067206z" p-id="16790" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/password.svg b/leave-school-vue/src/icons/svg/password.svg
new file mode 100644
index 0000000..920b500
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/password.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503994678729" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9229" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M780.8 354.579692 665.6 354.579692 665.6 311.689846c0-72.310154-19.849846-193.299692-153.6-193.299692-138.870154 0-153.6 135.049846-153.6 193.299692l0 42.889846L243.2 354.579692 243.2 311.689846C243.2 122.249846 348.790154 0 512 0s268.8 122.249846 268.8 311.689846L780.8 354.579692zM588.8 669.420308C588.8 625.900308 554.220308 590.769231 512 590.769231s-76.8 35.131077-76.8 78.651077c0 29.459692 15.399385 54.468923 38.439385 67.820308l0 89.639385c0 21.740308 17.250462 39.699692 38.4 39.699692s38.4-17.959385 38.4-39.699692l0-89.639385C573.44 723.889231 588.8 698.88 588.8 669.420308zM896 512l0 393.609846c0 65.260308-51.869538 118.390154-115.2 118.390154L243.2 1024c-63.291077 0-115.2-53.129846-115.2-118.390154L128 512c0-65.220923 51.869538-118.390154 115.2-118.390154l537.6 0C844.130462 393.609846 896 446.779077 896 512z" p-id="9230"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/rostersyncinterface.svg b/leave-school-vue/src/icons/svg/rostersyncinterface.svg
new file mode 100644
index 0000000..bf6e10a
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/rostersyncinterface.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534319999383" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10315" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M191.566694 251.408481C264.909372 154.591282 380.944055 91.952013 511.939185 91.952013c175.268322 0 324.14301 112.264164 379.4845 268.558261h93.898087C926.817912 153.983133 737.197292 2.432593 511.939185 2.432593 349.928495 2.432593 206.648771 81.005345 117.007721 201.783585l-97.546977-65.071862V450.029695L288.140634 315.750564l-96.57394-64.342083zM735.737736 673.949875l96.57394 64.342084C758.847369 835.109158 642.812686 897.748426 511.939185 897.748426c-175.389951 0-324.14301-112.264164-379.484499-268.558261h-93.898088C97.060458 835.717306 286.559449 987.267847 511.939185 987.267847c162.01069 0 305.168785-78.572752 394.809835-199.350992l97.546977 65.071861V539.670745L735.737736 673.949875z m-89.51942-134.27913" p-id="10316" fill="#bfcbd9"></path><path d="M719.925882 546.360375c-0.729778-28.218078-14.595558-55.706378-36.975413-72.977788-22.501485-17.879558-53.152156-24.690818-81.126975-18.001188-14.960447 3.52726-28.582967 11.068298-40.381042 20.79867-13.500891 11.311557-25.785485 23.839411-38.434969 36.002375-33.326523 32.475116-66.896306 64.706972-100.1012 97.303718l1.094667-1.337926c-15.933484-0.364889-32.475116 0.973037-47.435562-5.594964-21.406818-8.635705-35.272598-31.745338-34.66445-54.490082 0.243259-13.62252 5.473334-27.123411 14.595558-37.461931 10.33852-11.798076 25.663856-19.095855 41.35408-19.825632 11.189928-0.729778 22.258225 2.675852 31.745338 8.392445 6.93289 4.013778 12.771113 9.365483 18.852595 14.473928 8.027557 6.93289 15.933484 13.86578 23.839411 20.9203 9.000594-8.878964 18.122817-17.636299 27.123412-26.515264-8.757335-7.905927-17.636299-15.933484-26.636893-23.596151-8.514075-7.176149-17.14978-14.473928-27.001782-19.947262-7.905927-4.378667-16.420002-7.905927-25.298967-9.487113 0.608148 0.12163 1.702815 0.243259 2.189334 0.24326 2.675852-12.527854 7.905927-24.447559 15.446965-34.78608 12.406224-17.14978 30.772301-29.799264 51.206082-34.907708 19.825632-5.108445 41.35408-3.284 60.085046 5.230075 20.190521 9.122224 36.853783 25.663856 45.976006 45.854377 12.527854-3.284 25.663856-4.743556 38.556598-3.892149-0.486519-4.378667-2.675852-8.149186-4.257037-12.162965-12.527854-27.60993-35.150968-50.597933-62.639269-63.490676-25.663856-12.162965-55.463119-15.325336-83.194678-9.122223-22.866374 5.108445-44.273192 16.663262-61.179713 32.840004-20.312151 19.460744-34.056301 45.611118-38.313339 73.342678-23.109633 3.648889-44.516451 16.541632-59.112008 34.786079-13.86578 17.27141-21.528448 39.286376-21.163559 61.422972 0.12163 23.839411 9.608742 47.313933 25.785485 64.706972 14.838817 16.176743 35.515857 26.515263 57.165934 29.434375 21.650077 2.432593 43.421784 1.094667 65.071862 1.459555 49.381637 0.12163 98.763274 0 148.02328 0 16.176743-0.12163 32.596745 0.364889 48.4086-3.770519 15.446965-3.892149 29.920893-11.919705 41.35408-22.988003 19.947262-18.487706 31.13719-45.732747 30.042523-72.856159z m-38.678228 13.014373c-2.432593 14.352298-10.33852 27.73156-21.893336 36.488894-10.703409 8.027557-24.08267 11.554816-37.218672 11.919705-21.285188 0.608148-42.570377 0.364889-63.855565 0.364889h-79.42416c23.352892-22.744744 46.705785-45.367858 69.937047-67.990973 11.433187-11.068298 22.623114-22.136596 34.54282-32.718375 9.243853-8.149186 20.55541-14.473928 32.961634-16.176743 14.352298-1.946074 29.312745 1.946074 41.232451 10.216891 18.001188 12.527854 27.73156 36.124005 23.717781 57.895712z" p-id="10317" fill="#bfcbd9"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/schoolyear.svg b/leave-school-vue/src/icons/svg/schoolyear.svg
new file mode 100644
index 0000000..9c2dcc1
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/schoolyear.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534126205727" class="icon" style="" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4805" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><defs><style type="text/css"></style></defs><path d="M253.584 456.72V322.432a96.944 96.944 0 0 1-121.36-93.856 96.944 96.944 0 1 1 193.888 0c0 11.648-2.048 22.832-5.824 33.2h136.416V181.76h-56.576a179.856 179.856 0 0 0-16.496-40.08l40.448-40.624-67.232-67.312-40.208 40.4c-12.576-7.12-26.144-12.8-40.144-16.672V0h-94.752v57.792c-13.984 3.888-27.28 9.376-39.504 16.32l-40.608-40.464-67.296 67.216 40.4 40.8c-7.008 12.4-12.64 26.112-16.528 40.096H0v94.752h58.224c3.888 14 9.456 27.152 16.48 39.52L34.24 356.368l67.232 67.184 40.8-40.496c12.208 6.912 25.52 12.416 39.504 16.288v57.36l71.808 0.016z" fill="#bfcbd9" p-id="4806"></path><path d="M972.656 1023.744H344.16a52.4 52.4 0 0 1-52.368-52.368V369.04a52.368 52.368 0 0 1 52.368-52.368h104.752v26.192c0 2.32 0.736 4.304 1.312 6.416-16.72 4.864-27.504 11.888-27.504 19.76 0 14.48 35.136 26.224 78.576 26.224 43.376 0 78.528-11.728 78.528-26.224 0-7.872-10.768-14.912-27.488-19.76 0.512-2.112 1.264-4.096 1.264-6.416v-26.192h209.504v26.192c0 2.32 0.784 4.304 1.376 6.416-16.736 4.864-27.552 11.888-27.552 19.76 0 14.48 35.2 26.224 78.544 26.224 43.408 0 78.576-11.728 78.576-26.224 0-7.872-10.8-14.912-27.52-19.76 0.576-2.112 1.328-4.096 1.328-6.416v-26.192H972.64a52.384 52.384 0 0 1 52.336 52.368v602.336a52.32 52.32 0 0 1-52.32 52.368zM658.384 552.336A104.752 104.752 0 0 0 553.616 447.6c-48.72 0-89.344 33.408-100.976 78.528h55.888c9.12-15.584 25.76-26.176 45.072-26.176a52.368 52.368 0 1 1 0 104.72c-6.528 0-40.352 1.52-68.528 26.176 28.192 24.736 62 26.192 68.528 26.192a52.4 52.4 0 0 1 0 104.768 52.352 52.352 0 0 1-52.304-52.368h-52.384a104.752 104.752 0 0 0 209.488 0c0-31.472-14.16-59.392-36.128-78.592 21.968-19.184 36.112-47.008 36.112-78.512z m183.312-52.352c0-14.48-11.696-26.192-26.176-26.192h-26.208c-14.464 0-26.224 11.696-26.224 26.192v288.08c0 14.448 11.744 26.16 26.224 26.16h26.208c14.464 0 26.176-11.696 26.176-26.16v-288.08z m78.576 373.184c0-3.664-4.864-6.544-10.912-6.544H407.44c-6.048 0-10.928 2.88-10.928 6.544v13.088c0 3.632 4.864 6.544 10.928 6.544h501.92c6.032 0 10.912-2.928 10.912-6.544v-13.088z m0 58.912a13.104 13.104 0 0 0-13.088-13.088H409.616a13.088 13.088 0 0 0-13.088 13.088v26.24a13.12 13.12 0 0 0 13.088 13.056h497.552a13.12 13.12 0 0 0 13.088-13.056v-26.24z m-130.96-641.6h52.352v78.56h-52.352v-78.56z m-314.224 0h52.384v78.56h-52.384v-78.56z" fill="#bfcbd9" p-id="4807"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/table.svg b/leave-school-vue/src/icons/svg/table.svg
new file mode 100644
index 0000000..da6ffff
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/table.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1511504440567" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5070" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M568.6 0h454.9v454.9H568.6V0z m0 568.6h454.9v454.9H568.6V568.6zM0 568.6h454.9v454.9H0V568.6zM0 0h454.9v454.9H0V0z" fill="" p-id="5071"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/tree.svg b/leave-school-vue/src/icons/svg/tree.svg
new file mode 100644
index 0000000..11cedc0
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/tree.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1511512690058" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3507" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M1013.703 693.345c6.865 6.865 10.297 14.874 10.297 24.027l0 205.944c0 9.916-3.432 18.115-10.297 24.599-6.865 6.483-15.255 9.725-25.171 9.725L782.588 957.64c-9.153 0-17.162-3.242-24.027-9.725-6.865-6.483-10.297-14.683-10.297-24.599L748.264 717.372c0-6.102 1.526-11.823 4.577-17.162s7.246-9.534 12.586-12.586 11.06-4.577 17.162-4.577l77.801 0L860.39 546.896c0-4.577-1.144-8.772-3.432-12.586s-5.339-6.865-9.153-9.153-8.009-3.432-12.585-3.432L543.464 521.725l0 161.323 77.801 0c9.153 0 17.162 3.432 24.027 10.297s10.297 14.874 10.297 24.027l0 205.944c0 6.102-1.526 11.823-4.577 17.162s-7.246 9.534-12.585 12.585-11.06 4.577-17.162 4.577L415.321 957.64c-6.102 0-11.823-1.526-17.162-4.577s-9.725-7.246-13.158-12.585-5.149-11.06-5.149-17.162L379.852 717.372c0-9.153 3.432-17.162 10.297-24.027s15.255-10.297 25.171-10.297l76.657 0L491.977 521.725 188.782 521.725c-7.628 0-13.92 2.479-18.878 7.437-4.958 4.958-7.437 10.869-7.437 17.734l0 136.152 77.801 0c9.916 0 18.115 3.432 24.599 10.297s9.725 14.874 9.725 24.027l0 205.944c0 9.916-3.242 18.115-9.725 24.599-6.483 6.483-14.683 9.725-24.599 9.725L34.324 957.64c-3.814 0-7.437-0.572-10.869-1.716-3.432-1.144-6.483-2.67-9.153-4.577-2.67-1.907-5.149-4.386-7.437-7.437-2.288-3.051-4.004-6.293-5.149-9.725C0.572 930.753 0 927.13 0 923.316L0 717.372c0-3.051 0.381-6.102 1.144-9.153s1.907-5.721 3.432-8.009 3.432-4.577 5.721-6.865 4.577-4.195 6.865-5.721 4.958-2.67 8.009-3.432 6.102-1.144 9.153-1.144l77.801 0L112.125 495.41c0-6.865 2.479-12.776 7.437-17.734s10.869-7.437 17.734-7.437l354.682 0L491.978 342.096l-76.657 0c-9.916 0-18.306-3.432-25.171-10.297s-10.297-14.874-10.297-24.027L379.853 101.828c0-9.916 3.432-18.306 10.297-25.171s15.255-10.297 25.171-10.297l205.944 0c6.102 0 11.823 1.716 17.162 5.149 5.339 3.432 9.534 7.818 12.585 13.158 3.051 5.339 4.577 11.06 4.577 17.162l0 205.944c0 9.153-3.432 17.162-10.297 24.027s-14.874 10.297-24.027 10.297l-77.801 0 0 128.143L885.56 470.24c7.628 0 13.92 2.479 18.878 7.437s7.437 10.869 7.437 17.734l0 187.638 76.657 0C998.448 683.048 1006.838 686.48 1013.703 693.345z" p-id="3508"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/user.svg b/leave-school-vue/src/icons/svg/user.svg
new file mode 100644
index 0000000..5971dee
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/user.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1503993891882" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7986" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M504.951 511.98c93.49 0 169.28-74.002 169.28-165.26 0-91.276-75.79-165.248-169.28-165.248-93.486 0-169.287 73.972-169.279 165.248-0.001 91.258 75.793 165.26 169.28 165.26z m77.6 55.098H441.466c-120.767 0-218.678 95.564-218.678 213.45V794.3c0 48.183 97.911 48.229 218.678 48.229H582.55c120.754 0 218.66-1.78 218.66-48.229v-13.77c0-117.887-97.898-213.45-218.66-213.45z" p-id="7987"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/icons/svg/workteam.svg b/leave-school-vue/src/icons/svg/workteam.svg
new file mode 100644
index 0000000..0a378c6
--- /dev/null
+++ b/leave-school-vue/src/icons/svg/workteam.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1534323352713" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11266" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M585.728 550.912V782.336c0 14.848-4.608 19.968-19.456 19.968h-30.208c-8.192 0-16.896 1.024-22.528-10.752-5.12 11.776-13.824 10.24-22.016 10.752h-33.28c-9.728 0-14.848-4.608-16.384-14.336-0.512-2.048 0-4.096 0-6.656v-219.136-10.752c-11.776-2.048-22.528-4.096-33.792-5.632-8.192-1.024-10.752-4.608-10.752-13.312 0-52.736-1.024-105.472 0-157.696 0.512-23.552 3.584-47.104 7.168-70.656 3.072-19.456 14.848-28.16 33.792-31.744 11.264-2.048 22.528-5.632 33.28-9.216 4.096-1.536 8.192-5.632 11.264-9.216 8.704-9.728 8.192-11.264-0.512-20.48-3.072-3.584-5.632-7.68-8.704-11.776-2.56-4.096-3.584-9.216-9.216-11.264-2.56-1.024-4.096-7.168-4.608-11.264-2.56-19.456 2.56-37.888 11.776-53.76 10.24-18.944 29.696-20.48 49.152-18.432 23.552 2.56 36.864 16.896 39.424 40.96 0.512 3.584 2.048 6.656 3.072 10.24 3.584 10.752 4.096 24.064-3.072 30.72-9.728 9.216-12.8 22.528-24.064 30.208-1.024 1.024-1.536 5.632 0 7.68 8.704 16.384 24.064 22.528 40.96 25.6 2.048 0.512 4.096 0.512 6.656 0.512 22.528 2.56 33.28 13.312 36.864 35.84 6.656 39.936 7.168 80.384 7.168 120.832 0 34.816-1.024 69.632-0.512 104.448 0 7.68-3.072 10.752-9.728 11.776-10.752 1.024-20.992 3.072-31.744 5.12zM512 404.48c5.12-6.144 9.216-11.264 13.824-15.872 4.608-4.096 5.632-8.192 4.608-14.336-4.096-20.48-6.144-40.96-10.752-61.44-3.584-14.848-2.56-26.624 10.752-35.328 0.512 0 0.512-1.024 0.512-1.536-12.288-14.848-26.112-14.848-37.376 1.024 2.048 2.56 4.096 5.12 7.168 7.168 6.656 4.608 7.168 10.752 5.632 18.432-4.608 25.088-8.704 49.664-12.8 74.752-0.512 2.56 0 6.144 1.536 7.68 4.608 6.656 10.24 12.288 16.896 19.456zM736.768 256c-6.656-9.728-10.24-19.456-16.896-25.088-8.704-6.656-9.728-14.336-8.192-22.528 1.536-11.264 4.608-23.552 9.728-33.792 8.192-15.872 24.064-17.92 39.936-16.384 14.848 1.024 27.136 7.68 31.232 22.528 3.072 11.264 5.12 23.04 6.144 34.304 0.512 5.632 0 12.288-7.68 14.336-1.536 0.512-2.048 3.072-3.072 4.608-2.56 4.096-5.12 8.192-8.192 11.776-7.168 8.704-7.168 11.776 1.536 19.968s19.968 11.264 31.744 12.8c20.992 2.56 29.696 10.752 32.256 31.744 2.56 27.136 4.608 54.272 5.632 81.408 1.024 34.304-0.512 69.12 0 103.424 0 5.632-1.536 8.704-7.168 9.216-8.704 1.536-16.896 3.072-26.624 5.12V699.392c0 15.872-3.072 18.432-18.432 18.432-8.704 0-17.408 0.512-26.112 0-5.12-0.512-10.24-2.56-16.896-4.608-3.072 5.12-10.24 5.12-17.92 4.608h-27.648c-7.68 0-11.776-4.096-12.8-11.776-0.512-2.56 0-5.632 0-8.192v-179.2-9.216c-9.728-1.536-19.456-3.584-28.672-5.12-5.632-1.024-8.192-3.584-8.192-10.24 0.512-46.592-0.512-93.184 0.512-140.288 0-15.872 2.56-31.744 5.12-47.616 2.56-17.92 12.288-26.112 30.208-29.184 9.728-1.536 19.968-5.12 28.672-9.728 4.608-0.512 8.192-7.68 11.776-11.264z m16.896 132.608c4.608-4.608 8.192-8.192 11.264-10.752 5.12-4.096 6.144-9.216 4.608-15.36-3.584-16.384-5.12-32.768-8.704-49.152-2.56-11.776-1.536-20.992 8.704-28.16 0.512-0.512 0.512-1.536 1.024-2.048-10.752-12.288-22.016-11.776-30.72 1.024 1.536 1.536 3.072 3.584 5.12 5.12 5.632 4.608 6.656 9.728 5.12 16.896-4.096 19.968-7.168 39.936-10.24 59.904-0.512 3.072 1.024 7.168 3.072 9.728 2.56 4.096 6.656 8.192 10.752 12.8zM270.336 714.752c-5.632 1.024-11.264 3.584-17.92 4.096-9.216 0.512-18.944 0.512-28.16 0-8.192 0-12.288-4.096-13.312-12.288v-6.656-180.736c0-3.072 0-5.632-0.512-8.704-10.24-2.048-19.968-3.584-29.696-5.12-5.12-1.024-7.168-3.584-7.168-8.704 0-47.104-0.512-94.208 0.512-141.824 0-15.872 3.072-32.256 5.12-48.128 2.56-16.896 12.288-25.6 29.696-27.648 17.408-2.048 33.28-7.168 41.472-25.6-7.168-8.704-14.848-17.92-22.016-26.624-3.584-4.096-5.12-20.48-2.56-26.624 1.536-3.072 2.56-6.656 3.072-9.728 3.072-20.992 15.36-32.256 37.376-32.768 24.064-0.512 37.888 9.216 41.984 30.208 1.536 9.728 3.584 19.456 4.096 29.184 0 4.608-0.512 10.752-7.168 12.288-1.024 0-1.536 1.536-2.048 2.56-5.12 7.168-9.728 14.848-15.36 23.04 3.584 10.24 12.288 16.896 23.552 20.48 6.144 2.048 12.8 3.072 18.944 3.584 15.36 2.048 25.088 9.216 27.648 24.064 3.072 18.432 6.144 37.376 6.144 56.32 1.024 45.568 0 91.136 0 136.704 0 5.632-2.048 7.68-7.168 8.704-8.704 1.536-16.896 3.072-26.624 5.12v189.44c0 16.384-2.56 18.944-18.432 18.944-8.192 0-16.384 0.512-24.064 0-6.144 0-11.776-2.048-17.408-3.584z m-1.536-325.12c4.096-4.608 6.144-8.192 9.216-10.752 6.144-4.608 7.68-9.728 5.632-17.408-3.584-15.36-4.608-31.232-8.192-47.104-3.072-12.288-2.56-22.528 8.704-30.208 0.512 0 0-1.024 0.512-1.536-10.24-12.288-21.504-11.776-30.72 1.024 1.024 1.536 2.048 3.072 3.584 4.096 7.168 5.12 8.192 11.264 6.144 19.456-4.096 19.456-7.168 39.424-10.24 58.88-0.512 2.56 1.024 6.144 2.56 8.192 3.584 5.12 7.68 9.216 12.8 15.36z" fill="#bfcbd9" p-id="11267"></path><path d="M833.536 675.84c33.28 9.728 65.536 17.408 96.256 28.16 20.992 7.168 40.96 17.92 60.416 29.184 9.216 5.12 16.896 14.336 23.04 23.04 8.704 12.8 7.68 27.136-2.56 38.4-9.728 10.752-20.992 20.48-33.28 27.648-39.424 23.04-82.944 33.792-126.976 43.52-62.464 13.824-125.952 21.504-189.952 26.112-76.288 5.632-152.576 7.168-228.864 4.096-95.744-4.096-190.976-13.312-284.672-36.352-32.256-8.192-64.512-17.92-94.208-33.792-14.336-7.68-28.16-15.872-38.4-29.184-11.776-15.36-12.8-32.256 0.512-46.592 9.728-10.24 21.504-19.968 34.304-26.624 40.96-23.04 86.016-33.792 131.584-44.032 4.096-1.024 7.68-1.536 12.8-2.56v19.968c-4.096 1.024-9.216 2.048-13.824 4.096-22.528 8.192-45.056 16.896-67.072 26.112-6.144 2.56-11.264 7.168-15.872 12.288-11.776 11.776-11.776 24.576 0 36.352 11.776 12.288 27.136 18.944 42.496 24.576 44.544 16.896 90.624 25.6 137.728 32.256 110.592 15.36 222.208 17.92 333.824 12.8 69.632-3.072 139.264-10.24 207.872-25.6 30.72-6.656 60.928-14.336 88.576-29.696 8.192-4.608 15.872-10.24 22.528-16.896 9.728-10.24 9.216-22.016-0.512-32.768-12.8-14.336-30.208-21.504-47.616-27.648-12.8-4.608-25.6-8.704-38.4-11.776-7.168-1.536-10.24-4.608-9.216-11.776 0-3.584-0.512-6.656-0.512-13.312zM418.304 668.672c-23.04 1.536-46.08 3.072-69.632 4.608-0.512-1.024-1.024-2.048-1.024-3.072-1.024-13.824-1.024-14.336 12.8-14.848 18.944-1.536 37.888-2.56 57.856-3.584v16.896zM610.304 669.184v-16.896c13.824 0.512 27.136 1.536 40.448 2.048 6.656 0.512 13.312 1.536 19.968 1.536 7.168 0 9.728 2.56 8.704 9.728-0.512 2.56-0.512 5.12-0.512 8.704-22.528-2.048-45.056-3.584-68.608-5.12z" fill="#bfcbd9" p-id="11268"></path></svg>
\ No newline at end of file
diff --git a/leave-school-vue/src/main.js b/leave-school-vue/src/main.js
new file mode 100644
index 0000000..015ce46
--- /dev/null
+++ b/leave-school-vue/src/main.js
@@ -0,0 +1,34 @@
+import Vue from 'vue'
+
+import 'normalize.css/normalize.css'// A modern alternative to CSS resets
+
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
+
+import '@/styles/index.scss' // global css
+
+import App from './App'
+import router from './router'
+import store from './store'
+
+import '@/icons' // icon
+import '@/permission' // permission control
+
+import './mock' // 模拟数据
+// 富文本
+import '../static/ueditor/ueditor.config.js'
+import '../static/ueditor/ueditor.all.min.js'
+import '../static/ueditor/lang/zh-cn/zh-cn.js'
+import '../static/ueditor/ueditor.parse.min.js'
+
+Vue.use(ElementUI, { locale })
+
+Vue.config.productionTip = false
+
+new Vue({
+ el: '#app',
+ router,
+ store,
+ render: h => h(App)
+})
diff --git a/leave-school-vue/src/mock/auditscope.js b/leave-school-vue/src/mock/auditscope.js
new file mode 100644
index 0000000..b1f233c
--- /dev/null
+++ b/leave-school-vue/src/mock/auditscope.js
@@ -0,0 +1,69 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const auditscopeList = Mock.mock({
+ 'list|50': [{
+ 'id': '@increment',
+ 'fwkzmc': '@cword(6, 15)',
+ 'fwkzsxl': '@word(15)'
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { fwkzmc, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = auditscopeList.filter(item => {
+ if (fwkzmc && item.fwkzmc !== fwkzmc) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = auditscopeList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const auditscope = JSON.parse(config.body)
+ if (!auditscope.id) {
+ auditscope.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ auditscopeList.unshift(auditscope)
+ } else {
+ for (let i = 0; i < auditscopeList.length; i++) {
+ if (auditscopeList[i].id + '' === auditscope.id + '') {
+ auditscopeList.splice(i, 1, auditscope)
+ break
+ }
+ }
+ }
+ return {
+ item: auditscope,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const auditscope = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < auditscopeList.length; i++) {
+ if (auditscopeList[i].id + '' === auditscope.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ auditscopeList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/autoaudittype.js b/leave-school-vue/src/mock/autoaudittype.js
new file mode 100644
index 0000000..ab77486
--- /dev/null
+++ b/leave-school-vue/src/mock/autoaudittype.js
@@ -0,0 +1,69 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const autoaudittypeList = Mock.mock({
+ 'list|50': [{
+ 'id': '@increment',
+ 'zdshlxmc': '@cword(6, 15)',
+ 'zdshlxsxl': '@word(15)'
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { zdshlxmc, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = autoaudittypeList.filter(item => {
+ if (zdshlxmc && item.zdshlxmc !== zdshlxmc) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = autoaudittypeList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const autoaudittype = JSON.parse(config.body)
+ if (!autoaudittype.id) {
+ autoaudittype.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ autoaudittypeList.unshift(autoaudittype)
+ } else {
+ for (let i = 0; i < autoaudittypeList.length; i++) {
+ if (autoaudittypeList[i].id + '' === autoaudittype.id + '') {
+ autoaudittypeList.splice(i, 1, autoaudittype)
+ break
+ }
+ }
+ }
+ return {
+ item: autoaudittype,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const autoaudittype = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < autoaudittypeList.length; i++) {
+ if (autoaudittypeList[i].id + '' === autoaudittype.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ autoaudittypeList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/class.js b/leave-school-vue/src/mock/class.js
new file mode 100644
index 0000000..01fc0ae
--- /dev/null
+++ b/leave-school-vue/src/mock/class.js
@@ -0,0 +1,88 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const clsList = Mock.mock({
+ 'list|26': [{
+ 'id': '@increment',
+ 'nj|1': ['6', '7', '8'],
+ 'njmc|1': ['2017', '2018', '2019'],
+ 'yx|1-26': 26,
+ 'yxmc': '@cword(6, 15)',
+ 'zy|27-375': 375,
+ 'zymc': '@cword(3, 5)',
+ 'bjdm': '@word(5)',
+ 'bjmc': '@cword(6, 10)',
+ 'sfky|1': ['1', '0'],
+ 'sfkymc|1': ['可用', '不可用']
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { yx, zy, bjmc, nj, bjdm, sfky, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = clsList.filter(item => {
+ if (yx && item.yx + '' !== yx + '') return false
+ if (zy && item.zy !== zy) return false
+ if (bjmc && item.bjmc !== bjmc) return false
+ if (nj && item.nj !== nj) return false
+ if (bjdm && item.bjdm !== bjdm) return false
+ if (sfky && item.sfky !== sfky) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getAllList: config => {
+ return {
+ items: clsList,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = clsList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const cls = JSON.parse(config.body)
+ if (!cls.id) {
+ cls.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ clsList.unshift(cls)
+ } else {
+ for (let i = 0; i < clsList.length; i++) {
+ if (clsList[i].id + '' === cls.id + '') {
+ clsList.splice(i, 1, cls)
+ break
+ }
+ }
+ }
+ return {
+ item: cls,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const cls = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < clsList.length; i++) {
+ if (clsList[i].id + '' === cls.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ clsList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/department.js b/leave-school-vue/src/mock/department.js
new file mode 100644
index 0000000..ce07f0b
--- /dev/null
+++ b/leave-school-vue/src/mock/department.js
@@ -0,0 +1,86 @@
+import Mock from 'mockjs'
+import { param2Obj, parseTime } from '@/utils'
+
+const deptList = Mock.mock({
+ 'list|26': [{
+ 'id': '@increment',
+ 'dwdm': '000@id',
+ 'dwmc': '@cword(6, 15)',
+ 'dwjc': '@cword(3, 5)',
+ 'dwywmc': '@word(6, 10)',
+ 'sfqy|1': ['启用', '未启用'],
+ 'sfqycode|1': ['1', '0'],
+ 'lbm|1': ['院系', '部门'],
+ 'lbmid|1': ['1', '2'],
+ 'cjsj': '@Date'
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { dwdm, dwmc, sfqy, lbm, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = deptList.filter(item => {
+ if (dwdm && item.dwdm !== dwdm) return false
+ if (dwmc && item.dwmc !== dwmc) return false
+ if (sfqy && item.sfqycode !== sfqy) return false
+ if (lbm && item.lbmid !== lbm) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getAllList: config => {
+ return {
+ items: deptList,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = deptList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const dept = JSON.parse(config.body)
+ dept.cjsj = parseTime(new Date(), '{y}-{m}-{d}')
+ if (!dept.id) {
+ dept.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ deptList.unshift(dept)
+ } else {
+ for (let i = 0; i < deptList.length; i++) {
+ if (deptList[i].id + '' === dept.id + '') {
+ deptList.splice(i, 1, dept)
+ break
+ }
+ }
+ }
+ return {
+ item: dept,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const dept = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < deptList.length; i++) {
+ if (deptList[i].id + '' === dept.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ deptList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/departmentleader.js b/leave-school-vue/src/mock/departmentleader.js
new file mode 100644
index 0000000..e9fe93e
--- /dev/null
+++ b/leave-school-vue/src/mock/departmentleader.js
@@ -0,0 +1,77 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const departmentleaderList = Mock.mock({
+ 'list|50': [{
+ 'gh': '@increment',
+ 'xm': '@cword(2, 3)',
+ 'yx': '@cword(6, 15)',
+ 'xb|1': ['男', '女'],
+ 'zzmm|1': ['党员', '共青团员', '群众'],
+ 'lxdh': '@word',
+ 'sfzr|1': ['是', '否']
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { gh, xm, yx, zzmm, xb, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = departmentleaderList.filter(item => {
+ if (gh && item.gh + '' !== gh + '') return false
+ if (xm && item.xm !== xm) return false
+ if (yx && item.yx !== yx) return false
+ if (zzmm && item.zzmm !== zzmm) return false
+ if (xb && item.xb !== xb) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = departmentleaderList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const departmentleader = JSON.parse(config.body)
+ if (!departmentleader.id) {
+ departmentleader.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ departmentleaderList.unshift(departmentleader)
+ } else {
+ for (let i = 0; i < departmentleaderList.length; i++) {
+ if (departmentleaderList[i].id + '' === departmentleader.id + '') {
+ departmentleaderList.splice(i, 1, departmentleader)
+ break
+ }
+ }
+ }
+ return {
+ item: departmentleader,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const departmentleader = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < departmentleaderList.length; i++) {
+ if (departmentleaderList[i].id + '' === departmentleader.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ departmentleaderList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/dictionary.js b/leave-school-vue/src/mock/dictionary.js
new file mode 100644
index 0000000..fbfb169
--- /dev/null
+++ b/leave-school-vue/src/mock/dictionary.js
@@ -0,0 +1,108 @@
+// import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const deptList = [{
+ 'id': '1',
+ 'type': 'lbm',
+ 'name': '院系'
+},
+{
+ 'id': '2',
+ 'type': 'lbm',
+ 'name': '部门'
+},
+{
+ 'id': '3',
+ 'type': 'gjzybz',
+ 'name': '文学'
+},
+{
+ 'id': '4',
+ 'type': 'gjzybz',
+ 'name': '物理'
+},
+{
+ 'id': '5',
+ 'type': 'gjzybz',
+ 'name': '数学'
+},
+{
+ 'id': '6',
+ 'type': 'nj',
+ 'name': '2017'
+},
+{
+ 'id': '7',
+ 'type': 'nj',
+ 'name': '2018'
+},
+{
+ 'id': '8',
+ 'type': 'nj',
+ 'name': '2019'
+},
+{
+ 'id': '9',
+ 'type': 'zzmm',
+ 'name': '党员'
+},
+{
+ 'id': '10',
+ 'type': 'zzmm',
+ 'name': '群众'
+},
+{
+ 'id': '11',
+ 'type': 'xb',
+ 'name': '男'
+},
+{
+ 'id': '12',
+ 'type': 'xb',
+ 'name': '女'
+},
+{
+ 'id': '13',
+ 'type': 'xswz',
+ 'name': '置顶'
+},
+{
+ 'id': '14',
+ 'type': 'xswz',
+ 'name': '其他'
+},
+{
+ 'id': '15',
+ 'type': 'gglx',
+ 'name': '离校公告'
+},
+{
+ 'id': '16',
+ 'type': 'jszlx',
+ 'name': '所有人'
+},
+{
+ 'id': '17',
+ 'type': 'jszlx',
+ 'name': '所有学生'
+},
+{
+ 'id': '18',
+ 'type': 'jszlx',
+ 'name': '所有教职工'
+}]
+
+export default{
+ getDicList: config => {
+ const { type } = param2Obj(config.url)
+ const mockList = deptList.filter(item => {
+ if (type && item.type !== type) return false
+ return true
+ })
+
+ return {
+ items: mockList,
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/index.js b/leave-school-vue/src/mock/index.js
new file mode 100644
index 0000000..1e9f075
--- /dev/null
+++ b/leave-school-vue/src/mock/index.js
@@ -0,0 +1,90 @@
+import Mock from 'mockjs'
+import loginApi from './login'
+import departmentApi from './department'
+import menulistApi from './menulist'
+import majorApi from './major'
+import classApi from './class'
+import dicApi from './dictionary'
+import schoolyearApi from './schoolyear'
+import auditscopeApi from './auditscope'
+import autoaudittypeApi from './autoaudittype'
+import rostersyncinterfaceApi from './rostersyncinterface'
+import departmentleaderApi from './departmentleader'
+import instructorApi from './instructor'
+import newspublishApi from './newspublish'
+
+// 登录
+Mock.mock(/\/api\/login\/login/, 'post', loginApi.loginByUsername)
+Mock.mock(/\/api\/system\/user\/info/, 'get', loginApi.getUserInfo)
+Mock.mock(/\/api\/login\/logout-api/, 'post', loginApi.logout)
+
+// 数据字典
+Mock.mock(/\/api\/system\/dictionary\/getdiclist/, 'get', dicApi.getDicList)
+
+// 菜单列表
+Mock.mock(/\/api\/system\/menu\/list/, 'get', menulistApi.getMenuList)
+
+// 院系部门管理
+Mock.mock(/\/api\/system\/department\/list-api/, 'get', departmentApi.getList)
+Mock.mock(/\/api\/system\/department\/all-list/, 'get', departmentApi.getAllList)
+Mock.mock(/\/api\/system\/department\/create-department/, 'post', departmentApi.createData)
+Mock.mock(/\/api\/system\/department\/delete-department/, 'delete', departmentApi.deleteData)
+Mock.mock(/\/api\/system\/department\/get-item/, 'get', departmentApi.getItem)
+
+// 专业管理
+Mock.mock(/\/api\/system\/major\/list-api/, 'get', majorApi.getList)
+Mock.mock(/\/api\/system\/major\/create-major/, 'post', majorApi.createData)
+Mock.mock(/\/api\/system\/major\/delete-major/, 'delete', majorApi.deleteData)
+Mock.mock(/\/api\/system\/major\/get-item/, 'get', majorApi.getItem)
+Mock.mock(/\/api\/system\/major\/list-byyx-api/, 'get', majorApi.getZyListByYx)
+
+// 班级管理
+Mock.mock(/\/api\/system\/class\/list-api/, 'get', classApi.getList)
+Mock.mock(/\/api\/system\/class\/all-list/, 'get', classApi.getAllList)
+Mock.mock(/\/api\/system\/class\/create-class/, 'post', classApi.createData)
+Mock.mock(/\/api\/system\/class\/delete-class/, 'delete', classApi.deleteData)
+Mock.mock(/\/api\/system\/class\/get-item/, 'get', classApi.getItem)
+
+// 学年管理
+Mock.mock(/\/api\/system\/schoolyear\/list-api/, 'get', schoolyearApi.getList)
+Mock.mock(/\/api\/system\/schoolyear\/create-schoolyear/, 'post', schoolyearApi.createData)
+Mock.mock(/\/api\/system\/schoolyear\/delete-schoolyear/, 'delete', schoolyearApi.deleteData)
+Mock.mock(/\/api\/system\/schoolyear\/get-item/, 'get', schoolyearApi.getItem)
+
+// 名单同步接口设置
+Mock.mock(/\/api\/system\/rostersyncinterface\/list-api/, 'get', rostersyncinterfaceApi.getList)
+Mock.mock(/\/api\/system\/rostersyncinterface\/create-rostersyncinterface/, 'post', rostersyncinterfaceApi.createData)
+Mock.mock(/\/api\/system\/rostersyncinterface\/delete-rostersyncinterface/, 'delete', rostersyncinterfaceApi.deleteData)
+Mock.mock(/\/api\/system\/rostersyncinterface\/get-item/, 'get', rostersyncinterfaceApi.getItem)
+
+// 审核学生范围控制
+Mock.mock(/\/api\/system\/auditscope\/list-api/, 'get', auditscopeApi.getList)
+Mock.mock(/\/api\/system\/auditscope\/create-auditscope/, 'post', auditscopeApi.createData)
+Mock.mock(/\/api\/system\/auditscope\/delete-auditscope/, 'delete', auditscopeApi.deleteData)
+Mock.mock(/\/api\/system\/auditscope\/get-item/, 'get', auditscopeApi.getItem)
+
+// 离校自动审核类型设置
+Mock.mock(/\/api\/system\/autoaudittype\/list-api/, 'get', autoaudittypeApi.getList)
+Mock.mock(/\/api\/system\/autoaudittype\/create-autoaudittype/, 'post', autoaudittypeApi.createData)
+Mock.mock(/\/api\/system\/autoaudittype\/delete-autoaudittype/, 'delete', autoaudittypeApi.deleteData)
+Mock.mock(/\/api\/system\/autoaudittype\/get-item/, 'get', autoaudittypeApi.getItem)
+
+// 学院负责人信息管理
+Mock.mock(/\/api\/workteam\/departmentleader\/list-api/, 'get', departmentleaderApi.getList)
+Mock.mock(/\/api\/workteam\/departmentleader\/create-departmentleader/, 'post', departmentleaderApi.createData)
+Mock.mock(/\/api\/workteam\/departmentleader\/delete-departmentleader/, 'delete', departmentleaderApi.deleteData)
+Mock.mock(/\/api\/workteam\/departmentleader\/get-item/, 'get', departmentleaderApi.getItem)
+
+// 辅导员信息管理
+Mock.mock(/\/api\/workteam\/instructor\/list-api/, 'get', instructorApi.getList)
+Mock.mock(/\/api\/workteam\/instructor\/create-instructor/, 'post', instructorApi.createData)
+Mock.mock(/\/api\/workteam\/instructor\/delete-instructor/, 'delete', instructorApi.deleteData)
+Mock.mock(/\/api\/workteam\/instructor\/get-item/, 'get', instructorApi.getItem)
+
+// 院系部门管理
+Mock.mock(/\/api\/news\/newspublish\/list-api/, 'get', newspublishApi.getList)
+Mock.mock(/\/api\/news\/newspublish\/create-newspublish/, 'post', newspublishApi.createData)
+Mock.mock(/\/api\/news\/newspublish\/delete-newspublish/, 'delete', newspublishApi.deleteData)
+Mock.mock(/\/api\/news\/newspublish\/get-item/, 'get', newspublishApi.getItem)
+
+export default Mock
diff --git a/leave-school-vue/src/mock/instructor.js b/leave-school-vue/src/mock/instructor.js
new file mode 100644
index 0000000..0f48407
--- /dev/null
+++ b/leave-school-vue/src/mock/instructor.js
@@ -0,0 +1,76 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const instructorList = Mock.mock({
+ 'list|50': [{
+ 'gh': '@increment',
+ 'xm': '@cword(2, 3)',
+ 'sdbj': '@cword(6, 15)',
+ 'bjzrs': '@integer(60, 100)',
+ 'szyx': '@cword(5,7)',
+ 'sfzr|1': ['是', '否']
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { gh, xm, yx, bjzrs, sfzr, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = instructorList.filter(item => {
+ if (gh && item.gh + '' !== gh + '') return false
+ if (xm && item.xm !== xm) return false
+ if (yx && item.yx !== yx) return false
+ if (bjzrs && item.bjzrs !== bjzrs) return false
+ if (sfzr && item.sfzr !== sfzr) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = instructorList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const instructor = JSON.parse(config.body)
+ if (!instructor.id) {
+ instructor.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ instructorList.unshift(instructor)
+ } else {
+ for (let i = 0; i < instructorList.length; i++) {
+ if (instructorList[i].id + '' === instructor.id + '') {
+ instructorList.splice(i, 1, instructor)
+ break
+ }
+ }
+ }
+ return {
+ item: instructor,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const instructor = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < instructorList.length; i++) {
+ if (instructorList[i].id + '' === instructor.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ instructorList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/login.js b/leave-school-vue/src/mock/login.js
new file mode 100644
index 0000000..baa100d
--- /dev/null
+++ b/leave-school-vue/src/mock/login.js
@@ -0,0 +1,33 @@
+import { param2Obj } from '@/utils'
+
+const userMap = {
+ admin: {
+ data: {
+ roles: ['admin'],
+ token: 'admin',
+ introduction: '我是超级管理员',
+ avatar: 'https://cn.vuejs.org/images/logo.png',
+ name: 'Super Admin'
+ },
+ code: 200
+ }
+}
+export default {
+ loginByUsername: config => {
+ const { username } = JSON.parse(config.body)
+ return userMap[username]
+ },
+ getUserInfo: config => {
+ const { token } = param2Obj(config.url)
+ if (userMap[token]) {
+ return userMap[token]
+ } else {
+ return false
+ }
+ },
+ logout: () => {
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/major.js b/leave-school-vue/src/mock/major.js
new file mode 100644
index 0000000..fe9b977
--- /dev/null
+++ b/leave-school-vue/src/mock/major.js
@@ -0,0 +1,86 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const majorList = Mock.mock({
+ 'list|350': [{
+ 'id': '@increment',
+ 'zydm': '000@id',
+ 'zymc': '@cword(6, 15)',
+ 'sfky|1': ['可用', '不可用'],
+ 'sfkycode|1': ['1', '0'],
+ 'ssyx|1': ['教育学院', '经管学院', '人文学院', '数学学院', '计算机学院', '电子学院', '电气学院', '生命科学院'],
+ 'ssyxid|1': ['1', '2', '3', '4', '5', '6', '7', '8'],
+ 'sszygb|1': ['计算机', '哲学']
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { zydm, zymc, sfky, ssyx, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = majorList.filter(item => {
+ if (zydm && item.zydm !== zydm) return false
+ if (zymc && item.zymc !== zymc) return false
+ if (sfky && item.sfkycode !== sfky) return false
+ if (ssyx && item.ssyxid !== ssyx) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getZyListByYx: config => {
+ const { yx } = param2Obj(config.url)
+ const mockList = majorList.filter(item => item.ssyxid === yx)
+
+ return {
+ list: mockList,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = majorList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const major = JSON.parse(config.body)
+ if (!major.id) {
+ major.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ majorList.unshift(major)
+ } else {
+ for (let i = 0; i < majorList.length; i++) {
+ if (majorList[i].id + '' === major.id + '') {
+ majorList.splice(i, 1, major)
+ break
+ }
+ }
+ }
+ return {
+ item: major,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const major = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < majorList.length; i++) {
+ if (majorList[i].id + '' === major.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ majorList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/menulist.js b/leave-school-vue/src/mock/menulist.js
new file mode 100644
index 0000000..7453cd9
--- /dev/null
+++ b/leave-school-vue/src/mock/menulist.js
@@ -0,0 +1,101 @@
+/* Layout */
+// import Layout from '../views/layout/Layout'
+
+const menuList = [
+ {
+ path: '/dictionary',
+ code: 'dictionary',
+ meta: { title: '数据字典管理', icon: 'dictionary' },
+ children: [
+ {
+ path: 'department',
+ code: 'Department',
+ resource: '/views/systemmanagement/department/index',
+ meta: { title: '院系部门管理', icon: 'department' }
+ },
+ {
+ path: 'major',
+ code: 'Major',
+ resource: '/views/systemmanagement/major/index',
+ meta: { title: '专业管理', icon: 'major' }
+ },
+ {
+ path: 'class',
+ code: 'Class',
+ resource: '/views/systemmanagement/class/index',
+ meta: { title: '班级管理', icon: 'class' }
+ },
+ {
+ path: 'schoolyear',
+ code: 'SchoolYear',
+ resource: '/views/systemmanagement/schoolyear/index',
+ meta: { title: '学年管理', icon: 'schoolyear' }
+ },
+ {
+ path: 'rostersyncinterface',
+ code: 'RosterSyncInterface',
+ resource: '/views/systemmanagement/rostersyncinterface/index',
+ meta: { title: '名单同步接口设置', icon: 'rostersyncinterface' }
+ },
+ {
+ path: 'auditscope',
+ code: 'AuditScope',
+ resource: '/views/systemmanagement/auditscope/index',
+ meta: { title: '审核学生范围控制', icon: 'auditscope' }
+ },
+ {
+ path: 'autoaudittype',
+ code: 'AutoAuditType',
+ resource: '/views/systemmanagement/autoaudittype/index',
+ meta: { title: '离校自动审核类型设置', icon: 'autoaudittype' }
+ }
+ ]
+ },
+ {
+ path: '/workteam',
+ code: 'workteam',
+ meta: { title: '工作队伍管理', icon: 'workteam' },
+ children: [
+ {
+ path: 'departmentleader',
+ code: 'Departmentleader',
+ resource: '/views/workteam/departmentleader/index',
+ meta: { title: '学院负责人信息管理', icon: 'departmentleader' }
+ },
+ {
+ path: 'instructor',
+ code: 'Instructor',
+ resource: '/views/workteam/instructor/index',
+ meta: { title: '辅导员信息管理', icon: 'instructor' }
+ }
+ ]
+ },
+ {
+ path: '/news',
+ code: 'news',
+ meta: { title: '新闻公告管理', icon: 'news' },
+ children: [
+ {
+ path: 'newspublish',
+ code: 'NewsPublish',
+ resource: '/views/news/newspublish/index',
+ meta: { title: '新闻公告发布', icon: 'newspublish' }
+ },
+ {
+ path: 'newview',
+ code: 'NewsView',
+ resource: '/views/news/newview/index',
+ meta: { title: '新闻公告查看', icon: 'newview' }
+ }
+ ]
+ }
+]
+
+export default{
+ getMenuList: config => {
+ return {
+ items: menuList,
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/newspublish.js b/leave-school-vue/src/mock/newspublish.js
new file mode 100644
index 0000000..2c4d8f3
--- /dev/null
+++ b/leave-school-vue/src/mock/newspublish.js
@@ -0,0 +1,84 @@
+import Mock from 'mockjs'
+import { param2Obj, parseTime } from '@/utils'
+
+const newspublishList = Mock.mock({
+ 'list|26': [{
+ 'id': '@increment',
+ 'ggbt': '@cword(6, 15)',
+ 'gglx': '离校公告',
+ 'jszlx|1': ['所有学生', '所有人', '所有教职工'],
+ 'sfky|1': ['可用', '不可用'],
+ 'fbqssj': '2018-06-28',
+ 'fbjssj': '2018-06-28',
+ 'xswz|1': ['其它', '置顶'],
+ 'jlckzt': '需要',
+ 'djs': '@integer(60, 100)',
+ 'fbr': 'admin',
+ 'fbrq': '2018-08-08'
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { ggbt, fbqssj, fbjssj, sfky, xswz, jlckzt, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = newspublishList.filter(item => {
+ if (ggbt && item.ggbt !== ggbt) return false
+ if (fbqssj && item.fbqssj !== fbqssj) return false
+ if (fbjssj && item.fbjssj !== fbjssj) return false
+ if (sfky && item.sfky !== sfky) return false
+ if (xswz && item.xswz !== xswz) return false
+ if (jlckzt && item.jlckzt !== jlckzt) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = newspublishList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const newspublish = JSON.parse(config.body)
+ newspublish.cjsj = parseTime(new Date(), '{y}-{m}-{d}')
+ if (!newspublish.id) {
+ newspublish.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ newspublishList.unshift(newspublish)
+ } else {
+ for (let i = 0; i < newspublishList.length; i++) {
+ if (newspublishList[i].id + '' === newspublish.id + '') {
+ newspublishList.splice(i, 1, newspublish)
+ break
+ }
+ }
+ }
+ return {
+ item: newspublish,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const newspublish = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < newspublishList.length; i++) {
+ if (newspublishList[i].id + '' === newspublish.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ newspublishList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/rostersyncinterface.js b/leave-school-vue/src/mock/rostersyncinterface.js
new file mode 100644
index 0000000..3a7259c
--- /dev/null
+++ b/leave-school-vue/src/mock/rostersyncinterface.js
@@ -0,0 +1,76 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const rostersyncinterfaceList = Mock.mock({
+ 'list|50': [{
+ 'id': '@increment',
+ 'dm': '@word(4)',
+ 'mc': '@cword(6, 15)',
+ 'tj': '@word(15)',
+ 'px': '@word(15)',
+ 'gglx': '@word(15)'
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { dm, mc, tj, px, gglx, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = rostersyncinterfaceList.filter(item => {
+ if (dm && item.dm !== dm) return false
+ if (mc && item.mc !== mc) return false
+ if (tj && item.tj !== tj) return false
+ if (px && item.px !== px) return false
+ if (gglx && item.gglx !== gglx) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = rostersyncinterfaceList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const rostersyncinterface = JSON.parse(config.body)
+ if (!rostersyncinterface.id) {
+ rostersyncinterface.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ rostersyncinterfaceList.unshift(rostersyncinterface)
+ } else {
+ for (let i = 0; i < rostersyncinterfaceList.length; i++) {
+ if (rostersyncinterfaceList[i].id + '' === rostersyncinterface.id + '') {
+ rostersyncinterfaceList.splice(i, 1, rostersyncinterface)
+ break
+ }
+ }
+ }
+ return {
+ item: rostersyncinterface,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const rostersyncinterface = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < rostersyncinterfaceList.length; i++) {
+ if (rostersyncinterfaceList[i].id + '' === rostersyncinterface.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ rostersyncinterfaceList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/mock/schoolyear.js b/leave-school-vue/src/mock/schoolyear.js
new file mode 100644
index 0000000..7e37aa9
--- /dev/null
+++ b/leave-school-vue/src/mock/schoolyear.js
@@ -0,0 +1,70 @@
+import Mock from 'mockjs'
+import { param2Obj } from '@/utils'
+
+const schoolyearList = Mock.mock({
+ 'list|26': [{
+ 'id': '@increment',
+ 'xndm|1': ['2016', '2017', '2018'],
+ 'xnmc': '@xndm@cword(6, 15)'
+ }]
+}).list
+
+export default{
+ getList: config => {
+ const { xndm, xnmc, pageIndex = 1, pageSize = 20 } = param2Obj(config.url)
+ const mockList = schoolyearList.filter(item => {
+ if (xndm && item.xndm !== xndm) return false
+ if (xnmc && item.xnmc !== xnmc) return false
+ return true
+ })
+
+ const pageList = mockList.filter((item, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1))
+ return {
+ items: pageList,
+ recordCount: mockList.length,
+ code: 200
+ }
+ },
+ getItem: config => {
+ const { id } = param2Obj(config.url)
+ const mockList = schoolyearList.filter(item => item.id + '' === id + '')
+ return {
+ data: mockList.length > 0 ? mockList[0] : null,
+ code: 200
+ }
+ },
+ createData: config => {
+ const schoolyear = JSON.parse(config.body)
+ if (!schoolyear.id) {
+ schoolyear.id = '' + parseInt(Math.random() * 100) + 1024 // mock a id
+ schoolyearList.unshift(schoolyear)
+ } else {
+ for (let i = 0; i < schoolyearList.length; i++) {
+ if (schoolyearList[i].id + '' === schoolyear.id + '') {
+ schoolyearList.splice(i, 1, schoolyear)
+ break
+ }
+ }
+ }
+ return {
+ item: schoolyear,
+ code: 200
+ }
+ },
+ deleteData: config => {
+ const schoolyear = JSON.parse(config.body)
+ let index = -1
+ for (let i = 0; i < schoolyearList.length; i++) {
+ if (schoolyearList[i].id + '' === schoolyear.id + '') {
+ index = i
+ break
+ }
+ }
+ if (index > -1) {
+ schoolyearList.splice(index, 1)
+ }
+ return {
+ code: 200
+ }
+ }
+}
diff --git a/leave-school-vue/src/permission.js b/leave-school-vue/src/permission.js
new file mode 100644
index 0000000..d2e4ead
--- /dev/null
+++ b/leave-school-vue/src/permission.js
@@ -0,0 +1,41 @@
+import router from './router'
+import store from './store'
+import NProgress from 'nprogress' // Progress 进度条
+import 'nprogress/nprogress.css'// Progress 进度条样式
+import { Message } from 'element-ui'
+import { getToken } from '@/utils/auth' // 验权
+
+const whiteList = ['/login'] // 不重定向白名单
+router.beforeEach((to, from, next) => {
+ NProgress.start()
+ if (getToken()) {
+ if (to.path === '/login') {
+ next({ path: '/' })
+ NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
+ } else {
+ if (store.getters.roles.length === 0) {
+ store.dispatch('GetInfo').then(res => { // 拉取用户信息
+ next()
+ }).catch((err) => {
+ store.dispatch('FedLogOut').then(() => {
+ Message.error(err || '验证失败,请重新登录')
+ next({ path: '/' })
+ })
+ })
+ } else {
+ next()
+ }
+ }
+ } else {
+ if (whiteList.indexOf(to.path) !== -1) {
+ next()
+ } else {
+ next('/login')
+ NProgress.done()
+ }
+ }
+})
+
+router.afterEach(() => {
+ NProgress.done() // 结束Progress
+})
diff --git a/leave-school-vue/src/router/index.js b/leave-school-vue/src/router/index.js
new file mode 100644
index 0000000..7f638d2
--- /dev/null
+++ b/leave-school-vue/src/router/index.js
@@ -0,0 +1,111 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+
+// in development-env not use lazy-loading, because lazy-loading too many pages will cause webpack hot update too slow. so only in production use lazy-loading;
+// detail: https://panjiachen.github.io/vue-element-admin-site/#/lazy-loading
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '../views/layout/Layout'
+import { getMenuList } from '../api/menulist-api'
+
+/**
+* hidden: true if `hidden:true` will not show in the sidebar(default is false)
+* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
+* if not set alwaysShow, only more than one route under the children
+* it will becomes nested mode, otherwise not show the root menu
+* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
+* name:'router-name' the name is used by <keep-alive> (must set!!!)
+* meta : {
+ title: 'title' the name show in submenu and breadcrumb (recommend set)
+ icon: 'svg-name' the icon show in the sidebar,
+ }
+**/
+// 全局路由
+const globalRouter = [
+ { path: '/login', component: () => import('@/views/login/index'), hidden: true },
+ { path: '/404', component: () => import('@/views/404'), hidden: true }
+]
+// 主页路由
+const mainRouter = {
+ path: '/',
+ component: Layout,
+ redirect: '/dashboard',
+ hidden: true,
+ children: [{
+ path: 'dashboard',
+ component: () => import('@/views/dashboard/index'),
+ name: 'Dashboard',
+ meta: { title: 'Dashboard', icon: 'dashboard', noCache: true }
+ }]
+}
+// 菜单路由
+const menuRouter = []
+
+const constantRouterMap = globalRouter.concat(mainRouter).concat(menuRouter)
+
+const router = new Router({
+ // mode: 'history', //后端支持可开
+ scrollBehavior: () => ({ y: 0 }),
+ hasLoadedDynamicRoutes: false, // 动态路由已加载
+ routes: constantRouterMap
+})
+
+router.beforeEach((to, from, next) => {
+ if (router.options.hasLoadedDynamicRoutes) {
+ next()
+ } else {
+ getMenuList().then(response => {
+ const menuList = initDynamicRouters(response.items)
+ router.options.routes.push(...menuList)
+ router.addRoutes(menuList)
+ router.addRoutes([{ path: '*', redirect: '/404', hidden: true }])
+ router.options.hasLoadedDynamicRoutes = true
+ next({ ...to, replace: true })
+ })
+ }
+})
+function getMenuResource(resource) {
+ let menuresource = resource
+ if (menuresource && menuresource.startsWith('/views/')) {
+ menuresource = menuresource.substring(6)
+ }
+ return menuresource
+}
+function getChildren(menus) {
+ const children = []
+ for (const menu of menus) {
+ const menuresource = getMenuResource(menu.resource)
+ const route = {
+ path: menu.path,
+ name: menu.code,
+ component: () => import('@/views' + menuresource),
+ meta: menu.meta,
+ children: menu.children ? getChildren(menu.children) : null
+ }
+ children.push(route)
+ }
+ return children.length > 0 ? children : null
+}
+
+function initDynamicRouters(menus) {
+ const menuList = []
+ if (menus && menus.length > 0) {
+ for (const menu of menus) {
+ const route = {
+ path: menu.path,
+ component: Layout,
+ // alwaysShow: true,
+ redirect: menu.path + '/' + ((menu.children && menu.children.length > 0) ? menu.children[0].path : null),
+ name: menu.code,
+ meta: menu.meta,
+ children: menu.children ? getChildren(menu.children) : null
+ }
+ menuList.push(route)
+ }
+ }
+ return menuList
+}
+
+export default router
diff --git a/leave-school-vue/src/store/getters.js b/leave-school-vue/src/store/getters.js
new file mode 100644
index 0000000..b8ff1dc
--- /dev/null
+++ b/leave-school-vue/src/store/getters.js
@@ -0,0 +1,11 @@
+const getters = {
+ sidebar: state => state.app.sidebar,
+ device: state => state.app.device,
+ visitedViews: state => state.tagsView.visitedViews,
+ cachedViews: state => state.tagsView.cachedViews,
+ token: state => state.user.token,
+ avatar: state => state.user.avatar,
+ name: state => state.user.name,
+ roles: state => state.user.roles
+}
+export default getters
diff --git a/leave-school-vue/src/store/index.js b/leave-school-vue/src/store/index.js
new file mode 100644
index 0000000..fcbb633
--- /dev/null
+++ b/leave-school-vue/src/store/index.js
@@ -0,0 +1,19 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import tagsView from './modules/tagsView'
+import user from './modules/user'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+ modules: {
+ app,
+ tagsView,
+ user
+ },
+ getters
+})
+
+export default store
diff --git a/leave-school-vue/src/store/modules/app.js b/leave-school-vue/src/store/modules/app.js
new file mode 100644
index 0000000..f487241
--- /dev/null
+++ b/leave-school-vue/src/store/modules/app.js
@@ -0,0 +1,43 @@
+import Cookies from 'js-cookie'
+
+const app = {
+ state: {
+ sidebar: {
+ opened: !+Cookies.get('sidebarStatus'),
+ withoutAnimation: false
+ },
+ device: 'desktop'
+ },
+ mutations: {
+ TOGGLE_SIDEBAR: state => {
+ if (state.sidebar.opened) {
+ Cookies.set('sidebarStatus', 1)
+ } else {
+ Cookies.set('sidebarStatus', 0)
+ }
+ state.sidebar.opened = !state.sidebar.opened
+ state.sidebar.withoutAnimation = false
+ },
+ CLOSE_SIDEBAR: (state, withoutAnimation) => {
+ Cookies.set('sidebarStatus', 1)
+ state.sidebar.opened = false
+ state.sidebar.withoutAnimation = withoutAnimation
+ },
+ TOGGLE_DEVICE: (state, device) => {
+ state.device = device
+ }
+ },
+ actions: {
+ ToggleSideBar: ({ commit }) => {
+ commit('TOGGLE_SIDEBAR')
+ },
+ CloseSideBar({ commit }, { withoutAnimation }) {
+ commit('CLOSE_SIDEBAR', withoutAnimation)
+ },
+ ToggleDevice({ commit }, device) {
+ commit('TOGGLE_DEVICE', device)
+ }
+ }
+}
+
+export default app
diff --git a/leave-school-vue/src/store/modules/tagsView.js b/leave-school-vue/src/store/modules/tagsView.js
new file mode 100644
index 0000000..25d513c
--- /dev/null
+++ b/leave-school-vue/src/store/modules/tagsView.js
@@ -0,0 +1,76 @@
+const tagsView = {
+ state: {
+ visitedViews: [],
+ cachedViews: []
+ },
+ mutations: {
+ ADD_VISITED_VIEWS: (state, view) => {
+ if (state.visitedViews.some(v => v.path === view.path)) return
+ state.visitedViews.push(Object.assign({}, view, {
+ title: view.meta.title || 'no-name'
+ }))
+ if (!view.meta.noCache) {
+ state.cachedViews.push(view.name)
+ }
+ },
+ DEL_VISITED_VIEWS: (state, view) => {
+ for (const [i, v] of state.visitedViews.entries()) {
+ if (v.path === view.path) {
+ state.visitedViews.splice(i, 1)
+ break
+ }
+ }
+ for (const i of state.cachedViews) {
+ if (i === view.name) {
+ const index = state.cachedViews.indexOf(i)
+ state.cachedViews.splice(index, 1)
+ break
+ }
+ }
+ },
+ DEL_OTHERS_VIEWS: (state, view) => {
+ for (const [i, v] of state.visitedViews.entries()) {
+ if (v.path === view.path) {
+ state.visitedViews = state.visitedViews.slice(i, i + 1)
+ break
+ }
+ }
+ for (const i of state.cachedViews) {
+ if (i === view.name) {
+ const index = state.cachedViews.indexOf(i)
+ state.cachedViews = state.cachedViews.slice(index, index + 1)
+ break
+ }
+ }
+ },
+ DEL_ALL_VIEWS: (state) => {
+ state.visitedViews = []
+ state.cachedViews = []
+ }
+ },
+ actions: {
+ addVisitedViews({ commit }, view) {
+ commit('ADD_VISITED_VIEWS', view)
+ },
+ delVisitedViews({ commit, state }, view) {
+ return new Promise((resolve) => {
+ commit('DEL_VISITED_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delOthersViews({ commit, state }, view) {
+ return new Promise((resolve) => {
+ commit('DEL_OTHERS_VIEWS', view)
+ resolve([...state.visitedViews])
+ })
+ },
+ delAllViews({ commit, state }) {
+ return new Promise((resolve) => {
+ commit('DEL_ALL_VIEWS')
+ resolve([...state.visitedViews])
+ })
+ }
+ }
+}
+
+export default tagsView
diff --git a/leave-school-vue/src/store/modules/user.js b/leave-school-vue/src/store/modules/user.js
new file mode 100644
index 0000000..b504067
--- /dev/null
+++ b/leave-school-vue/src/store/modules/user.js
@@ -0,0 +1,87 @@
+import { login, logout, getInfo } from '@/api/login'
+import { getToken, setToken, removeToken } from '@/utils/auth'
+
+const user = {
+ state: {
+ token: getToken(),
+ name: '',
+ avatar: '',
+ roles: []
+ },
+
+ mutations: {
+ SET_TOKEN: (state, token) => {
+ state.token = token
+ },
+ SET_NAME: (state, name) => {
+ state.name = name
+ },
+ SET_AVATAR: (state, avatar) => {
+ state.avatar = avatar
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles
+ }
+ },
+
+ actions: {
+ // 登录
+ Login({ commit }, userInfo) {
+ const username = userInfo.username.trim()
+ return new Promise((resolve, reject) => {
+ login(username, userInfo.password).then(response => {
+ const data = response.data
+ setToken(data.token)
+ commit('SET_TOKEN', data.token)
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 获取用户信息
+ GetInfo({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ getInfo(state.token).then(response => {
+ const data = response.data
+ if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
+ commit('SET_ROLES', data.roles)
+ } else {
+ reject('getInfo: roles must be a non-null array !')
+ }
+ commit('SET_NAME', data.name)
+ commit('SET_AVATAR', data.avatar)
+ resolve(response)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 登出
+ LogOut({ commit, state }) {
+ return new Promise((resolve, reject) => {
+ logout(state.token).then(() => {
+ commit('SET_TOKEN', '')
+ commit('SET_ROLES', [])
+ removeToken()
+ resolve()
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+
+ // 前端 登出
+ FedLogOut({ commit }) {
+ return new Promise(resolve => {
+ commit('SET_TOKEN', '')
+ removeToken()
+ resolve()
+ })
+ }
+ }
+}
+
+export default user
diff --git a/leave-school-vue/src/styles/element-ui.scss b/leave-school-vue/src/styles/element-ui.scss
new file mode 100644
index 0000000..ef7bb5d
--- /dev/null
+++ b/leave-school-vue/src/styles/element-ui.scss
@@ -0,0 +1,29 @@
+ //to reset element-ui default css
+.el-upload {
+ input[type="file"] {
+ display: none !important;
+ }
+}
+
+.el-upload__input {
+ display: none;
+}
+
+//暂时性解决diolag 问题 https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+ transform: none;
+ left: 0;
+ position: relative;
+ margin: 0 auto;
+}
+
+//element ui upload
+.upload-container {
+ .el-upload {
+ width: 100%;
+ .el-upload-dragger {
+ width: 100%;
+ height: 200px;
+ }
+ }
+}
diff --git a/leave-school-vue/src/styles/index.scss b/leave-school-vue/src/styles/index.scss
new file mode 100644
index 0000000..333a548
--- /dev/null
+++ b/leave-school-vue/src/styles/index.scss
@@ -0,0 +1,96 @@
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+
+body {
+ height: 100%;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+ font-weight: 700;
+}
+
+html {
+ height: 100%;
+ box-sizing: border-box;
+}
+
+#app{
+ height: 100%;
+}
+
+*,
+*:before,
+*:after {
+ box-sizing: inherit;
+}
+
+a,
+a:focus,
+a:hover {
+ cursor: pointer;
+ color: inherit;
+ outline: none;
+ text-decoration: none;
+}
+
+div:focus{
+ outline: none;
+ }
+
+a:focus,
+a:active {
+ outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+ cursor: pointer;
+ color: inherit;
+ text-decoration: none;
+}
+
+.clearfix {
+ &:after {
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content: " ";
+ clear: both;
+ height: 0;
+ }
+}
+
+//main-container全局样式
+.app-main{
+ min-height: 100%
+}
+
+.app-container {
+ padding: 20px;
+}
+
+.filter-container {
+ padding-bottom: 10px;
+ .filter-item {
+ display: inline-block;
+ vertical-align: middle;
+ margin-bottom: 10px;
+ }
+}
+
+//refine vue-multiselect plugin
+.multiselect {
+ line-height: 16px;
+}
+
+.multiselect--active {
+ z-index: 1000 !important;
+}
diff --git a/leave-school-vue/src/styles/mixin.scss b/leave-school-vue/src/styles/mixin.scss
new file mode 100644
index 0000000..601d7a0
--- /dev/null
+++ b/leave-school-vue/src/styles/mixin.scss
@@ -0,0 +1,27 @@
+@mixin clearfix {
+ &:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+}
+
+@mixin scrollBar {
+ &::-webkit-scrollbar-track-piece {
+ background: #d3dce6;
+ }
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: #99a9bf;
+ border-radius: 20px;
+ }
+}
+
+@mixin relative {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
diff --git a/leave-school-vue/src/styles/sidebar.scss b/leave-school-vue/src/styles/sidebar.scss
new file mode 100644
index 0000000..8b55c87
--- /dev/null
+++ b/leave-school-vue/src/styles/sidebar.scss
@@ -0,0 +1,119 @@
+#app {
+ // 主体区域
+ .main-container {
+ min-height: 100%;
+ transition: margin-left .28s;
+ margin-left: 220px;
+ position: relative;
+ }
+ // 侧边栏
+ .sidebar-container {
+ transition: width 0.28s;
+ width: 220px !important;
+ height: 100%;
+ position: fixed;
+ font-size: 0px;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1001;
+ overflow: hidden;
+ //reset element-ui css
+ .horizontal-collapse-transition {
+ transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+ }
+ .scrollbar-wrapper {
+ height: calc(100% + 15px);
+ .el-scrollbar__view {
+ height: 100%;
+ }
+ }
+ .is-horizontal {
+ display: none;
+ }
+ a {
+ display: inline-block;
+ width: 100%;
+ overflow: hidden;
+ }
+ .svg-icon {
+ margin-right: 16px;
+ }
+ .el-menu {
+ border: none;
+ height: 100%;
+ width: 100% !important;
+ }
+ }
+ .hideSidebar {
+ .sidebar-container {
+ width: 36px !important;
+ }
+ .main-container {
+ margin-left: 36px;
+ }
+ .submenu-title-noDropdown {
+ padding-left: 10px !important;
+ position: relative;
+ .el-tooltip {
+ padding: 0 10px !important;
+ }
+ }
+ .el-submenu {
+ overflow: hidden;
+ &>.el-submenu__title {
+ padding-left: 10px !important;
+ .el-submenu__icon-arrow {
+ display: none;
+ }
+ }
+ }
+ .el-menu--collapse {
+ .el-submenu {
+ &>.el-submenu__title {
+ &>span {
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ visibility: hidden;
+ display: inline-block;
+ }
+ }
+ }
+ }
+ }
+ .sidebar-container .nest-menu .el-submenu>.el-submenu__title,
+ .sidebar-container .el-submenu .el-menu-item {
+ min-width: 220px !important;
+ background-color: $subMenuBg !important;
+ &:hover {
+ background-color: $menuHover !important;
+ }
+ }
+ .el-menu--collapse .el-menu .el-submenu {
+ min-width: 220px !important;
+ }
+
+ //适配移动端
+ .mobile {
+ .main-container {
+ margin-left: 0px;
+ }
+ .sidebar-container {
+ transition: transform .28s;
+ width: 220px !important;
+ }
+ &.hideSidebar {
+ .sidebar-container {
+ transition-duration: 0.3s;
+ transform: translate3d(-220px, 0, 0);
+ }
+ }
+ }
+ .withoutAnimation {
+ .main-container,
+ .sidebar-container {
+ transition: none;
+ }
+ }
+}
diff --git a/leave-school-vue/src/styles/transition.scss b/leave-school-vue/src/styles/transition.scss
new file mode 100644
index 0000000..c4d47ad
--- /dev/null
+++ b/leave-school-vue/src/styles/transition.scss
@@ -0,0 +1,32 @@
+//globl transition css
+
+/*fade*/
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+ opacity: 0;
+}
+
+/*fade*/
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+ transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+ opacity: 0;
+ transform: translateX(20px);
+}
+
+.breadcrumb-move {
+ transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+ position: absolute;
+}
diff --git a/leave-school-vue/src/styles/variables.scss b/leave-school-vue/src/styles/variables.scss
new file mode 100644
index 0000000..2fee827
--- /dev/null
+++ b/leave-school-vue/src/styles/variables.scss
@@ -0,0 +1,4 @@
+//sidebar
+$menuBg:#304156;
+$subMenuBg:#1f2d3d;
+$menuHover:#001528;
diff --git a/leave-school-vue/src/utils/auth.js b/leave-school-vue/src/utils/auth.js
new file mode 100644
index 0000000..08a43d6
--- /dev/null
+++ b/leave-school-vue/src/utils/auth.js
@@ -0,0 +1,15 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'Admin-Token'
+
+export function getToken() {
+ return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+ return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+ return Cookies.remove(TokenKey)
+}
diff --git a/leave-school-vue/src/utils/crud.js b/leave-school-vue/src/utils/crud.js
new file mode 100644
index 0000000..70eb9e2
--- /dev/null
+++ b/leave-school-vue/src/utils/crud.js
@@ -0,0 +1,95 @@
+import { MessageBox } from 'element-ui'
+
+export default {
+ data() {
+ return {
+ items: null,
+ recordCount: null,
+ listLoading: true,
+ dialogStatus: '',
+ dialogFormVisible: false,
+ temp: {},
+ textMap: {
+ update: '修改',
+ create: '新增'
+ },
+ dialogPvVisible: false,
+ listQuery: {
+ pageIndex: 1,
+ pageSize: 20
+ },
+ height: 500
+ }
+ }
+}
+
+export function crudPageList(page, _pagelist) {
+ page.listLoading = true
+ _pagelist(Object.assign({}, page.listQuery)).then(response => {
+ page.items = response.items
+ page.listLoading = false
+ page.recordCount = response.recordCount
+ page.pageIndex = response.pageIndex
+ page.pageSize = response.pageSize
+ })
+}
+export function crudGetItem(page, _get, rowid, initData) {
+ if (rowid) {
+ _get({ id: rowid }).then(response => {
+ if (!response.data) {
+ MessageBox.alert('数据不存在,请确认是否已删除。', '消息', {
+ confirmButtonText: '确定'
+ })
+ return
+ }
+ page.temp = response.data
+ page.dialogFormVisible = true
+ page.$nextTick(() => {
+ page.$refs['dataForm'].clearValidate()
+ })
+ })
+ } else {
+ page.temp = Object.assign({}, initData)
+ page.dialogFormVisible = true
+ page.$nextTick(() => {
+ page.$refs['dataForm'].clearValidate()
+ })
+ }
+}
+export function crudCreate(page, _create, _callback) {
+ page.$refs['dataForm'].validate((valid) => {
+ if (valid) {
+ _create(page.temp).then(response => {
+ if (typeof _callback === 'function') {
+ _callback()
+ }
+ page.dialogFormVisible = false
+ page.$notify({
+ title: '成功',
+ message: (page.dialogStatus === 'create') ? '创建成功' : '修改成功',
+ type: 'success',
+ duration: 2000
+ })
+ })
+ }
+ })
+}
+export function crudDelete(page, _delete, rowid, _callback) {
+ MessageBox.confirm('确认删除记录吗?', '删除', {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }).then(() => {
+ _delete({ id: rowid }).then(response => {
+ if (typeof _callback === 'function') {
+ _callback()
+ }
+ page.$notify({
+ title: '成功',
+ message: '删除成功',
+ type: 'success',
+ duration: 2000
+ })
+ })
+ })
+}
diff --git a/leave-school-vue/src/utils/index.js b/leave-school-vue/src/utils/index.js
new file mode 100644
index 0000000..ebe2c42
--- /dev/null
+++ b/leave-school-vue/src/utils/index.js
@@ -0,0 +1,76 @@
+/**
+ * Created by jiachenpan on 16/11/18.
+ */
+
+export function parseTime(time, cFormat) {
+ if (arguments.length === 0) {
+ return null
+ }
+ const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+ let date
+ if (typeof time === 'object') {
+ date = time
+ } else {
+ if (('' + time).length === 10) time = parseInt(time) * 1000
+ date = new Date(time)
+ }
+ const formatObj = {
+ y: date.getFullYear(),
+ m: date.getMonth() + 1,
+ d: date.getDate(),
+ h: date.getHours(),
+ i: date.getMinutes(),
+ s: date.getSeconds(),
+ a: date.getDay()
+ }
+ const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+ let value = formatObj[key]
+ if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
+ if (result.length > 0 && value < 10) {
+ value = '0' + value
+ }
+ return value || 0
+ })
+ return time_str
+}
+
+export function formatTime(time, option) {
+ time = +time * 1000
+ const d = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) { // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ }
+ if (option) {
+ return parseTime(time, option)
+ } else {
+ return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
+ }
+}
+
+export function param2Obj(url) {
+ const search = url.split('?')[1]
+ if (!search) {
+ return {}
+ }
+ return JSON.parse('{"' + decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"')
+ .replace(/mapBean%5B/g, '').replace(/%5D/g, '') + '"}')
+}
+
+export function resetForm(listQuery) {
+ for (const attr in listQuery) {
+ if (attr === 'pageIndex' || attr === 'pageSize') {
+ continue
+ }
+ listQuery[attr] = null
+ }
+}
diff --git a/leave-school-vue/src/utils/request.js b/leave-school-vue/src/utils/request.js
new file mode 100644
index 0000000..8b0925b
--- /dev/null
+++ b/leave-school-vue/src/utils/request.js
@@ -0,0 +1,78 @@
+import axios from 'axios'
+import { Message, MessageBox } from 'element-ui'
+import store from '../store'
+import { getToken } from '@/utils/auth'
+
+// 网络请求约定属性名,不可在业务中使用
+const whitelist = ['X-Token', 'token', 'pageIndex', 'pageSize']
+// 创建axios实例
+const service = axios.create({
+ baseURL: process.env.BASE_API, // api的base_url
+ timeout: 10000 // 请求超时时间
+})
+
+// request拦截器
+service.interceptors.request.use(config => {
+ if (store.getters.token) {
+ config.headers['X-Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
+ }
+ if (config.params) {
+ for (const attr in config.params) {
+ if (whitelist.indexOf(attr) > -1) {
+ // 约定的属性不用转换
+ continue
+ }
+ config.params[encodeURIComponent('mapBean[' + attr + ']')] = config.params[attr]
+ delete config.params[attr]
+ }
+ }
+ return config
+}, error => {
+ // Do something with request error
+ console.log(error) // for debug
+ Promise.reject(error)
+})
+
+// respone拦截器
+service.interceptors.response.use(
+ response => {
+ /**
+ * code为非20000是抛错 可结合自己业务进行修改
+ */
+ const res = response.data
+ if (response.status !== 200) {
+ Message({
+ message: res.message || '请求失败,状态码:' + res.code,
+ type: 'error',
+ duration: 5 * 1000
+ })
+
+ // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
+ if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+ MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
+ confirmButtonText: '重新登录',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }).then(() => {
+ store.dispatch('FedLogOut').then(() => {
+ location.reload()// 为了重新实例化vue-router对象 避免bug
+ })
+ })
+ }
+ return Promise.reject('error')
+ } else {
+ return response.data
+ }
+ },
+ error => {
+ console.log('err' + error)// for debug
+ Message({
+ message: error.message,
+ type: 'error',
+ duration: 5 * 1000
+ })
+ return Promise.reject(error)
+ }
+)
+
+export default service
diff --git a/leave-school-vue/src/utils/validate.js b/leave-school-vue/src/utils/validate.js
new file mode 100644
index 0000000..834a8dd
--- /dev/null
+++ b/leave-school-vue/src/utils/validate.js
@@ -0,0 +1,33 @@
+/**
+ * Created by jiachenpan on 16/11/18.
+ */
+
+export function isvalidUsername(str) {
+ const valid_map = ['admin', 'editor']
+ return valid_map.indexOf(str.trim()) >= 0
+}
+
+/* 合法uri*/
+export function validateURL(textval) {
+ const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+ return urlregex.test(textval)
+}
+
+/* 小写字母*/
+export function validateLowerCase(str) {
+ const reg = /^[a-z]+$/
+ return reg.test(str)
+}
+
+/* 大写字母*/
+export function validateUpperCase(str) {
+ const reg = /^[A-Z]+$/
+ return reg.test(str)
+}
+
+/* 大小写字母*/
+export function validatAlphabets(str) {
+ const reg = /^[A-Za-z]+$/
+ return reg.test(str)
+}
+
diff --git a/leave-school-vue/src/views/404.vue b/leave-school-vue/src/views/404.vue
new file mode 100644
index 0000000..733e038
--- /dev/null
+++ b/leave-school-vue/src/views/404.vue
@@ -0,0 +1,236 @@
+<template>
+ <div class="wscn-http404-container">
+ <div class="wscn-http404">
+ <div class="pic-404">
+ <img class="pic-404__parent" :src="img_404" alt="404">
+ <img class="pic-404__child left" :src="img_404_cloud" alt="404">
+ <img class="pic-404__child mid" :src="img_404_cloud" alt="404">
+ <img class="pic-404__child right" :src="img_404_cloud" alt="404">
+ </div>
+ <div class="bullshit">
+ <div class="bullshit__oops">OOPS!</div>
+ <div class="bullshit__info">
+ <a class='link-type' href='' target='_blank'></a>
+ </div>
+ <div class="bullshit__headline">{{ message }}</div>
+ <div class="bullshit__info">请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告</div>
+ <a href="" class="bullshit__return-home">返回首页</a>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import img_404 from '@/assets/404_images/404.png'
+import img_404_cloud from '@/assets/404_images/404_cloud.png'
+
+export default {
+ name: 'page404',
+ data() {
+ return {
+ img_404,
+ img_404_cloud
+ }
+ },
+ computed: {
+ message() {
+ return '页面找不到了......'
+ }
+ }
+}
+</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>
diff --git a/leave-school-vue/src/views/dashboard/index.vue b/leave-school-vue/src/views/dashboard/index.vue
new file mode 100644
index 0000000..4b4625c
--- /dev/null
+++ b/leave-school-vue/src/views/dashboard/index.vue
@@ -0,0 +1,32 @@
+<template>
+ <div class="dashboard-container">
+ <div class="dashboard-text">name:{{name}}</div>
+ <div class="dashboard-text">roles:<span v-for='role in roles' :key='role'>{{role}}</span></div>
+ </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+
+export default {
+ name: 'dashboard',
+ computed: {
+ ...mapGetters([
+ 'name',
+ 'roles'
+ ])
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.dashboard {
+ &-container {
+ margin: 30px;
+ }
+ &-text {
+ font-size: 30px;
+ line-height: 46px;
+ }
+}
+</style>
diff --git a/leave-school-vue/src/views/layout/Layout.vue b/leave-school-vue/src/views/layout/Layout.vue
new file mode 100644
index 0000000..df7af87
--- /dev/null
+++ b/leave-school-vue/src/views/layout/Layout.vue
@@ -0,0 +1,74 @@
+<template>
+ <div class="app-wrapper" :class="classObj">
+ <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"></div>
+ <sidebar class="sidebar-container"></sidebar>
+ <div class="main-container">
+ <navbar></navbar>
+ <tags-view v-if='showtags'></tags-view>
+ <app-main></app-main>
+ </div>
+ </div>
+</template>
+
+<script>
+import { Navbar, Sidebar, AppMain, TagsView } from './components'
+import ResizeMixin from './mixin/ResizeHandler'
+
+export default {
+ name: 'layout',
+ components: {
+ Navbar,
+ Sidebar,
+ AppMain,
+ TagsView
+ },
+ mixins: [ResizeMixin],
+ computed: {
+ showtags() {
+ return process.env.SHOW_TAGS
+ },
+ sidebar() {
+ return this.$store.state.app.sidebar
+ },
+ device() {
+ return this.$store.state.app.device
+ },
+ classObj() {
+ return {
+ hideSidebar: !this.sidebar.opened,
+ openSidebar: this.sidebar.opened,
+ withoutAnimation: this.sidebar.withoutAnimation,
+ mobile: this.device === 'mobile'
+ }
+ }
+ },
+ methods: {
+ handleClickOutside() {
+ this.$store.dispatch('CloseSideBar', { withoutAnimation: false })
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+ @import "src/styles/mixin.scss";
+ .app-wrapper {
+ @include clearfix;
+ position: relative;
+ height: 100%;
+ width: 100%;
+ &.mobile.openSidebar{
+ position: fixed;
+ top: 0;
+ }
+ }
+ .drawer-bg {
+ background: #000;
+ opacity: 0.3;
+ width: 100%;
+ top: 0;
+ height: 100%;
+ position: absolute;
+ z-index: 999;
+ }
+</style>
diff --git a/leave-school-vue/src/views/layout/components/AppMain.vue b/leave-school-vue/src/views/layout/components/AppMain.vue
new file mode 100644
index 0000000..64ecff8
--- /dev/null
+++ b/leave-school-vue/src/views/layout/components/AppMain.vue
@@ -0,0 +1,33 @@
+<template>
+ <section class="app-main">
+ <transition name="fade" mode="out-in">
+ <!-- <router-view :key="key"></router-view> -->
+ <keep-alive :include="cachedViews">
+ <router-view :key="key"></router-view>
+ </keep-alive>
+ </transition>
+ </section>
+</template>
+
+<script>
+export default {
+ name: 'AppMain',
+ computed: {
+ cachedViews() {
+ return this.$store.state.tagsView.cachedViews
+ },
+ key() {
+ return this.$route.fullPath
+ }
+ }
+}
+</script>
+
+<style scoped>
+.app-main {
+ /*50 = navbar */
+ min-height: calc(100vh - 84px);
+ position: relative;
+ overflow: hidden;
+}
+</style>
diff --git a/leave-school-vue/src/views/layout/components/Navbar.vue b/leave-school-vue/src/views/layout/components/Navbar.vue
new file mode 100644
index 0000000..c901e8f
--- /dev/null
+++ b/leave-school-vue/src/views/layout/components/Navbar.vue
@@ -0,0 +1,95 @@
+<template>
+ <el-menu class="navbar" mode="horizontal">
+ <hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
+ <breadcrumb></breadcrumb>
+ <el-dropdown class="avatar-container" trigger="click">
+ <div class="avatar-wrapper">
+ <img class="user-avatar" :src="avatar">
+ <i class="el-icon-caret-bottom"></i>
+ </div>
+ <el-dropdown-menu class="user-dropdown" slot="dropdown">
+ <router-link class="inlineBlock" to="/">
+ <el-dropdown-item>
+ 首页
+ </el-dropdown-item>
+ </router-link>
+ <el-dropdown-item divided>
+ <span @click="logout" style="display:block;">注销</span>
+ </el-dropdown-item>
+ </el-dropdown-menu>
+ </el-dropdown>
+ </el-menu>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Breadcrumb from '@/components/Breadcrumb'
+import Hamburger from '@/components/Hamburger'
+
+export default {
+ components: {
+ Breadcrumb,
+ Hamburger
+ },
+ computed: {
+ ...mapGetters([
+ 'sidebar',
+ 'avatar'
+ ])
+ },
+ methods: {
+ toggleSideBar() {
+ this.$store.dispatch('ToggleSideBar')
+ },
+ logout() {
+ var pro = this.$store.dispatch('LogOut')
+ pro.then(() => {
+ location.reload() // 为了重新实例化vue-router对象 避免bug
+ })
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.navbar {
+ height: 50px;
+ line-height: 50px;
+ border-radius: 0px !important;
+ .hamburger-container {
+ line-height: 58px;
+ height: 50px;
+ float: left;
+ padding: 0 10px;
+ }
+ .screenfull {
+ position: absolute;
+ right: 90px;
+ top: 16px;
+ color: red;
+ }
+ .avatar-container {
+ height: 50px;
+ display: inline-block;
+ position: absolute;
+ right: 35px;
+ .avatar-wrapper {
+ cursor: pointer;
+ margin-top: 5px;
+ position: relative;
+ .user-avatar {
+ width: 40px;
+ height: 40px;
+ border-radius: 10px;
+ }
+ .el-icon-caret-bottom {
+ position: absolute;
+ right: -20px;
+ top: 25px;
+ font-size: 12px;
+ }
+ }
+ }
+}
+</style>
+
diff --git a/leave-school-vue/src/views/layout/components/Sidebar/SidebarItem.vue b/leave-school-vue/src/views/layout/components/Sidebar/SidebarItem.vue
new file mode 100644
index 0000000..78edb91
--- /dev/null
+++ b/leave-school-vue/src/views/layout/components/Sidebar/SidebarItem.vue
@@ -0,0 +1,78 @@
+<template>
+ <div v-if="!item.hidden&&item.children" class="menu-wrapper">
+
+ <router-link v-if="hasOneShowingChild(item.children) && !onlyOneChild.children&&!item.alwaysShow" :to="resolvePath(onlyOneChild.path)">
+ <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
+ <svg-icon v-if="onlyOneChild.meta&&onlyOneChild.meta.icon" :icon-class="onlyOneChild.meta.icon"></svg-icon>
+ <span v-if="onlyOneChild.meta&&onlyOneChild.meta.title" slot="title">{{onlyOneChild.meta.title}}</span>
+ </el-menu-item>
+ </router-link>
+
+ <el-submenu v-else :index="item.name||item.path">
+ <template slot="title">
+ <svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon>
+ <span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span>
+ </template>
+
+ <template v-for="child in item.children" v-if="!child.hidden">
+ <sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :item="child" :key="child.path" :base-path="resolvePath(child.path)"></sidebar-item>
+
+ <router-link v-else :to="resolvePath(child.path)" :key="child.name">
+ <el-menu-item :index="resolvePath(child.path)">
+ <svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon>
+ <span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
+ </el-menu-item>
+ </router-link>
+ </template>
+ </el-submenu>
+
+ </div>
+</template>
+
+<script>
+import path from 'path'
+
+export default {
+ name: 'SidebarItem',
+ props: {
+ // route配置json
+ item: {
+ type: Object,
+ required: true
+ },
+ isNest: {
+ type: Boolean,
+ default: false
+ },
+ basePath: {
+ type: String,
+ default: ''
+ }
+ },
+ data() {
+ return {
+ onlyOneChild: null
+ }
+ },
+ methods: {
+ hasOneShowingChild(children) {
+ const showingChildren = children.filter(item => {
+ if (item.hidden) {
+ return false
+ } else {
+ // temp set(will be used if only has one showing child )
+ this.onlyOneChild = item
+ return true
+ }
+ })
+ if (showingChildren.length === 1) {
+ return true
+ }
+ return false
+ },
+ resolvePath(...paths) {
+ return path.resolve(this.basePath, ...paths)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/layout/components/Sidebar/index.vue b/leave-school-vue/src/views/layout/components/Sidebar/index.vue
new file mode 100644
index 0000000..a84207e
--- /dev/null
+++ b/leave-school-vue/src/views/layout/components/Sidebar/index.vue
@@ -0,0 +1,35 @@
+<template>
+ <el-scrollbar wrapClass="scrollbar-wrapper">
+ <el-menu
+ mode="vertical"
+ :show-timeout="200"
+ :default-active="$route.path"
+ :collapse="isCollapse"
+ background-color="#304156"
+ text-color="#bfcbd9"
+ active-text-color="#409EFF"
+ >
+ <sidebar-item v-for="route in routes" :key="route.name" :item="route" :base-path="route.path"></sidebar-item>
+ </el-menu>
+ </el-scrollbar>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import SidebarItem from './SidebarItem'
+
+export default {
+ components: { SidebarItem },
+ computed: {
+ ...mapGetters([
+ 'sidebar'
+ ]),
+ routes() {
+ return this.$router.options.routes
+ },
+ isCollapse() {
+ return !this.sidebar.opened
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/layout/components/TagsView.vue b/leave-school-vue/src/views/layout/components/TagsView.vue
new file mode 100644
index 0000000..121c2b2
--- /dev/null
+++ b/leave-school-vue/src/views/layout/components/TagsView.vue
@@ -0,0 +1,205 @@
+<template>
+ <div class="tags-view-container">
+ <scroll-pane class='tags-view-wrapper' ref='scrollPane'>
+ <router-link ref='tag' class="tags-view-item" :class="isActive(tag)?'active':''" v-for="tag in Array.from(visitedViews)"
+ :to="tag" :key="tag.path" @contextmenu.prevent.native="openMenu(tag,$event)">
+ {{tag.title}}
+ <span class='el-icon-close' @click.prevent.stop='closeSelectedTag(tag)'></span>
+ </router-link>
+ </scroll-pane>
+ <ul class='contextmenu' v-show="visible" :style="{left:left+'px',top:top+'px'}">
+ <li @click="closeSelectedTag(selectedTag)">关闭当前</li>
+ <li @click="closeOthersTags">关闭其它</li>
+ <li @click="closeAllTags">关闭所有</li>
+ </ul>
+ </div>
+</template>
+
+<script>
+import ScrollPane from '@/components/ScrollPane'
+// import { generateTitle } from '@/utils/i18n'
+
+export default {
+ components: { ScrollPane },
+ data() {
+ return {
+ visible: false,
+ top: 0,
+ left: 0,
+ selectedTag: {}
+ }
+ },
+ computed: {
+ visitedViews() {
+ return this.$store.state.tagsView.visitedViews
+ }
+ },
+ watch: {
+ $route() {
+ this.addViewTags()
+ this.moveToCurrentTag()
+ },
+ visible(value) {
+ if (value) {
+ document.body.addEventListener('click', this.closeMenu)
+ } else {
+ document.body.removeEventListener('click', this.closeMenu)
+ }
+ }
+ },
+ mounted() {
+ this.addViewTags()
+ },
+ methods: {
+ // generateTitle, // generateTitle by vue-i18n
+ generateRoute() {
+ if (this.$route.name) {
+ return this.$route
+ }
+ return false
+ },
+ isActive(route) {
+ return route.path === this.$route.path
+ },
+ addViewTags() {
+ const route = this.generateRoute()
+ if (!route) {
+ return false
+ }
+ this.$store.dispatch('addVisitedViews', route)
+ },
+ moveToCurrentTag() {
+ const tags = this.$refs.tag
+ this.$nextTick(() => {
+ for (const tag of tags) {
+ if (tag.to.path === this.$route.path) {
+ this.$refs.scrollPane.moveToTarget(tag.$el)
+ break
+ }
+ }
+ })
+ },
+ closeSelectedTag(view) {
+ this.$store.dispatch('delVisitedViews', view).then((views) => {
+ if (this.isActive(view)) {
+ const latestView = views.slice(-1)[0]
+ if (latestView) {
+ this.$router.push(latestView)
+ } else {
+ this.$router.push('/')
+ }
+ }
+ })
+ },
+ closeOthersTags() {
+ this.$router.push(this.selectedTag)
+ this.$store.dispatch('delOthersViews', this.selectedTag).then(() => {
+ this.moveToCurrentTag()
+ })
+ },
+ closeAllTags() {
+ this.$store.dispatch('delAllViews')
+ this.$router.push('/')
+ },
+ openMenu(tag, e) {
+ this.visible = true
+ this.selectedTag = tag
+ const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
+ this.left = e.clientX - offsetLeft + 15 // 15: margin right
+ this.top = e.clientY
+ },
+ closeMenu() {
+ this.visible = false
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.tags-view-container {
+ .tags-view-wrapper {
+ background: #fff;
+ height: 34px;
+ border-bottom: 1px solid #d8dce5;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
+ .tags-view-item {
+ display: inline-block;
+ position: relative;
+ height: 26px;
+ line-height: 26px;
+ border: 1px solid #d8dce5;
+ color: #495060;
+ background: #fff;
+ padding: 0 8px;
+ font-size: 12px;
+ margin-left: 5px;
+ margin-top: 4px;
+ &:first-of-type {
+ margin-left: 15px;
+ }
+ &.active {
+ background-color: #42b983;
+ color: #fff;
+ border-color: #42b983;
+ &::before {
+ content: '';
+ background: #fff;
+ display: inline-block;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ position: relative;
+ margin-right: 2px;
+ }
+ }
+ }
+ }
+ .contextmenu {
+ margin: 0;
+ background: #fff;
+ z-index: 100;
+ position: absolute;
+ list-style-type: none;
+ padding: 5px 0;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 400;
+ color: #333;
+ box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+ li {
+ margin: 0;
+ padding: 7px 16px;
+ cursor: pointer;
+ &:hover {
+ background: #eee;
+ }
+ }
+ }
+}
+</style>
+
+<style rel="stylesheet/scss" lang="scss">
+//reset element css of el-icon-close
+.tags-view-wrapper {
+ .tags-view-item {
+ .el-icon-close {
+ width: 16px;
+ height: 16px;
+ vertical-align: 2px;
+ border-radius: 50%;
+ text-align: center;
+ transition: all .3s cubic-bezier(.645, .045, .355, 1);
+ transform-origin: 100% 50%;
+ &:before {
+ transform: scale(.6);
+ display: inline-block;
+ vertical-align: -3px;
+ }
+ &:hover {
+ background-color: #b4bccc;
+ color: #fff;
+ }
+ }
+ }
+}
+</style>
diff --git a/leave-school-vue/src/views/layout/components/index.js b/leave-school-vue/src/views/layout/components/index.js
new file mode 100644
index 0000000..7cddb7c
--- /dev/null
+++ b/leave-school-vue/src/views/layout/components/index.js
@@ -0,0 +1,4 @@
+export { default as Navbar } from './Navbar'
+export { default as Sidebar } from './Sidebar'
+export { default as TagsView } from './TagsView'
+export { default as AppMain } from './AppMain'
diff --git a/leave-school-vue/src/views/layout/mixin/ResizeHandler.js b/leave-school-vue/src/views/layout/mixin/ResizeHandler.js
new file mode 100644
index 0000000..b22c8bb
--- /dev/null
+++ b/leave-school-vue/src/views/layout/mixin/ResizeHandler.js
@@ -0,0 +1,41 @@
+import store from '@/store'
+
+const { body } = document
+const WIDTH = 1024
+const RATIO = 3
+
+export default {
+ watch: {
+ $route(route) {
+ if (this.device === 'mobile' && this.sidebar.opened) {
+ store.dispatch('CloseSideBar', { withoutAnimation: false })
+ }
+ }
+ },
+ beforeMount() {
+ window.addEventListener('resize', this.resizeHandler)
+ },
+ mounted() {
+ const isMobile = this.isMobile()
+ if (isMobile) {
+ store.dispatch('ToggleDevice', 'mobile')
+ store.dispatch('CloseSideBar', { withoutAnimation: true })
+ }
+ },
+ methods: {
+ isMobile() {
+ const rect = body.getBoundingClientRect()
+ return rect.width - RATIO < WIDTH
+ },
+ resizeHandler() {
+ if (!document.hidden) {
+ const isMobile = this.isMobile()
+ store.dispatch('ToggleDevice', isMobile ? 'mobile' : 'desktop')
+
+ if (isMobile) {
+ store.dispatch('CloseSideBar', { withoutAnimation: true })
+ }
+ }
+ }
+ }
+}
diff --git a/leave-school-vue/src/views/login/index.vue b/leave-school-vue/src/views/login/index.vue
new file mode 100644
index 0000000..fd4a9c1
--- /dev/null
+++ b/leave-school-vue/src/views/login/index.vue
@@ -0,0 +1,168 @@
+<template>
+ <div class="login-container">
+ <el-form class="login-form" autoComplete="on" :model="loginForm" :rules="loginRules" ref="loginForm" label-position="left">
+ <h3 class="title">离校管理系统</h3>
+ <el-form-item prop="username">
+ <span class="svg-container svg-container_login">
+ <svg-icon icon-class="user" />
+ </span>
+ <el-input name="username" type="text" v-model="loginForm.username" autoComplete="on" placeholder="username" />
+ </el-form-item>
+ <el-form-item prop="password">
+ <span class="svg-container">
+ <svg-icon icon-class="password"></svg-icon>
+ </span>
+ <el-input name="password" :type="pwdType" @keyup.enter.native="handleLogin" v-model="loginForm.password" autoComplete="on"
+ placeholder="password"></el-input>
+ <span class="show-pwd" @click="showPwd"><svg-icon icon-class="eye" /></span>
+ </el-form-item>
+ <el-form-item>
+ <el-button type="primary" style="width:100%;" :loading="loading" @click.native.prevent="handleLogin">
+ 登录
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+</template>
+
+<script>
+import { isvalidUsername } from '@/utils/validate'
+
+export default {
+ name: 'login',
+ data() {
+ const validateUsername = (rule, value, callback) => {
+ if (!isvalidUsername(value)) {
+ callback(new Error('请输入正确的用户名'))
+ } else {
+ callback()
+ }
+ }
+ const validatePass = (rule, value, callback) => {
+ if (value.length < 5) {
+ callback(new Error('密码不能小于5位'))
+ } else {
+ callback()
+ }
+ }
+ return {
+ loginForm: {
+ username: 'admin',
+ password: 'admin'
+ },
+ loginRules: {
+ username: [{ required: true, trigger: 'blur', validator: validateUsername }],
+ password: [{ required: true, trigger: 'blur', validator: validatePass }]
+ },
+ loading: false,
+ pwdType: 'password'
+ }
+ },
+ methods: {
+ showPwd() {
+ if (this.pwdType === 'password') {
+ this.pwdType = ''
+ } else {
+ this.pwdType = 'password'
+ }
+ },
+ handleLogin() {
+ this.$refs.loginForm.validate(valid => {
+ if (valid) {
+ this.loading = true
+ this.$store.dispatch('Login', this.loginForm).then(() => {
+ this.loading = false
+ this.$router.push({ path: '/' })
+ }).catch(() => {
+ this.loading = false
+ })
+ } else {
+ console.log('error submit!!')
+ return false
+ }
+ })
+ }
+ }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+$bg:#2d3a4b;
+$light_gray:#eee;
+
+/* reset element-ui css */
+.login-container {
+ .el-input {
+ display: inline-block;
+ height: 47px;
+ width: 85%;
+ input {
+ background: transparent;
+ border: 0px;
+ -webkit-appearance: none;
+ border-radius: 0px;
+ padding: 12px 5px 12px 15px;
+ color: $light_gray;
+ height: 47px;
+ &:-webkit-autofill {
+ -webkit-box-shadow: 0 0 0px 1000px $bg inset !important;
+ -webkit-text-fill-color: #fff !important;
+ }
+ }
+ }
+ .el-form-item {
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ background: rgba(0, 0, 0, 0.1);
+ border-radius: 5px;
+ color: #454545;
+ }
+}
+
+</style>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+$bg:#2d3a4b;
+$dark_gray:#889aa4;
+$light_gray:#eee;
+.login-container {
+ position: fixed;
+ height: 100%;
+ width: 100%;
+ background-color: $bg;
+ .login-form {
+ position: absolute;
+ left: 0;
+ right: 0;
+ width: 520px;
+ padding: 35px 35px 15px 35px;
+ margin: 120px auto;
+ }
+ .svg-container {
+ padding: 6px 5px 6px 15px;
+ color: $dark_gray;
+ vertical-align: middle;
+ width: 30px;
+ display: inline-block;
+ &_login {
+ font-size: 20px;
+ }
+ }
+ .title {
+ font-size: 26px;
+ font-weight: 400;
+ color: $light_gray;
+ margin: 0px auto 40px auto;
+ text-align: center;
+ font-weight: bold;
+ }
+ .show-pwd {
+ position: absolute;
+ right: 10px;
+ top: 7px;
+ font-size: 16px;
+ color: $dark_gray;
+ cursor: pointer;
+ user-select: none;
+ }
+}
+</style>
diff --git a/leave-school-vue/src/views/news/newspublish/index.vue b/leave-school-vue/src/views/news/newspublish/index.vue
new file mode 100644
index 0000000..a83a8fd
--- /dev/null
+++ b/leave-school-vue/src/views/news/newspublish/index.vue
@@ -0,0 +1,257 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-row :gutter="20">
+ <el-col :span="5">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="公告标题" v-model="listQuery.ggbt">
+ </el-input>
+ </el-col>
+ <el-col :span="5">
+ <el-date-picker
+ v-model="listQuery.fbqssj"
+ type="date"
+ placeholder="发布起始时间">
+ </el-date-picker>
+ </el-col>
+ <el-col :span="5">
+ <el-date-picker
+ v-model="listQuery.fbjssj"
+ type="date"
+ placeholder="发布结束时间">
+ </el-date-picker>
+ </el-col>
+ <el-col :span="9">
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="5">
+ <el-select class="filter-item" v-model="temp.sfky" placeholder="是否可用">
+ <el-option key="1" label="可用" value="1">
+ </el-option>
+ <el-option key="0" label="不可用" value="0">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="5">
+ <el-select clearable class="filter-item" v-model="listQuery.xswz" placeholder="显示位置">
+ <el-option v-for="item in xswzList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="5">
+ <el-select clearable class="filter-item" v-model="listQuery.jlckzt" placeholder="记录查看状态">
+ <el-option key="1" label="需要" value="1">
+ </el-option>
+ <el-option key="0" label="不需要" value="0">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="9">
+ </el-col>
+ </el-row>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" type="index" label='序号' width="95">
+ </el-table-column>
+ <el-table-column label="公告标题" align="center">
+ <template slot-scope="scope">
+ {{scope.row.ggbt}}
+ </template>
+ </el-table-column>
+ <el-table-column label="公告类型" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.gglx}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="接收者类型" align="center">
+ <template slot-scope="scope">
+ {{scope.row.jszlx}}
+ </template>
+ </el-table-column>
+ <el-table-column label="是否可用" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sfky}}
+ </template>
+ </el-table-column>
+ <el-table-column label="发布起始时间" align="center">
+ <template slot-scope="scope">
+ {{scope.row.fbqssj}}
+ </template>
+ </el-table-column>
+ <el-table-column label="发布结束时间" align="center">
+ <template slot-scope="scope">
+ {{scope.row.fbjssj}}
+ </template>
+ </el-table-column>
+ <el-table-column label="显示位置设置" align="center">
+ <template slot-scope="scope">
+ {{scope.row.xswz}}
+ </template>
+ </el-table-column>
+ <el-table-column label="点击数" align="center">
+ <template slot-scope="scope">
+ {{scope.row.djs}}
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="80%" top="10vh">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='margin-left:50px;'>
+ <el-form-item label="公告标题" prop="ggbt">
+ <el-input v-model="temp.ggbt"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="是否可用" prop="sfky">
+ <el-select class="filter-item" v-model="temp.sfky" placeholder="是否可用">
+ <el-option key="1" label="可用" value="1">
+ </el-option>
+ <el-option key="0" label="不可用" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="发布开始时间">
+ <el-date-picker
+ v-model="temp.fbqssj"
+ type="date"
+ placeholder="选择日期">
+ </el-date-picker>
+ </el-form-item>
+ <el-form-item label="发布结束时间">
+ <el-date-picker
+ v-model="temp.fbjssj"
+ type="date"
+ placeholder="选择日期">
+ </el-date-picker>
+ </el-form-item>
+ <el-form-item label="记录查看状态">
+ <el-select class="filter-item" v-model="temp.jlckzt" placeholder="请选择">
+ <el-option key="1" label="需要" value="1">
+ </el-option>
+ <el-option key="0" label="不需要" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="显示位置" prop="xswz">
+ <el-select class="filter-item" v-model="temp.xswz" placeholder="请选择">
+ <el-option v-for="item in xswzList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="接收者类型">
+ <el-radio-group v-model="temp.jszlx">
+ <el-radio v-for="item in jszlxList" :label="item.id" :key="item.id" >{{item.name}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+ <el-form-item label="公告内容">
+ <div class="editor-container">
+ <UE v-model="temp.ggnr" :config=config ref="ue"></UE>
+ </div>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createNewspublish, deleteNewspublish } from '@/api/newspublish-api'
+import { getDicList } from '@/api/dictionary-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+import UE from '@/components/UEditor'
+
+const initData = { sfky: '1', xswz: '14', jszlx: '16', ggnr: '' }
+export default {
+ name: 'newspublish',
+ components: { UE },
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ config: {
+ initialFrameWidth: null,
+ initialFrameHeight: 350
+ },
+ xswzList: [],
+ jszlxList: [],
+ rules: {
+ ggbt: [{ required: true, message: '公告标题必填', trigger: 'blur' }],
+ sfky: [{ required: true, message: '是否可用必选', trigger: 'change' }],
+ xswz: [{ required: true, message: '显示位置必选', trigger: 'change' }]
+ }
+ }
+ },
+ created() {
+ this.getXswzList()
+ this.getJszlxList()
+ this.handlePageList()
+ this.height = window.innerHeight - 266
+ },
+ methods: {
+ getXswzList() {
+ getDicList({ type: 'xswz' }).then(response => {
+ this.xswzList = response.items
+ })
+ },
+ getJszlxList() {
+ getDicList({ type: 'jszlx' }).then(response => {
+ this.jszlxList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ this.temp.ggnr = this.$refs.ue.getUEContent()
+ crudCreate(this, createNewspublish, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteNewspublish, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/news/newview/index.vue b/leave-school-vue/src/views/news/newview/index.vue
new file mode 100644
index 0000000..09a9ab3
--- /dev/null
+++ b/leave-school-vue/src/views/news/newview/index.vue
@@ -0,0 +1,107 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.gglx" placeholder="类型名称">
+ <el-option v-for="item in gglxList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="公告标题" v-model="listQuery.ggbt">
+ </el-input>
+ </el-col>
+ <el-col :span="12">
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </el-col>
+ </el-row>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" type="index" label='序号' width="95">
+ </el-table-column>
+ <el-table-column label="类型名称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.gglx}}
+ </template>
+ </el-table-column>
+ <el-table-column label="公告标题" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.ggbt}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="接收对象类型" align="center">
+ <template slot-scope="scope">
+ {{scope.row.jszlx}}
+ </template>
+ </el-table-column>
+ <el-table-column label="发布人" align="center">
+ <template slot-scope="scope">
+ {{scope.row.fbr}}
+ </template>
+ </el-table-column>
+ <el-table-column label="发布日期" align="center">
+ <template slot-scope="scope">
+ {{scope.row.fbrq}}
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+ </div>
+</template>
+
+<script>
+import { getList } from '@/api/newspublish-api'
+import { getDicList } from '@/api/dictionary-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+export default {
+ name: 'newview',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ gglxList: []
+ }
+ },
+ created() {
+ this.getGglxList()
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ getGglxList() {
+ getDicList({ type: 'gglx' }).then(response => {
+ this.gglxList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/auditscope/index.vue b/leave-school-vue/src/views/systemmanagement/auditscope/index.vue
new file mode 100644
index 0000000..7a37094
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/auditscope/index.vue
@@ -0,0 +1,129 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="范围名称" v-model="listQuery.fwkzmc">
+ </el-input>
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='范围控制代码' width="195">
+ <template slot-scope="scope">
+ {{scope.row.id}}
+ </template>
+ </el-table-column>
+ <el-table-column label="范围控制名称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.fwkzmc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="范围控制实现类" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.fwkzsxl}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="范围控制名称" prop="fwkzmc">
+ <el-input v-model="temp.fwkzmc"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="范围控制实现类" prop="fwkzsxl">
+ <el-input v-model="temp.fwkzsxl"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createAuditScope, deleteAuditScope } from '@/api/auditscope-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'auditscope',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ ssyxList: [],
+ sszygbList: [],
+ rules: {
+ fwkzmc: [{ required: true, message: '范围控制名称必填', trigger: 'blur' }],
+ fwkzsxl: [{ required: true, message: '范围控制实现类必填', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createAuditScope, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteAuditScope, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/autoaudittype/index.vue b/leave-school-vue/src/views/systemmanagement/autoaudittype/index.vue
new file mode 100644
index 0000000..9bcaa4e
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/autoaudittype/index.vue
@@ -0,0 +1,129 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="自动审核类型名称" v-model="listQuery.zdshlxmc">
+ </el-input>
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='自动审核类型代码' width="195">
+ <template slot-scope="scope">
+ {{scope.row.id}}
+ </template>
+ </el-table-column>
+ <el-table-column label="自动审核类型名称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.zdshlxmc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="自动审核类型实现类" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.zdshlxsxl}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="自动审核类型名称" prop="zdshlxmc">
+ <el-input v-model="temp.zdshlxmc"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="自动审核类型实现类" prop="zdshlxsxl">
+ <el-input v-model="temp.zdshlxsxl"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createAutoAuditType, deleteAutoAuditType } from '@/api/autoaudittype-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'autoaudittype',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ ssyxList: [],
+ sszygbList: [],
+ rules: {
+ zdshlxmc: [{ required: true, message: '自动审核类型名称必填', trigger: 'blur' }],
+ zdshlxsxl: [{ required: true, message: '自动审核类型实现类必填', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createAutoAuditType, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteAutoAuditType, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/class/index.vue b/leave-school-vue/src/views/systemmanagement/class/index.vue
new file mode 100644
index 0000000..33619b6
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/class/index.vue
@@ -0,0 +1,258 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-select clearable @change="initZyList" class="filter-item" v-model="listQuery.yx" placeholder="院系">
+ <el-option v-for="item in yxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.zy" placeholder="专业">
+ <el-option v-for="item in zyList" :key="item.id" :label="item.zymc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="班级名称" v-model="listQuery.bjmc">
+ </el-input>
+ </el-col>
+ <el-col :span="12">
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-select clearable @change="initZyList" class="filter-item" v-model="listQuery.nj" placeholder="年级">
+ <el-option v-for="item in njList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="班级代码" v-model="listQuery.bjdm">
+ </el-input>
+ </el-col>
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.sfky" placeholder="是否可用">
+ <el-option key="1" label="可用" value="1">
+ </el-option>
+ <el-option key="0" label="不可用" value="0">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="12">
+ </el-col>
+ </el-row>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column fixed align="center" label='序号' width="95">
+ <template slot-scope="scope">
+ {{scope.row.id}}
+ </template>
+ </el-table-column>
+ <el-table-column label="年级" align="center">
+ <template slot-scope="scope">
+ {{scope.row.njmc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="院系" align="center">
+ <template slot-scope="scope">
+ {{scope.row.yxmc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="专业" align="center">
+ <template slot-scope="scope">
+ {{scope.row.zymc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="班级代码" align="center">
+ <template slot-scope="scope">
+ {{scope.row.bjdm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="班级名称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.bjmc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="是否可用" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sfkymc}}
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex"
+ :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="班级代码" prop="bjdm">
+ <el-input v-model="temp.bjdm"></el-input>
+ </el-form-item>
+ <el-form-item label="班级名称" prop="bjmc">
+ <el-input v-model="temp.bjmc"></el-input>
+ </el-form-item>
+ <el-form-item label="院系" prop="yx">
+ <el-select class="filter-item" @change="initFormZyList" v-model="temp.yx" placeholder="--请选择--">
+ <el-option v-for="item in yxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="专业" prop="zy">
+ <el-select class="filter-item" v-model="temp.zy" placeholder="--请选择--">
+ <el-option v-for="item in formZyList" :key="item.id" :label="item.zymc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="年级" prop="nj">
+ <el-select class="filter-item" v-model="temp.nj" placeholder="--请选择--">
+ <el-option v-for="item in njList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="是否可用">
+ <el-select class="filter-item" v-model="temp.sfky" placeholder="--请选择--">
+ <el-option key="1" label="可用" value="1">
+ </el-option>
+ <el-option key="0" label="不可用" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createClass, deleteClass } from '@/api/class-api'
+import { getDicList } from '@/api/dictionary-api'
+import { getAllList as getAllDeptList } from '@/api/department-api'
+import { getZyListByYx } from '@/api/major-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'class',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ yxList: [],
+ zyList: [],
+ formZyList: [],
+ njList: [],
+ rules: {
+ bjdm: [{ required: true, message: '班级代码必填', trigger: 'blur' }],
+ bjmc: [{ required: true, message: '班级名称必填', trigger: 'blur' }],
+ yx: [{ required: true, message: '院系必选', trigger: 'change' }],
+ zy: [{ required: true, message: '专业必选', trigger: 'change' }],
+ nj: [{ required: true, message: '年级必选', trigger: 'change' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.initYxList()
+ this.initZyList()
+ this.initNjList()
+ this.handlePageList()
+ this.height = window.innerHeight - 266
+ },
+ methods: {
+ initYxList() {
+ getAllDeptList(this.listQuery).then(response => {
+ this.yxList = response.items
+ })
+ },
+ initZyList() {
+ getZyListByYx({ yx: this.listQuery.yx }).then(response => {
+ this.zyList = response.items
+ // TODO 坑,this.listQuery.zy == null 直接赋值,专业下拉框选择出bug,无法选择,原因未知
+ for (const attr in this.listQuery) {
+ if (attr === 'zy') {
+ this.listQuery['zy'] = null
+ }
+ }
+ })
+ },
+ initFormZyList() {
+ getZyListByYx({ yx: this.temp.yx }).then(response => {
+ this.formZyList = response.items
+ // TODO 坑,this.listQuery.zy == null 直接赋值,专业下拉框选择出bug,无法选择,原因未知
+ for (const attr in this.temp) {
+ if (attr === 'zy') {
+ this.temp['zy'] = null
+ }
+ }
+ })
+ },
+ initNjList() {
+ getDicList({ type: 'nj' }).then(response => {
+ this.njList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createClass, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteClass, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/department/index.vue b/leave-school-vue/src/views/systemmanagement/department/index.vue
new file mode 100644
index 0000000..d1c71bc
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/department/index.vue
@@ -0,0 +1,197 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="单位代码" v-model="listQuery.dwdm">
+ </el-input>
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="单位名称" v-model="listQuery.dwmc">
+ </el-input>
+ <el-select clearable class="filter-item" v-model="listQuery.sfqy" placeholder="是否启用">
+ <el-option key="1" label="启用" value="1">
+ </el-option>
+ <el-option key="0" label="未启用" value="0">
+ </el-option>
+ </el-select>
+ <el-select clearable class="filter-item" v-model="listQuery.lbm" placeholder="类别码">
+ <el-option v-for="item in lbmList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column fixed align="center" label='序号' width="95">
+ <template slot-scope="scope">
+ {{scope.row.id}}
+ </template>
+ </el-table-column>
+ <el-table-column fixed label="单位代码">
+ <template slot-scope="scope">
+ {{scope.row.dwdm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="单位名称" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.dwmc}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="单位简称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.dwjc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="单位英文名称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.dwywmc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="是否启用" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sfqy}}
+ </template>
+ </el-table-column>
+ <el-table-column class-name="status-col" label="类别码" width="110" align="center">
+ <template slot-scope="scope">
+ <el-tag :type="scope.row.lbm | statusFilter">{{scope.row.lbm}}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column align="center" prop="created_at" label="创建时间" width="200">
+ <template slot-scope="scope">
+ <i class="el-icon-time"></i>
+ {{scope.row.cjsj}}
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex"
+ :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="单位代码" prop="dwdm">
+ <el-input v-model="temp.dwdm"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="单位名称" prop="dwmc">
+ <el-input v-model="temp.dwmc"></el-input>
+ </el-form-item>
+ <el-form-item label="单位简称" prop="dwjc">
+ <el-input v-model="temp.dwjc"></el-input>
+ </el-form-item>
+ <el-form-item label="单位英文名称" prop="dwywmc">
+ <el-input v-model="temp.dwywmc"></el-input>
+ </el-form-item>
+ <el-form-item label="排序" prop="px">
+ <el-input v-model="temp.px"></el-input>
+ </el-form-item>
+ <el-form-item label="类别码">
+ <el-select class="filter-item" v-model="temp.lbm" placeholder="请选择">
+ <el-option v-for="item in lbmList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="是否启用">
+ <el-select class="filter-item" v-model="temp.sfqy" placeholder="请选择">
+ <el-option key="1" label="启用" value="1">
+ </el-option>
+ <el-option key="0" label="未启用" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createDepartment, deleteDepartment } from '@/api/department-api'
+import { getDicList } from '@/api/dictionary-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfqy: '1' }
+export default {
+ name: 'department',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ lbmList: [],
+ rules: {
+ dwdm: [{ required: true, message: '单位代码必填', trigger: 'blur' }],
+ dwmc: [{ required: true, message: '单位名称必填', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.getLbmList()
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ getLbmList() {
+ getDicList({ type: 'lbm' }).then(response => {
+ this.lbmList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createDepartment, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteDepartment, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/major/index.vue b/leave-school-vue/src/views/systemmanagement/major/index.vue
new file mode 100644
index 0000000..2738ff7
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/major/index.vue
@@ -0,0 +1,190 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="专业代码" v-model="listQuery.zydm">
+ </el-input>
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="专业名称" v-model="listQuery.zymc">
+ </el-input>
+ <el-select clearable class="filter-item" v-model="listQuery.sfky" placeholder="是否可用">
+ <el-option key="1" label="可用" value="1">
+ </el-option>
+ <el-option key="0" label="不可用" value="0">
+ </el-option>
+ </el-select>
+ <el-select clearable class="filter-item" v-model="listQuery.ssyx" placeholder="所属院系">
+ <el-option v-for="item in ssyxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='序号' width="95">
+ <template slot-scope="scope">
+ {{scope.row.id}}
+ </template>
+ </el-table-column>
+ <el-table-column label="专业代码" align="center">
+ <template slot-scope="scope">
+ {{scope.row.zydm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="专业名称" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.zymc}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="是否可用" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sfky}}
+ </template>
+ </el-table-column>
+ <el-table-column label="所属院系" align="center">
+ <template slot-scope="scope">
+ {{scope.row.ssyx}}
+ </template>
+ </el-table-column>
+ <el-table-column label="所属专业(国标)" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sszygb}}
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="专业代码" prop="zydm">
+ <el-input v-model="temp.zydm"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="专业名称" prop="zymc">
+ <el-input v-model="temp.zymc"></el-input>
+ </el-form-item>
+ <el-form-item label="所在院系">
+ <el-select class="filter-item" v-model="temp.ssyx" placeholder="请选择">
+ <el-option v-for="item in ssyxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="是否可用">
+ <el-select class="filter-item" v-model="temp.sfky" placeholder="请选择">
+ <el-option key="1" label="可用" value="1">
+ </el-option>
+ <el-option key="0" label="不可用" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="所属专业(国标)">
+ <el-select class="filter-item" v-model="temp.sszygb" placeholder="--请选择专业(国标)--">
+ <el-option v-for="item in sszygbList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createMajor, deleteMajor } from '@/api/major-api'
+import { getDicList } from '@/api/dictionary-api'
+import { getAllList as getAllDeptList } from '@/api/department-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'major',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ ssyxList: [],
+ sszygbList: [],
+ rules: {
+ zydm: [{ required: true, message: '专业代码必填', trigger: 'blur' }],
+ zymc: [{ required: true, message: '专业名称必填', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.getSsyxList()
+ this.getSszygbList()
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ getSszygbList() {
+ getDicList({ type: 'gjzybz' }).then(response => {
+ this.sszygbList = response.items
+ })
+ },
+ getSsyxList() {
+ getAllDeptList(this.listQuery).then(response => {
+ this.ssyxList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createMajor, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteMajor, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/rostersyncinterface/index.vue b/leave-school-vue/src/views/systemmanagement/rostersyncinterface/index.vue
new file mode 100644
index 0000000..886a122
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/rostersyncinterface/index.vue
@@ -0,0 +1,146 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="代码" v-model="listQuery.dm">
+ </el-input>
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="名称" v-model="listQuery.mc">
+ </el-input>
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="条件" v-model="listQuery.tj">
+ </el-input>
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="排序" v-model="listQuery.px">
+ </el-input>
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='代码' width="195">
+ <template slot-scope="scope">
+ {{scope.row.dm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="名称" align="center">
+ <template slot-scope="scope">
+ {{scope.row.mc}}
+ </template>
+ </el-table-column>
+ <el-table-column label="条件" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.tj}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="排序" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.px}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="代码" prop="dm">
+ <el-input v-model="temp.dm"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="名称" prop="mc">
+ <el-input v-model="temp.mc"></el-input>
+ </el-form-item>
+ <el-form-item label="条件" prop="tj">
+ <el-input type="textarea" :rows="2" v-model="temp.tj"></el-input>
+ </el-form-item>
+ <el-form-item label="排序" prop="px">
+ <el-input v-model="temp.px"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createRosterSyncInterface, deleteRosterSyncInterface } from '@/api/rostersyncinterface-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'rostersyncinterface',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ ssyxList: [],
+ sszygbList: [],
+ rules: {
+ zdshlxmc: [{ required: true, message: '自动审核类型名称必填', trigger: 'blur' }],
+ zdshlxsxl: [{ required: true, message: '自动审核类型实现类必填', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createRosterSyncInterface, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteRosterSyncInterface, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/systemmanagement/schoolyear/index.vue b/leave-school-vue/src/views/systemmanagement/schoolyear/index.vue
new file mode 100644
index 0000000..53c7014
--- /dev/null
+++ b/leave-school-vue/src/views/systemmanagement/schoolyear/index.vue
@@ -0,0 +1,130 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="学年代码" v-model="listQuery.xndm">
+ </el-input>
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="学年名称" v-model="listQuery.xnmc">
+ </el-input>
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='序号' width="95">
+ <template slot-scope="scope">
+ {{scope.row.id}}
+ </template>
+ </el-table-column>
+ <el-table-column label="学年代码" align="center">
+ <template slot-scope="scope">
+ {{scope.row.xndm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="学年名称" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.xnmc}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex"
+ :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="学年代码1" prop="xndm">
+ <el-input v-if="dialogStatus === 'update'" disabled v-model="temp.xndm"></el-input>
+ <el-input v-else v-model="temp.xndm"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="学年名称" prop="xnmc">
+ <el-input v-model="temp.xnmc"></el-input>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createSchoolyear, deleteSchoolyear } from '@/api/schoolyear-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = {}
+export default {
+ name: 'schoolyear',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ rules: {
+ xndm: [{ required: true, message: '学年代码必填', trigger: 'blur' }],
+ xnmc: [{ required: true, message: '学年名称必填', trigger: 'blur' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.handlePageList()
+ this.height = window.innerHeight - 216
+ },
+ methods: {
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createSchoolyear, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteSchoolyear, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
\ No newline at end of file
diff --git a/leave-school-vue/src/views/workteam/departmentleader/index.vue b/leave-school-vue/src/views/workteam/departmentleader/index.vue
new file mode 100644
index 0000000..c521dce
--- /dev/null
+++ b/leave-school-vue/src/views/workteam/departmentleader/index.vue
@@ -0,0 +1,234 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="工号" v-model="listQuery.gh">
+ </el-input>
+ </el-col>
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="姓名" v-model="listQuery.xm">
+ </el-input>
+ </el-col>
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.yx" placeholder="院系">
+ <el-option v-for="item in yxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="12">
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.zzmm" placeholder="政治面貌">
+ <el-option v-for="item in zzmmList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.xb" placeholder="性别">
+ <el-option v-for="item in xbList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ </el-col>
+ <el-col :span="12">
+ </el-col>
+ </el-row>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='工号'>
+ <template slot-scope="scope">
+ {{scope.row.gh}}
+ </template>
+ </el-table-column>
+ <el-table-column label="姓名" align="center">
+ <template slot-scope="scope">
+ {{scope.row.xm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="院系" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.yx}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="性别" align="center">
+ <template slot-scope="scope">
+ {{scope.row.xb}}
+ </template>
+ </el-table-column>
+ <el-table-column label="政治面貌" align="center">
+ <template slot-scope="scope">
+ {{scope.row.zzmm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="联系电话" align="center">
+ <template slot-scope="scope">
+ {{scope.row.lxdh}}
+ </template>
+ </el-table-column>
+ <el-table-column label="是否在任" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sfzr}}
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="工号" prop="gh">
+ <el-input v-model="temp.gh"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="姓名" prop="xm">
+ <el-input v-model="temp.xm"></el-input>
+ </el-form-item>
+ <el-form-item label="性别">
+ <el-select class="filter-item" v-model="temp.xb" placeholder="请选择">
+ <el-option v-for="item in xbList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="政治面貌">
+ <el-select class="filter-item" v-model="temp.zzmm" placeholder="请选择">
+ <el-option v-for="item in zzmmList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="联系电话" prop="lxdh">
+ <el-input v-model="temp.lxdh"></el-input>
+ </el-form-item>
+ <el-form-item label="是否在任">
+ <el-select class="filter-item" v-model="temp.sfzr" placeholder="请选择">
+ <el-option key="1" label="是" value="1">
+ </el-option>
+ <el-option key="0" label="否" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="院系" prop="yx">
+ <el-select class="filter-item" v-model="temp.yx" placeholder="--请选择院系--">
+ <el-option v-for="item in yxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createDepartmentleader, deleteDepartmentleader } from '@/api/departmentleader-api'
+import { getDicList } from '@/api/dictionary-api'
+import { getAllList as getAllDeptList } from '@/api/department-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'departmentleader',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ yxList: [],
+ zzmmList: [],
+ xbList: [],
+ rules: {
+ gh: [{ required: true, message: '工号必填', trigger: 'blur' }],
+ xm: [{ required: true, message: '姓名必填', trigger: 'blur' }],
+ yx: [{ required: true, message: '院系必填', trigger: 'change' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.getYxList()
+ this.getZzmmList()
+ this.getXbList()
+ this.handlePageList()
+ this.height = window.innerHeight - 266
+ },
+ methods: {
+ getYxList() {
+ getAllDeptList(this.listQuery).then(response => {
+ this.yxList = response.items
+ })
+ },
+ getZzmmList() {
+ getDicList({ type: 'zzmm' }).then(response => {
+ this.zzmmList = response.items
+ })
+ },
+ getXbList() {
+ getDicList({ type: 'xb' }).then(response => {
+ this.xbList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createDepartmentleader, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteDepartmentleader, rowid, this.handlePageList)
+ }
+ }
+}
+</script>
diff --git a/leave-school-vue/src/views/workteam/instructor/index.vue b/leave-school-vue/src/views/workteam/instructor/index.vue
new file mode 100644
index 0000000..cad431e
--- /dev/null
+++ b/leave-school-vue/src/views/workteam/instructor/index.vue
@@ -0,0 +1,223 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="工号" v-model="listQuery.gh">
+ </el-input>
+ </el-col>
+ <el-col :span="4">
+ <el-input @keyup.enter.native="handleFilter" style="width: 200px;" class="filter-item" placeholder="姓名" v-model="listQuery.xm">
+ </el-input>
+ </el-col>
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.yx" placeholder="院系">
+ <el-option v-for="item in szyxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="12">
+ <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查询</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate(null, 'create')" type="primary" icon="el-icon-edit">添加</el-button>
+ <el-button class="filter-item" style="margin-left: 10px;" @click="handleReset" type="primary" icon="el-icon-edit">重置</el-button>
+ </el-col>
+ </el-row>
+ <el-row :gutter="20">
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.zzmm" placeholder="政治面貌">
+ <el-option v-for="item in zzmmList" :key="item.id" :label="item.name" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ <el-select clearable class="filter-item" v-model="listQuery.sfzr" placeholder="是否在任">
+ <el-option key="1" label="是" value="1">
+ </el-option>
+ <el-option key="0" label="否" value="0">
+ </el-option>
+ </el-select>
+ </el-col>
+ <el-col :span="4">
+ </el-col>
+ <el-col :span="12">
+ </el-col>
+ </el-row>
+ </div>
+ <el-table :height="height" :data="items" v-loading="listLoading" element-loading-text="Loading" border fit highlight-current-row>
+ <el-table-column align="center" label='工号'>
+ <template slot-scope="scope">
+ {{scope.row.gh}}
+ </template>
+ </el-table-column>
+ <el-table-column label="姓名" align="center">
+ <template slot-scope="scope">
+ {{scope.row.xm}}
+ </template>
+ </el-table-column>
+ <el-table-column label="所带班级" align="center">
+ <template slot-scope="scope">
+ <span>{{scope.row.sdbj}}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="班级总人数" align="center">
+ <template slot-scope="scope">
+ {{scope.row.bjzrs}}
+ </template>
+ </el-table-column>
+ <el-table-column label="所在院系" align="center">
+ <template slot-scope="scope">
+ {{scope.row.szyx}}
+ </template>
+ </el-table-column>
+ <el-table-column label="是否在任" align="center">
+ <template slot-scope="scope">
+ {{scope.row.sfzr}}
+ </template>
+ </el-table-column>
+ <el-table-column
+ fixed="right"
+ header-align="center"
+ align="center"
+ width="150"
+ label="操作">
+ <template slot-scope="scope">
+ <el-button type="text" size="small" @click="handleCreate(scope.row.id, 'update')">修改</el-button>
+ <el-button type="text" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="pagination-container">
+ <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.pageIndex" :page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="recordCount">
+ </el-pagination>
+ </div>
+
+ <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
+ <el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="150px" style='width: 400px; margin-left:50px;'>
+ <el-form-item label="工号" prop="gh">
+ <el-input v-model="temp.gh"></el-input>
+ <input type="hidden" v-model="temp.id" />
+ </el-form-item>
+ <el-form-item label="姓名" prop="xm">
+ <el-input v-model="temp.xm"></el-input>
+ </el-form-item>
+ <el-form-item label="所带班级" prop="sdbj">
+ <el-select class="filter-item" v-model="temp.sdbj" placeholder="请选择">
+ <el-option v-for="item in sdbjList" :key="item.id" :label="item.bjmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="是否在任">
+ <el-select class="filter-item" v-model="temp.sfzr" placeholder="请选择">
+ <el-option key="1" label="是" value="1">
+ </el-option>
+ <el-option key="0" label="否" value="0">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="所在院系">
+ <el-select class="filter-item" v-model="temp.szyx" placeholder="--请选择院系--">
+ <el-option v-for="item in szyxList" :key="item.id" :label="item.dwmc" :value="item.id">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ </el-form>
+ <div slot="footer" class="dialog-footer">
+ <el-button @click="dialogFormVisible = false">返回</el-button>
+ <el-button type="primary" @click="createData">提交</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import { getList, getItem, createInstructor, deleteInstructor } from '@/api/instructor-api'
+import { getAllList } from '@/api/class-api'
+import { getDicList } from '@/api/dictionary-api'
+import { getAllList as getAllDeptList } from '@/api/department-api'
+import waves from '@/directive/waves' // 水波纹指令
+import { resetForm } from '@/utils'
+import { crudPageList, crudGetItem, crudCreate, crudDelete } from '@/utils/crud'
+import mixindata from '@/utils/crud'
+
+const initData = { sfky: '1' }
+export default {
+ name: 'instructor',
+ directives: {
+ waves
+ },
+ mixins: [mixindata],
+ data() {
+ return {
+ szyxList: [],
+ sdbjList: [],
+ zzmmList: [],
+ rules: {
+ gh: [{ required: true, message: '工号必填', trigger: 'blur' }],
+ xm: [{ required: true, message: '姓名必填', trigger: 'blur' }],
+ sdbj: [{ required: true, message: '所带班级必填', trigger: 'change' }]
+ }
+ }
+ },
+ filters: {
+ statusFilter(status) {
+ const statusMap = {
+ '1': 'success',
+ '0': 'danger'
+ }
+ return statusMap[status]
+ }
+ },
+ created() {
+ this.getSzyxList()
+ this.getSdbjList()
+ this.getZzmmList()
+ this.handlePageList()
+ this.height = window.innerHeight - 266
+ },
+ methods: {
+ getSzyxList() {
+ getAllDeptList(this.listQuery).then(response => {
+ this.szyxList = response.items
+ })
+ },
+ getSdbjList() {
+ getAllList(this.listQuery).then(response => {
+ this.sdbjList = response.items
+ })
+ },
+ getZzmmList() {
+ getDicList({ type: 'zzmm' }).then(response => {
+ this.zzmmList = response.items
+ })
+ },
+ handlePageList() {
+ crudPageList(this, getList)
+ },
+ handleCreate(rowid, dialogStatus) {
+ this.dialogStatus = dialogStatus
+ crudGetItem(this, getItem, rowid, initData)
+ },
+ handleReset() {
+ resetForm(this.listQuery)
+ },
+ handleFilter() {
+ this.listQuery.pageIndex = 1
+ this.handlePageList()
+ },
+ handleSizeChange(val) {
+ this.listQuery.pageSize = val
+ this.handlePageList()
+ },
+ handleCurrentChange(val) {
+ this.listQuery.pageIndex = val
+ this.handlePageList()
+ },
+ createData() {
+ crudCreate(this, createInstructor, this.handlePageList)
+ },
+ handleDelete(rowid) {
+ crudDelete(this, deleteInstructor, rowid, this.handlePageList)
+ }
+ }
+}
+</script>