├── .gitignore ├── README.md ├── babel.config.js ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── global.css │ └── logo.png ├── components │ ├── Aside.vue │ └── Header.vue ├── config │ └── axiosConfig.js ├── main.js ├── router │ └── index.js ├── store │ └── index.js ├── styles.scss ├── template │ └── 用户信息导入模板.xlsx └── views │ ├── error-pages │ └── Not404.vue │ └── pages │ ├── CheckAdmin.vue │ ├── CheckAdminHistory.vue │ ├── CheckUser.vue │ ├── CheckUserHistory.vue │ ├── Home.vue │ ├── Login.vue │ ├── Manage.vue │ ├── Right.vue │ ├── RightDataShow.vue │ ├── Role.vue │ ├── RoleDataShow.vue │ ├── User.vue │ ├── UserDataShow.vue │ └── UserInfo.vue └── vue.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## attendance_management_vue 2 | ## 基于SpringBoot的学生考勤系统前端设计 3 | ### 热词:Vue、Element UI、Echarts 4 | 5 | 6 | ### 1、、运行环境: 7 | Nodejs v16 8 | 9 | ### 2、简介 10 | + 这个项目是前端项目,项目所需文件都在下面。
11 | + 免编译使用方法 12 | + 安装serve插件:`npm install -g serve` 13 | + [点此下载](https://github.com/WongSilver/attendance_management_vue/releases/tag/v0.0.1) 打包好的项目 。解压,在**dist父目录** **dist父目录** **dist父目录**中运行命令:`serve -s dist`
14 | + 正常使用方法: 15 | + 项目安装 `npm install` 报错的话用NodeJS14的长期维护版 `https://nodejs.org/download/release/v14.19.1/` 16 | + 项目运行 `npm run serve` 报错的话安装 `npm install node-sass`, 详细看下一步 17 | + **有同学安装过程中可能遇到`node-sass`安装失败, 可以参考链接的解决方案 [点此访问](https://blog.csdn.net/kingslave1/article/details/130526329)** 18 | + 后端项目地址 [点此访问](https://github.com/WongSilver/attendance_management_api) 19 | 20 | 21 | ## [后端项目](https://github.com/WongSilver/attendance_management_api)包含了部分演示效果,有问题咨询 QQ:783244553 22 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "attendance_management_vue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.26.1", 11 | "core-js": "^3.8.3", 12 | "echarts": "^5.3.2", 13 | "element-ui": "^2.3.6", 14 | "sass-resources-loader": "^2.2.4", 15 | "vue": "^2.6.14", 16 | "vue-router": "^3.5.1", 17 | "vuex": "^3.6.2", 18 | "webpack": "^5.70.0" 19 | }, 20 | "devDependencies": { 21 | "@vue/cli-plugin-babel": "~5.0.0", 22 | "@vue/cli-plugin-router": "~5.0.0", 23 | "@vue/cli-plugin-vuex": "~5.0.0", 24 | "@vue/cli-service": "~5.0.0", 25 | "node-sass": "^7.0.1", 26 | "sass-loader": "^12.6.0", 27 | "vue-cli-plugin-element-ui": "~1.1.4", 28 | "vue-template-compiler": "^2.6.14" 29 | }, 30 | "browserslist": [ 31 | "> 1%", 32 | "last 2 versions", 33 | "not dead" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WongSilver/attendance_management_vue/24d3f8d185366e62295c9a1fe5c500173ddfe948/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/assets/global.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html, body { 8 | height: 100%; 9 | } 10 | 11 | .mr-5 { 12 | margin-right: 5px; 13 | } 14 | 15 | .ml-5 { 16 | margin-left: 5px; 17 | } 18 | 19 | .m-2 { 20 | margin: 2px; 21 | } 22 | 23 | .pd-10 { 24 | padding: 10px 0; 25 | } 26 | 27 | 28 | /*全局设置 header main footer*/ 29 | #app { 30 | position: absolute; 31 | top: 0; 32 | left: 0; 33 | height: 100%; 34 | width: 100%; 35 | padding: 0; 36 | margin: 0; 37 | } 38 | 39 | .el-container { 40 | height: 100vh; 41 | } 42 | 43 | .el-header { 44 | background-color: #428675; 45 | text-align: center; 46 | height: 20%; 47 | } 48 | 49 | .el-main { 50 | background-color: #c6e6e8; 51 | text-align: center; 52 | } 53 | 54 | .el-footer { 55 | background-color: #428675; 56 | color: #333; 57 | vertical-align: bottom; 58 | text-align: center; 59 | } -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WongSilver/attendance_management_vue/24d3f8d185366e62295c9a1fe5c500173ddfe948/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Aside.vue: -------------------------------------------------------------------------------- 1 | 30 | 54 | -------------------------------------------------------------------------------- /src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 51 | 52 | 57 | -------------------------------------------------------------------------------- /src/config/axiosConfig.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import ElementUI from "element-ui"; 3 | import router from "../router"; 4 | import store from "../store"; 5 | 6 | // 配置基础路由路径 7 | axios.defaults.baseURL = "http://127.0.0.1:8088/" 8 | 9 | // 前置拦截 10 | axios.interceptors.request.use(config => { 11 | config.headers['Content-Type'] = 'application/json;charset=utf-8'; 12 | if (localStorage.getItem("token") !== null) { 13 | config.headers['authorization'] = localStorage.getItem("token"); 14 | } else if ((localStorage.getItem("token") === null)) { 15 | router.push("/login") 16 | } 17 | 18 | return config 19 | }) 20 | 21 | // 后置拦截 22 | axios.interceptors.response.use(response => { 23 | let res = response.data; 24 | let msg = res.msg; 25 | 26 | //返回文件 27 | if (response.config.responseType === 'blob') { 28 | return res 29 | } 30 | //判断状态码是否成功 31 | if (res.code === 200) { 32 | return response 33 | } else if (res.code === 999) { 34 | msg = "token已失效,请重新登录" 35 | store.commit("REMOVE_INFO") 36 | router.push("/login") 37 | } else if (res.code === 233) { 38 | msg = "无权限" 39 | } else if (res.code === 401) { 40 | msg = "未授权异常,请重新登录" 41 | router.push("/login") 42 | } 43 | ElementUI.Message.error(msg, {duration: 3 * 100}) 44 | return Promise.reject(res.msg) 45 | 46 | }, 47 | 48 | // 处理后端没有定义的错误 49 | error => { 50 | let response = error.response; 51 | let msg; 52 | if (response.status === 401) { 53 | store.commit("REMOVE_INFO") 54 | msg = "未授权异常,请重新登录" 55 | router.push("/login") 56 | } else if(response.status === 500){ 57 | store.commit("REMOVE_INFO") 58 | msg = "未知错误,请重新登录" 59 | router.push("/login") 60 | }else { 61 | msg = "未知错误" 62 | } 63 | ElementUI.Message.error(msg, {duration: 3 * 1000}) 64 | return Promise.reject(res.msg) 65 | } 66 | ) -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | import ElementUI from "element-ui"; 6 | import axios from "axios"; 7 | import "./styles.scss"; 8 | import "./config/axiosConfig" 9 | import "./assets/global.css" 10 | 11 | // 全局使用ele 12 | Vue.use(ElementUI, {size: "small"}); 13 | 14 | Vue.config.productionTip = false; 15 | 16 | // 添加http请求库 17 | Vue.prototype.$axios = axios; 18 | 19 | // 设置标题 20 | router.beforeEach((to,from,next) =>{ 21 | if(to.meta.name){ 22 | document.title = to.meta.name 23 | } 24 | next(); 25 | }) 26 | 27 | new Vue({ 28 | router, 29 | store, 30 | render: (h) => h(App), 31 | }).$mount("#app"); 32 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import VueRouter from "vue-router"; 3 | import Manage from "../views/pages/Manage.vue"; 4 | import Home from "../views/pages/Home.vue"; 5 | import Login from "../views/pages/Login.vue"; 6 | import User from "../views/pages/User.vue"; 7 | import UserInfo from "../views/pages/UserInfo.vue"; 8 | import Role from "../views/pages/Role.vue"; 9 | import Right from "../views/pages/Right.vue"; 10 | import CheckUser from "../views/pages/CheckUser.vue"; 11 | import CheckAdmin from "../views/pages/CheckAdmin.vue"; 12 | import CheckUserHistory from "../views/pages/CheckUserHistory.vue"; 13 | import CheckAdminHistory from "../views/pages/CheckAdminHistory.vue"; 14 | import Not404 from "../views/error-pages/Not404.vue"; 15 | 16 | Vue.use(VueRouter); 17 | 18 | const routes = [ 19 | {path: "/login", name: "Login", component: Login,meta: {name: "登录", path: "/login"}}, 20 | 21 | //TODO 先用固定路由,动态路由后期完善 22 | { 23 | path: "/", 24 | name: "Manage", 25 | component: Manage, 26 | redirect: "/home", 27 | children: [ 28 | {path: "/", name: "home", component: Home, meta: {name: "首页", path: "/home"}}, 29 | {path: "home", name: "Home", component: Home, meta: {name: "首页", path: "/home"}}, 30 | {path: "user", name: "User", component: User, meta: {name: "用户列表", path: "/user"}}, 31 | {path: "role", name: "role", component: Role, meta: {name: "角色列表", path: "/role"}}, 32 | {path: "right", name: "right", component: Right, meta: {name: "权限列表", path: "/right"}}, 33 | {path: "userInfo", name: "userInfo", component: UserInfo, meta: {name: "个人信息", path: "/userInfo"}}, 34 | {path: "checkUser", name: "checkUser", component: CheckUser, meta: {name: "我要请假", path: "/checkUser"}}, 35 | {path: "checkAdmin", name: "checkAdmin", component: CheckAdmin, meta: {name: "请假名单", path: "/checkAdmin"}}, 36 | { 37 | path: "checkAdminHistory", 38 | name: "checkAdminHistory", 39 | component: CheckAdminHistory, 40 | meta: {name: "批假记录", path: "/checkAdminHistory"} 41 | }, 42 | { 43 | path: "checkUserHistory", 44 | name: "checkUserHistory", 45 | component: CheckUserHistory, 46 | meta: {name: "请假记录", path: "/checkUserHistory"} 47 | }, 48 | // 其他页面未定义的页面访问404 49 | { path: "*", name: 'not404', component: {Not404}, meta: {name: "页面未找到",path: "/404"}} 50 | ], 51 | }]; 52 | 53 | const router = new VueRouter({ 54 | mode: "history", //去除#号键 55 | routes, 56 | }); 57 | 58 | /** 59 | * TODO 60 | * 动态路由未完成,先用固定路由,后期完善 61 | */ 62 | // export const setRouter = () => { 63 | // const storeRights = sessionStorage.getItem("userInfo") ? JSON.parse(sessionStorage.getItem("userInfo")).rights : [] 64 | // if (storeRights) { 65 | // // console.log(storeRights) 66 | // const manageRouter = {path: "/", name: "Manage", component: Manage, redirect: "/home", children: []} 67 | // storeRights.forEach(item => { 68 | // let itemRight = { 69 | // path: item.url.replace("/", ""), 70 | // name: item.name, 71 | // component: () => import("../views/pages/" + item.pagePath + ".vue"), 72 | // meta: {name: item.name, path: item.url.replace("/", "")} 73 | // } 74 | // manageRouter.children.push(itemRight) 75 | // }) 76 | // // console.log(manageRouter) 77 | // const names = router.getRoutes().map(v => v.name); 78 | // if (!names.includes("Manage")) { 79 | // router.addRoute(manageRouter); 80 | // } 81 | // } 82 | // } 83 | 84 | // 路由守卫 85 | // let registerRouteFresh = true 86 | // router.beforeEach(async (to, from, next) => { 87 | // // 如果首次或者刷新界面,next(...to, replace: true)会循环遍历路由,如果to找不到对应的路由那么他会再执行一次beforeEach((to, from, next))直到找到对应的路由,我们的问题在于页面刷新以后异步获取数据,直接执行next()感觉路由添加了但是在next()之后执行的,所以我们没法导航到相应的界面。这里使用变量registerRouteFresh变量做记录,直到找到相应的路由以后,把值设置为false然后走else执行next(),整个流程就走完了,路由也就添加完了。 88 | // if (registerRouteFresh) { 89 | // setRouter() 90 | // next({...to, replace: true}) 91 | // registerRouteFresh = false 92 | // } else { 93 | // next() 94 | // } 95 | // }) 96 | 97 | // 解决路由重复的问题 98 | const originalPush = VueRouter.prototype.push 99 | VueRouter.prototype.push = function push(location) { 100 | return originalPush.call(this, location).catch(err => err) 101 | } 102 | export default router; 103 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | token: localStorage.getItem("token"), 9 | userInfo: JSON.parse(sessionStorage.getItem("userInfo")) 10 | }, 11 | getters: { 12 | // 相当于Java里的get 13 | getUserInfo: state => { 14 | return state.userInfo 15 | }, 16 | getToken:state=>{ 17 | return state.token 18 | } 19 | }, 20 | mutations: { 21 | // 相当于Java里的set 22 | SET_TOKEN: (state, token) => { 23 | state.token = token 24 | localStorage.setItem("token", token) 25 | }, 26 | SET_USERINFO: (state, userInfo) => { 27 | state.userInfo = userInfo 28 | sessionStorage.setItem("userInfo", JSON.stringify(userInfo)) //序列化存入浏览器会话中 29 | }, 30 | REMOVE_INFO(state) { 31 | state.token = '' 32 | state.userInfo = {} 33 | localStorage.removeItem("token") 34 | sessionStorage.removeItem("userInfo") 35 | } 36 | }, 37 | actions: {}, 38 | modules: {} 39 | }) -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* theme color */ 2 | $--color-primary: teal; 3 | 4 | /* icon font path, required */ 5 | $--font-path: '~element-ui/lib/theme-chalk/fonts'; 6 | 7 | @import "~element-ui/packages/theme-chalk/src/index"; 8 | -------------------------------------------------------------------------------- /src/template/用户信息导入模板.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WongSilver/attendance_management_vue/24d3f8d185366e62295c9a1fe5c500173ddfe948/src/template/用户信息导入模板.xlsx -------------------------------------------------------------------------------- /src/views/error-pages/Not404.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /src/views/pages/CheckAdmin.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 80 | 81 | -------------------------------------------------------------------------------- /src/views/pages/CheckAdminHistory.vue: -------------------------------------------------------------------------------- 1 | 38 | 64 | 65 | -------------------------------------------------------------------------------- /src/views/pages/CheckUser.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 100 | 101 | -------------------------------------------------------------------------------- /src/views/pages/CheckUserHistory.vue: -------------------------------------------------------------------------------- 1 | 33 | 59 | 60 | -------------------------------------------------------------------------------- /src/views/pages/Home.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 174 | 175 | -------------------------------------------------------------------------------- /src/views/pages/Login.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 154 | 155 | -------------------------------------------------------------------------------- /src/views/pages/Manage.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 50 | 55 | -------------------------------------------------------------------------------- /src/views/pages/Right.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 175 | 176 | -------------------------------------------------------------------------------- /src/views/pages/RightDataShow.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/views/pages/Role.vue: -------------------------------------------------------------------------------- 1 | 93 | 94 | 247 | 248 | -------------------------------------------------------------------------------- /src/views/pages/RoleDataShow.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/views/pages/User.vue: -------------------------------------------------------------------------------- 1 | 111 | 112 | 267 | 268 | -------------------------------------------------------------------------------- /src/views/pages/UserDataShow.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/views/pages/UserInfo.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 34 | 35 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true 4 | }) 5 | --------------------------------------------------------------------------------