Vue快速上手
1. Vue简介
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
如果你想在深入学习 Vue 之前对它有更多了解,我们制作了一个视频,带您了解其核心概念和一个示例工程。
如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看对比其它框架。
2. Vue2-3安装
官网—->安装 — Vue.js (vuejs.org)

在官网上 Node.js (nodejs.org) 中下载nodejs

使用淘宝**NPM 镜像**
大家都知道国内直接使用npm 的官方镜像是非常慢的,这里推荐使用淘宝 NPM 镜像。
$ npm install -g cnpm —registry=https://registry.npm.taobao.org
这样就可以使用cnpm 命令来安装模块了:
作者:程序员是粉色的
链接:https://www.jianshu.com/p/02b12c600c7b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
安装vue-cli
cnpm install vue-cli -g //全局安装 vue-cli

查看vue-cli是否成功,不能检查vue-cli,需要检查vue

3.Vue2-3项目创建
详细步骤到网上搜
①第一种方法:
vue create ”项目名称“ 回车
然后选择vue2或vue3
在VS Code中运行vue项目 npm run serve
②第二种方法:vue开发搭建(npm安装 + vue脚手架安装) - 咸咸海风 - 博客园 (cnblogs.com)
1、下载npm软件,URL: https://nodejs.org/en/
3、查看npm版本: npm -v
4、查看npm的本地仓库: npm list –global
5、修改npm的本地仓库:
npm config set prefix “D:\Program Files\nodejs\node_global”
npm config set cache “D:\Program Files\nodejs\node_cache”
这里修改仓库到d**盘,成功**
6、检查一下镜像站行不行命令1
输入命令:npm config get registry
7、检查一下镜像站行不行命令2, 获取vue信息(此时并非安装)
输入命令:npm info vue
8、安装更新模块,命令:npm install npm –g
9、验证vue是否安装成功, 命令: vue -V
10、初始化vue 项目
注意:vue-cli工具是内置了模板包括 webpack 和 webpack-simple,前者是比较复杂专业的项目,他的配置并不全放在根目录下的 webpack.config.js 中。
11、切换到d盘根目录,并输入: vue init webpack vue01
12、进入目录vue01, 初始化并输入命令:npm install安装依赖
13、输入命令:npm run dev
14、成功界面,提示打开地址 http://localhost:8080
注意 这里要在sell下进行安装和运行哦!!!

4.常用npm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| vue npm 安装指令汇总
1.elmentui:npm i element-ui -S
2.npm install vuex --save
3.打印插件:npm install vue-print-nb --save
4.时间转换插件:Moment:npm install moment
5.vue-cookies:npm install vuew-cookies --save
6.axios:npm install axios
7.导入导出下载:npm install js-file-download
8.css用less写的,安装:npm install --save less less-loader 1、在main.js import less from 'less' Vue.use(less) 2、<style lang="less">
9.css用sass写的,安装:npm install sass-loader --save-dev //存放在dev文件里 安装:npm install node-loader --save-dev 用法同上
10.服务器与浏览器双向通讯数据发送安装:npm install sockjs-client npm install stompjs
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 淘宝镜像使用方法 方法一:临时使用 npm --registry https://registry.npm.taobao.org install express 方法一:临时使用 npm --registry https://registry.npm.taobao.org install express 配置后可通过下面方式来验证是否成功 npm config get registry或 npm info express 方法三:通过cnpm使用 npm install -g cnpm --registry=https://registry.npm.taobao.org 执行语句后,可通过 cnpm install express 安装包了。 取消淘宝镜像,可以使用 npm config set registry https://registry.npmjs.org/
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| vue npm 使用指令汇总
# 查看 npm 的版本 $ npm -v //6.4.0 << 安装成功会返回版本号 # 查看各个命令的简单用法 $ npm -l # 查看 npm 命令列表 $ npm help # 查看 npm 的配置 $ npm config list -l $ npm set init-author-name 'my name jerry' $ set init-author-email '12345@qq.com' $ set init-author-url 'http://yourdomain.com' $ npm set init-license 'MIT' 执行了以上的修改,此时 Package.json并没有发生变化 //设置后执行init才是真正修改成功 $ npm init $ npm search <搜索词> [-g] #当前项目安装的所有模块 $npm list #列出全局安装的模块 带上[--depth 0] 不深入到包的支点 更简洁 $ npm list -g --depth 0 # 读取package.json里面的配置单安装 $ npm install //可简写成 npm i # 默认安装指定模块的最新(@latest)版本 $ npm install [<@scope>/]<name> //eg:npm install gulp # 安装指定模块的指定版本 $ npm install [<@scope>/]<name>@<version> //eg: npm install gulp@3.9.1 # 安装指定指定版本范围内的模块 $ npm install [<@scope>/]<name>@<version range> //eg: npm install vue@">=1.0.28 < 2.0.0" # 安装指定模块的指定标签 默认值为(@latest) $ npm install [<@scope>/]<name>@<tag> //eg:npm install sax@0.1.1 # 通过Github代码库地址安装 $ npm install <tarball url> //eg:npm install git://github.com/package/path.git #卸载当前项目或全局模块 $ npm uninstall <name> [-g] eg: npm uninstall gulp --save-dev npm i gulp -g 卸载后,你可以到 /node\_modules/ 目录下查看包是否还存在,或者使用以下命令查看: npm ls 查看安装的模块 #升级当前项目或全局的指定模块 $ npm update <name> [-g] //eg: npm update express npm update express -g # 引用依赖 有些包是全局安装了,在项目里面只需要引用即可。 $ npm link [<@scope>/]<pkg>[@<version>] //eg: 引用 npm link gulp gulp-ssh gulp-ftp //eg: 解除引用 npm unlink gulp # 引用模块 本人用得少没深入说了 用得上时可去翻文档例子 $ npm link (in package dir) 八、npm run 执行脚本 package.json的scripts字段,可以用于指定脚本命令,供npm直接调用。npm run会创建一个Shell,执行指定的命令。 两个命令简写,start和test属于特殊命令,可以省略run,其余的都得带上run。 npm run的参数。 如果不加任何参数,直接运行,会列出package.json里面所有可以执行的脚本命令 ---package.json文件--- { "name": "npm_test", "version": "1.0.0", "config": { "reporter": "xunit" }, "script":{ "bundle": "mkdir -p build/$npm_package_version/", //$npm_package_version 读的是外层"version"的值,同理$npm_package_name 读的是外层"name"的值 "test": "mocha test/ --reporter $npm_package_config_reporter" //$npm_package_config_reporter读的是"config"里的"reporter" } } pre-和post-两个钩子(hook) npm会先查看有没有定义prelint和postlint两个钩子,如果有的话,就会 先执行npm run pre-命令名,然后执行npm run 命令名,最后执行npm run post-命令名。 ---package.json文件--- "scripts": { "lint": "eslint --cache --ext .js --ext .jsx src", "test": "karma start --log-leve=error karma.config.js --single-run=true", "pretest": "npm run lint", "posttest": "echo 'Finished running tests'" } -------终端------- $ npm run lint //直接执行 npm run lint 结束 $ npm run test //因为有定义了两个钩子pretest、posttest。 //所以先执行 npm run pretest //然后执行 npm run test //最后执行 npm run posttest 九、npm publish 发布模块 # 未注册 申请注册一个用户 直接在https://www.npmjs.com/注册一样 $ npm adduser //执行后 填写几个问题 Username、Password、Email #已注册 $ npm login #发布 $ npm publish
|
*vue知识点
*创建vue脚手架
=>安装npm
=>安装node.js
=>安装vue-cli
npm install vue-cli -g //全局安装 vue-cli
=>创建 vue create ”项目名称“
=>运行vue项目 npm run serve
npm rebuild node-sass
=>安装常用图标 npm install font—awesome
*vue项目通用
创建vue项目选择条件引用Element-UI时所用到通用部分
=>vue.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| let proxyObj = {};
proxyObj['/'] = { ws: false, target: 'http://dongeast.top:8181', changeOrigin: true, pathWewrite: { "^/": '/', } }
proxyObj['/ws'] = { ws: true, target: 'ws://dongeast.top:8181' };
module.exports = { devServer: { host: "localhost", port: 8080, proxy: proxyObj, } }
|
=>main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import Vue from 'vue' import App from './App.vue' import ElementUI from 'element-ui'; import router from './router' import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false Vue.use(ElementUI);
new Vue({ router, render: h => h(App), }).$mount('#app')
|
=>router.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import Vue from 'vue' import VueRouter from 'vue-router' import Login from '../views/Login'
Vue.use(VueRouter)
const routes = [{ path:'/', name:'Login', component:Login, children: [
{ path: '/adminInfo', name: '个人中心', component: AdminInfo }] }, ..., ..., ..., ] const router = new VueRouter({ routes }) const originalPush = VueRouter.prototype.push; VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch((err) => err); }; export default router
|
=>api.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| import axios from 'axios'; import { Loading, Message } from 'element-ui' import router from '../router';
axios.interceptors.request.use(success => { if (window.sessionStorage.getItem('tokenStr')) { success.headers['Authorization'] = window.sessionStorage.getItem('tokenStr'); } return success; }, error => { console.log(error); })
axios.interceptors.response.use(success=>{ if(success.status && success.status == 200){ if(success.data.code == 500 || success.data.code == 401 || success.data.code == 403){ Message.error({message:success.data.message}); return; } if(success.data.message){ Message.success({message:success.data.message}) } } return success.data; },error =>{ if(error.response.code == 504 || error.response.code == 404){ Message.error({Message:'服务器错误!'}); }else if(error.response.code == 403){ Message.error({message:'权限不足,请联系管理员!'}) }else if(error.response.code == 401){ Message.error({message:'尚未登录,请登录!'}) router.replace('/'); }else{ if(error.response.data.message){ Message.error({message:error.response.data.message}) }else{ Message.error({message:'未知错误!'}); } } return; });
let base = '';
export const postRequest = (url,params)=>{ return axios({ method:'post', url:`${base}${url}`, data:params }) }
export const putRequest = (url, params) => { return axios({ method: 'put', url: `${base}${url}`, data: params }) }
export const getRequest = (url, params) => { return axios({ method: 'get', url: `${base}${url}`, data: params, }) }
export const deleteRequest = (url, params) => { return axios({ method: 'delete', url: `${base}${url}`, params, }) }
|
=>App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template> <div id="app"> <router-view /> <!-- 默认跳转 --> </div> </template>
<script> export default { name: 'App'
} </script> <style>
</style>
|
*选择导航器
menu.js部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import { getRequest } from "./api";
export const initMenu = (router, store) => { if (store.state.routes.length > 0) { return; } getRequest("/system/cfg/menu").then(data => { if (data) { let fmtRoutes = formatRoutes(data); router.addRoutes(fmtRoutes); store.commit('initRoutes', fmtRoutes); } }) }
export const formatRoutes = (routes) => { let fmtRoutes = []; routes.forEach(router => { let { path, component, name, iconCls, children } = router; if (children && children instanceof Array) { children = formatRoutes(children); } let fmRouter = { path: path, name: name, iconCls: iconCls, children: children, component(resolve) { if (component.startsWith('Home')) { require(['../views/' + component + '.vue'], resolve); } else if (component.startsWith('Emp')) { require(['../views/emp/' + component + '.vue'], resolve); } else if (component.startsWith('Per')) { require(['../views/per/' + component + '.vue'], resolve); } else if (component.startsWith('Sal')) { require(['../views/sal/' + component + '.vue'], resolve); } else if (component.startsWith('Sta')) { require(['../views/sta/' + component + '.vue'], resolve); } else if (component.startsWith('Sys')) { require(['../views/sys/' + component + '.vue'], resolve); } } } fmtRoutes.push(fmRouter) }); return fmtRoutes; }
|
vue部分
①不定死(推荐)(首页左侧)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <el-container> <el-aside width="200px"> <el-menu router unique-opened><!-- 默认不展开列表 --> <el-submenu :index="index + ''" v-for="(item, index) in routes" :key="index"> <template slot="title"> <i :class="item.iconCls" style="color: skyblue; margin-right: 5px"></i> <span>{{ item.name }}</span> </template> <el-menu-item :index="children.path" v-for="(children, indexj) in item.children" :key="indexj"> {{ children.name }} </el-menu-item> </el-submenu> </el-menu> </el-aside> <el-main> <el-breadcrumb v-if="this.$router.currentRoute.path != '/home'"> <el-breadcrumb-item :to="{path:'/home'}">首页</el-breadcrumb-item> <el-breadcrumb-item>{{this.$router.currentRoute.name}}</el-breadcrumb-item> </el-breadcrumb> <div class="homeWelcome" v-if="this.$router.currentRoute.path == '/home'"> 欢迎来到云E办系统! </div> <router-view class="homeRouterView"></router-view> </el-main> </el-container> export default { name:'Home', computed:{ routes(){ return this.$store.state.routes; } } }
|
②定死(不推荐)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <el-container> <el-aside width="200px"> <el-menu @select="menuClick"> <!-- 菜单点击事件 --> <el-submenu index="1"> <template slot="title"><i class="el-icon-location"></i>导航一</template> <el-menu-item-group> <el-menu-item index="/adminInfo">选项1</el-menu-item> <el-menu-item index="1-2">选项2</el-menu-item> </el-menu-item-group> </el-submenu> </el-menu> </el-aside> <el-main> <router-view /> </el-main> </el-container> methods:{ menuClick(index){ this.$router.push(index) } }
|
*图标
=>安装 npm install font—awesome 或 npm install font-awesome —save
在main.js添加
1
| import 'font-awesome/css/font-awesome.css'
|
在vue中添加
1 2 3 4 5
| <template slot="title"> <i :class="item.iconCls" style="color: skyblue; margin-right: 5px"></i> <!-- :class="item.iconCls"绑定数据库里的图标 --> <span>{{ item.name }}</span> </template>
|
*登录功能
*规则问题:输入框提示为空
1 2 3 4 5 6 7 8 9 10
| <el-form :rules="rules" v-loading="loading" ref="loginForm" :model="loginForm" class="loginContainer"> 出现红色提示为空 </el-form> data(){ rules:{ username:[{required:true,message:'请输入用户名',trigger:'blur'}], password:[{required:true,message:'请输入密码',trigger:'blur'}], code:[{required:true,message:'请输入验证码',trigger:'blur'}], } }
|
*获取用户登录信息
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| router.beforeEach((to, from, next) => { if (window.sessionStorage.getItem('tokenStr')) { initMenu(router, store); if (!window.sessionStorage.getItem('user')) { return getRequest('/admin/info').then(resp => { if (resp) { window.sessionStorage.setItem('user', JSON.stringify(resp)); store.commit("INIT_ADMIN", resp); next(); } }); } next(); } else { if (to.path == '/') { next(); } else { next('/?redirect=' + to.path) } } })
|
vue部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <el-header class="homeHeader"> <div class="title">云E办</div> <div> <el-dropdown class="userInfo" @command="commandHandler"> <span class="el-dropdown-link"> {{user.name}}<i><img :src="user.userFace"></i> </span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item command="userinfo">个人中心</el-dropdown-item> <el-dropdown-item command="setting">设置</el-dropdown-item> <el-dropdown-item command="logout">注销登录</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> </el-header> data(){ return{ user:JSON.parse(window.sessionStorage.getItem('user')) } }, computed:{ routes(){ return this.$store.state.routes; } }, methods:{ commandHandler(command){ if(command == 'logout'){ this.$confirm('此操作将注销登录, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { //注销登录 this.postRequest('/logout'); window.sessionStorage.removeItem('tokenStr'); window.sessionStorage.removeItem('user'); //清空菜单 this.$store.commit('initRoutes',[]); //跳转登录页面 this.$router.replace('/') }).catch(() => { this.$message({ type: 'info', message: '已取消操作' }); }); } } }
|
*主界面
*面包屑
1 2 3 4 5 6 7 8 9
| <el-breadcrumb v-if="this.$router.currentRoute.path != '/home'"><!-- 判断书否为首页,如果是则不展示面包屑 --> <el-breadcrumb-item :to="{path:'/home'}">首页</el-breadcrumb-item> <!-- 当前路由名称 --> <el-breadcrumb-item>{{this.$router.currentRoute.name}}</el-breadcrumb-item> </el-breadcrumb> <div class="homeWelcome" v-if="this.$router.currentRoute.path == '/home'"> 欢迎来到云E办系统! </div> <router-view class="homeRouterView"></router-view>
|
*login.vue
1 2 3 4 5 6 7 8 9 10 11
| this.postRequest('/login',this.loginForm).then(resp=>{ if(resp){ this.loading = false; //存储用户token const tokenStr = resp.obj.tokenHead + resp.obj.token; window.sessionStorage.setItem('tokenStr',tokenStr); //页面跳转首页 let path = this.$router.replace('/home'); this.$$router.replace((path=='/'||path==undefined)?'/home': path) } })
|
*选择框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <el-select size="small" v-model="jl.titleLevel" placeholder="职称等级" style="margin-left: 10px; margin-right: 10px"> <el-option v-for="item in titleLevels" :key="item" :label="item" :value="item"> </el-option> data() { return { jl: { name: "", titleLevel: "", }, titleLevels: ["正高级", "副高级", "中级", "初级", "员级"], }, }
|
*组件
1 2 3 4 5
| @keydown.enter.native='事件' 键盘事件 icon="图标" 添加图标 placeholder="请输入中文名" 提示内容 size="mini" 变小输入框 :title="数据" 动态绑定标题
|
1 2 3
| show-checkbox 默认选中子节点 :key="index" key绑定的是index索引值,索引变化,key也会改变 :props=" " 组件数据的一个字段,期望从父组件传下来
|
一、展示信息-PC端
1. 云E办
1.1 表格页面编辑

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| <template> <div> <el-table :data="emps" border stripe> <el-table-column type="selection" align="left" width="55"> </el-table-column> <el-table-column prop="name" label="姓名" align="left" width="120" fixed> </el-table-column> <el-table-column prop="workID" label="工号" align="left" width="120"> </el-table-column> <el-table-column prop="email" label="邮箱地址" align="left" width="200"> </el-table-column> <el-table-column prop="phone" label="电话号码" align="left" width="120"> </el-table-column> <el-table-column label="工资账套" align="center"> <template slot-scope="scope"> <el-tooltip placement="right"> <div slot="content"> <table> <tr> <td>基本工资</td> <td>{{ scope.row.s.basicSalary }}</td> </tr> <tr> <td>交通补助</td> <td>{{ scope.row.s.trafficSalary }}</td> </tr> <tr> <td>午餐补助</td> <td>{{ scope.row.s.lunchSalary }}</td> </tr> <tr> <td>奖金</td> <td>{{ scope.row.s.bonus }}</td> </tr> <tr> <td>养老金比率</td> <td>{{ scope.row.s.pensionPer }}</td> </tr> <tr> <td>养老金基数</td> <td>{{ scope.row.s.pensionBase }}</td> </tr> <tr> <td>医疗保险比率</td> <td>{{ scope.row.s.medicalPer }}</td> </tr> <tr> <td>医疗保险金基数</td> <td>{{ scope.row.s.medicalBase }}</td> </tr> <tr> <td>公积金比率</td> <td>{{ scope.row.s.accumulationFundPer }}</td> </tr> <tr> <td>公积金基数</td> <td>{{ scope.row.s.accumulationFundBase }}</td> </tr> </table> </div> <el-tag type="success" v-if="scope.row.s.name"> {{scope.row.s.name}} </el-tag> <el-tag v-else type="primary">暂未设置</el-tag> </el-tooltip> </template> </el-table-column> <el-table-column label="操作" align="center"> <template slot-scope="scope"> <el-popover placement="left" title="编辑工资账套" @show="showPop(scope.row.s)" @hide="hide(scope.row)" width="200" trigger="click"> <div> <el-select v-model="currentSalary" placeholder="请选择"> <el-option v-for="item in salaries" :key="item.id" :label="item.name" :value="item.id"> </el-option> </el-select> </div> <el-button slot="reference" type="danger"> 修改工资账套</el-button> </el-popover> </template> </el-table-column> </el-table> <div style="display: flex; justify-content: flex-end; margin-top: 10px"> <el-pagination background @current-change="currentChange" @size-change="sizeChange" layout="prev, pager, next, jumper, ->, total, slot" :total="total" ></el-pagination> </div> </div> </template> <script> export default { name: "SalSobCfg", data() { return { currentSalary: null, salaries: [], emps: [], currentPage: 1, size: 10, total: 0, }; }, mounted() { this.initEmps(); this.initSalaries(); }, methods: { hide(data) { /* 如果未修改过不会更新,则修改会更新 */ if (this.currentSalary && this.currentSalary != data.s.id) { this.putRequest( "/salary-adjust/update?eid=" + data.id + "&eSid=" + this.currentSalary ).then((resp) => { if (resp) { this.intEmps(); } }); } }, showPop(data) { /* 点击编辑时会一直显示一个值,值为空时也是某给值,bug存在,因此做出判断 */ if (data) { this.currentSalary = data.id; } else { this.currentSalary = null; } }, initSalaries() { this.getRequest("/salary-adjust/get-All").then((resp) => { if (resp) { this.salaries = resp; } }); }, currentChange(page) { this.currentPage = page; this.initEmps(); }, sizeChange(size) { this.size = size; this.initEmps(); }, initEmps() { this.getRequest( "/salary-adjust/list?currentPage=" + this.currentPage + "&size=" + this.size ).then((resp) => { if (resp) { this.emps = resp.date; this.total = resp.total; console.log(resp); } }); }, }, }; </script>
|
二、激活信息-PC端
1.云E办
1.1 卡片用户角色
用户角色用列表的方式编辑激活权限

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| <div> 用户角色: <el-tag style="margin-right: 10px" type="success" v-for="(role, indexj) in admin.roles" :key="indexj" >{{ role.nameZh }} </el-tag> <el-popover placement="right" title="角色列表" width="200" @show="showPop(admin)" @hide="hidePop(admin)" trigger="click"> <el-select v-model="selectRoles" multiple placeholder="请选择"> <el-option v-for="(r, index) in allRoles" :key="index" :label="r.nameZh" :value="r.id"> </el-option> </el-select> <el-button slot="reference" type="text" icon="el-icon-more"> </el-button> </el-popover> </div> data() { return { admins: [], keywords: "", allRoles: [], selectRoles: [], }; }, mounted() { this.initAdmins(); }, methods: { hidePop(admin) { let roles = []; Object.assign(roles, admin.roles); let flag = false; if (roles.length != this.selectRoles.length) { flag = true; } else { for (let i = 0; i < roles.length; i++) { let role = roles[i]; for (let j = 0; j < this.selectRoles.length; j++) { let sr = this.selectRoles[j]; if (role.id == sr) { roles.splice(i, 1); i--; break; } } } if (roles.length != 0) { flag = true; } } if (flag) { let url = "/admin/updaterole?adminId=" + admin.id; this.selectRoles.forEach((rs) => { url += "&rids=" + rs; }); this.putRequest(url).then((resp) => { if (resp) { this.initAdmins(); } }); } }, showPop(admin) { this.initAllRoles(); let roles = admin.roles; this.selectRoles = []; roles.forEach((r) => { this.selectRoles.push(r.id); }); }, initAllRoles() { this.getRequest("/admin/roles").then((resp) => { if (resp) { this.allRoles = resp; } }); }, } }
|
三、搜索信息-PC端
1. 云E办
1.1 自动提示搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <el-input placeholder="输入需要搜索的内容" prefix-icon="el-icon-search" v-model="filterText" > </el-input> <el-tree style="margin-top: 20px" :data="deps" :props="defaultProps" :filter-node-method="filterNode" :expand-on-click-node="false" ref="tree" > </el-tree> data() { return { filterText: "", deps: [], defaultProps: { children: "children", label: "name", }, dialogVisible: false, dep: { name: "", parentId: "", }, pname: "", }; }, mounted() { this.initDeps(); }, watch: { filterText(val) { this.$refs.tree.filter(val); }, }, methods: { initDeps() { this.getRequest("/system/basic/department/list").then((resp) => { if (resp) { this.deps = resp; } }); }, filterNode(value, data) { if (!value) return true; return data.name.indexOf(value) !== -1; }, }
|
1.2 用户名搜索

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 搜索框
<div style="display: flex; justify-content: center; margin-top: 20px"> <el-input placeholder="通过用户名搜索用户" prefix-icon="el-icon-search" style="width: 400px; margin-right: 20px" v-model="keywords" @keydown.enter.native="doSearch"></el-input> <el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button> </div> data() { return { admins: [], //在接口文档中keywords是参数名称 keywords: "", }, mounted() { this.initAdmins(); }, methods: { doSearch() { this.initAdmins(); }, initAdmins() { this.getRequest("/admin/list/?keywords=" + this.keywords).then((resp) => { if (resp) { this.admins = resp; } }); }, }
|
1.2 高级用户名搜索

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
| <div> <div style="display: flex; justify-content: space-between"> <div> <el-input prefix-icon="el-icon-search" placeholder="请输入员工姓名进行搜索..." v-model="empName" @keydown.enter.native="initEmps" clearable @clear="initEmps" style="width: 300px"> </el-input> <el-button style="margin-left: 10px" icon="el-icon-search" type="primary" @click="initEmps">搜索</el-button> <el-button type="primary" @click="showSearch = !showSearch"> <i :class=" showSearch ? 'fa fa-angle-double-up' : 'fa fa-angle-double-down'" aria-hidden="true"></i>高级搜索 </el-button> </div> </div> <transition name="slide-fade"> <div v-show="showSearch" style=" border: 1px solid #409eff; border-radius: 5px; box-sizing: border-box; padding: 7px; margin: 15px 0px; " > <el-row> <el-col :span="5"> 政治面貌: <el-select v-model="searchValue.politicId" size="mini" placeholder="政治面貌" style="width: 130px" > <el-option v-for="item in politicsstatus" :key="item.id" :label="item.name" :value="item.id" > </el-option> </el-select> </el-col> <el-col :span="4"> 民族: <el-select v-model="searchValue.nationId" size="mini" placeholder="民族" style="width: 130px" > <el-option v-for="item in nations" :key="item.id" :label="item.name" :value="item.id" > </el-option> </el-select> </el-col> <el-col :span="4"> 职位: <el-select v-model="searchValue.posId" size="mini" placeholder="职位" style="width: 130px" > <el-option v-for="item in positions" :key="item.id" :label="item.name" :value="item.id" > </el-option> </el-select> </el-col> <el-col :span="4"> 职称: <el-select v-model="searchValue.jobLevelId" size="mini" placeholder="职称" style="width: 130px" > <el-option v-for="item in joblevels" :key="item.id" :label="item.name" :value="item.id" > </el-option> </el-select> </el-col> <el-col :span="7"> 聘用形式: <el-radio-group v-model="searchValue.engageForm"> <el-radio label="劳动合同">劳动合同</el-radio> <el-radio label="劳务合同">劳务合同</el-radio> </el-radio-group> </el-col> </el-row> <el-row style="margin-top: 10px"> <el-col :span="5"> 所属部门: <el-popover placement="bottom" title="请选择部门" width="200" trigger="manual" v-model="visible2" > <el-tree :data="allDeps" :props="defaultProps" default-expand-all @node-click="searchhandleNodeClick" ></el-tree> <div slot="reference" style=" width: 130px; height: 24px; display: inline-flex; border: 1px solid #dedede; border-radius: 5px; cursor: pointer; align-items: center; font-size: 13px; padding-left: 8px; box-sizing: border-box; " @click="showDepView2" > {{ inputDepName }} </div> </el-popover> </el-col> <el-col :span="10"> 入职日期: <el-date-picker size="mini" v-model="searchValue.beginDateScope" type="daterange" value-format="yyy-MM-dd" unlink-panels range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" > </el-date-picker> </el-col> <el-col :span="5" :offset="4"> <el-button size="mini" icon="el-icon-search" type="primary" @click="initEmps('advanced')" >搜索</el-button > <el-button size="mini">取消</el-button> </el-col> </el-row> </div> </transition> </div> data() { return { showSearch: false, emps: [], loading: false, total: 0, currentPage: 1, size: 10, empName: "", dialogVisible: false, emp: { id: null, name: "", gender: "", birthday: "", idCard: "", wedlock: "", nationId: null, nativePlace: "", politicId: null, email: "", phone: "", address: "", departmentId: null, jobLevelId: null, posId: null, engageForm: "", tiptopDegree: "", specialty: "", school: "", beginDate: "", workState: "在职", workID: "", contractTerm: 9.31, conversionTime: "", notWorkDate: null, beginContract: "", endContract: "", workAge: null, salaryId: 2, nation: { id: null, name: "", }, politicsStatus: { id: null, name: "", }, department: { id: null, name: "", parentId: null, depPath: null, enabled: null, isParent: null, children: null, result: null, }, joblevel: { id: null, name: "", titleLevel: null, createDate: null, enabled: null, }, position: { id: null, name: "", createDate: null, enabled: null, }, s: null, }, }, mounted() { this.initEmps(); }, methods: { searchhandleNodeClick(data) { this.inputDepName = data.name; this.searchValue.departmentId = data.id; this.visible2 = !this.visible2; }, showDepView2() { this.visible2 = !this.visible2; }, handleNodeClick(data) { this.inputDepName = data.name; this.emp.departmentId = data.id; this.visible = !this.visible; }, initEmps(type) { this.loading = true; console.log(this.searchValue.beginDateScope); let url ="/employee/basic/list?currentPage=" +this.currentPage +"&size=" +this.size; if (type && type == "advanced") { if (this.searchValue.politicId) { url += "&politicId=" + this.searchValue.politicId; } if (this.searchValue.nationId) { url += "&nationId=" + this.searchValue.nationId; } if (this.searchValue.posId) { url += "&posId=" + this.searchValue.posId; } if (this.searchValue.jobLevelId) { url += "&jobLevelId=" + this.searchValue.jobLevelId; } if (this.searchValue.engageForm) { url += "&engageForm=" + this.searchValue.jobLevelId; } if (this.searchValue.departmentId) { url += "&departmentId=" + this.searchValue.departmentId; } if (this.searchValue.beginDateScope) { url +="&startDate=" +this.searchValue.beginDateScope[0] +"&endDate=" + this.searchValue.beginDateScope[1]; } if (this.empName) { url += "&name=" + this.empName; } } this.getRequest(url).then((resp) => { this.loading = false; if (resp) { this.emps = resp.date; this.total = resp.total; } }); }, }, } <style> .slide-fade-enter-active { transition: all 0.3s ease; } .slide-fade-leave-active { transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1); } .slide-fade-enter, .slide-fade-leave-to /* .slide-fade-leave-active for below version 2.1.8 */ { transform: translateX(10px); opacity: 0; } </style>
|
四、添加信息-PC端
1. 云E办
1.1 添加工资账套

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| <div style="display: flex; justify-content: space-between"> <el-button type="primary" icon="el-icon-plus" @click="showAddSalary">添加工资账套</el-button> <el-button type="success" icon="el-icon-refresh" @click="initSalaries"></el-button> </div> <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="30%"> <div style="display: flex; justify-content: space-around; align-item: center"> <el-steps direction="vertical" :active="activeItemIndex"> <el-step :title="itemName" v-for="(itemName, index) in salaryItemName" :key="index"> </el-step> </el-steps> <el-input v-model="salary[title]" :placeholder="'请输入' + salaryItemName[index]" v-for="(value, title, index) in salary" :key="index" v-show="activeItemIndex == index" style="width: 200px"> </el-input> </div> <span slot="footer" class="dialog-footer"> <el-button @click="preStep"> {{activeItemIndex == 10 ? "取消" : "上一步"}}</el-button> <el-button type="primary" @click="nextStep"> {{ activeItemIndex == 10 ? "确认" : "下一步"}}</el-button> </span> </el-dialog> </div> name: "SalSob", data() { return { dialogTitle: "", dialogVisible: false, salaries: [], /*注意是0,1的直接跳过第一个输入*/ activeItemIndex: 0, salaryItemName: [ "账套名称", "基本工资", "交通补助", "午餐补助", "奖金", "养老金比率", "养老金基数", "医疗保险比率", "医疗保险基数", "公积金比率", "公积金基数", ], salary: { name: "", basicSalary: 0, trafficSalary: 0, lunchSalary: 0, bonus: 0, pensionPer: 0, pensionBase: 0, medicalPer: 0, medicalBase: 0, accumulationFundPer: 0, accumulationFundBase: 0, }, }; }, mounted() { this.initSalaries(); }, methods: { preStep() { if (this.activeItemIndex == 0) { return; } else if (this.activeItemIndex == 10) { this.dialogVisible == fasle; return; } this.activeItemIndex--; }, nextStep() { if (this.activeItemIndex == 10) { if (this.salary.id) { this.putRequest("/salary/sob/update", this.salary).then((resp) => { if (resp) { this.initSalaries(); this.dialogVisible = false; } }); } else { this.postRequest("/salary/sob/add", this.salary).then((resp) => { if (resp) { this.initSalaries(); this.dialogVisible = false; } }); } return; } this.activeItemIndex++; }, initSalaries() { this.getRequest("/salary/sob/get-All").then((resp) => { if (resp) { this.salaries = resp; } }); }, showAddSalary() { this.dialogTitle = "添加工资账套"; this.activeItemIndex = 0; this.dialogVisible = true; this.salary = { name: "", basicSalary: 0, trafficSalary: 0, lunchSalary: 0, bonus: 0, pensionPer: 0, pensionBase: 0, medicalPer: 0, medicalBase: 0, accumulationFundPer: 0, accumulationFundBase: 0, }; }, },
|
五、编辑信息-PC端
1. 云E办
1.1 修改个人信息

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| <el-dialog title="编辑用户信息" :visible.sync="dialogVisible" width="30%"> <div> <table> <tr> <td>用户昵称:</td> <td><el-input v-model="admin2.name"></el-input></td> </tr> <tr> <td>电话号码:</td> <td><el-input v-model="admin2.telephone"></el-input></td> </tr> <tr> <td>手机号码:</td> <td><el-input v-model="admin2.phone"></el-input></td> </tr> <tr> <td>居住地址:</td> <td><el-input v-model="admin2.address"></el-input></td> </tr> </table> </div> <span slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false">取 消</el-button> <el-button type="primary" @click="updateAdmin">确 定</el-button> </span> </el-dialog> data() { return { header: { Authorization: window.sessionStorage.getItem("tokenStr"), }, admin: null, dialogVisible: false, admin2: null, dialogVisible2: false, ruleForm: { pass: "", checkPass: "", oldPass: "", }, rules: { pass: [{ validator: validatePass, trigger: "blur" }], checkPass: [{ validator: validatePass2, trigger: "blur" }], oldPass: [{ validator: validatePass, trigger: "blur" }], }, }; }, mounted() { this.initAdmins(); }, methods: { initAdmins() { this.getRequest("/admin/info").then((resp) => { if (resp) { this.admin = resp; /* 防止编辑时界面也会跟着编辑,是个bug */ this.admin2 = Object.assign({}, this.admin); window.sessionStorage.setItem("user", resp); this.$store.commit("INIT_ADMIN", resp); } }); }, /* 编辑是更新数据 */ updateAdmin() { this.putRequest("/admin-info", this.admin2).then((resp) => { if (resp) { this.dialogVisible = false; this.initAdmins(); } }); }, showUpdate() { this.dialogVisible = true; }, }
|
在store中index.js中加全局更新
1 2 3 4 5 6 7 8
| mutations: { INIT_ADMINS(state, data) { state.admins = data; }, INIT_ADMIN(state, admin) { state.currentAdmin = admin } },
|
在main.js文件中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| router.beforeEach((to, from, next) => { if (window.sessionStorage.getItem('tokenStr')) { initMenu(router, store); if (!window.sessionStorage.getItem('user')) { return getRequest('/admin/info').then(resp => { if (resp) { window.sessionStorage.setItem('user', JSON.stringify(resp));
store.commit("INIT_ADMIN", resp); next(); } }); } next(); } else { if (to.path == '/') { next(); } else { next('/?redirect=' + to.path) } } })
|
1.2 修改密码

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| <el-button type="danger" @click="showUpdatePassword">修改密码</el-button> <el-dialog title="更新密码" :visible.sync="dialogVisible2" width="30%"> <div> <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> <el-form-item label="旧密码" prop="oldPass"> <el-input v-model="ruleForm.oldPass"></el-input> </el-form-item> <el-form-item label="密码" prop="pass"> <el-input type="password" v-model="ruleForm.pass" autocomplete="off" ></el-input> </el-form-item> <el-form-item label="确认密码" prop="checkPass"> <el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"> </el-input> </el-form-item> data() { var validatePass = (rule, value, callback) => { if (value === "") { callback(new Error("请输入密码")); } else { if (this.ruleForm.checkPass !== "") { this.$refs.ruleForm.validateField("checkPass"); } callback(); } }; var validatePass2 = (rule, value, callback) => { if (value === "") { callback(new Error("请再次输入密码")); } else if (value !== this.ruleForm.pass) { callback(new Error("两次输入密码不一致!")); } else { callback(); } }; return { header: { Authorization: window.sessionStorage.getItem("tokenStr"), }, admin: null, dialogVisible: false, admin2: null, dialogVisible2: false, ruleForm: { pass: "", checkPass: "", oldPass: "", }, rules: { pass: [{ validator: validatePass, trigger: "blur" }], checkPass: [{ validator: validatePass2, trigger: "blur" }], oldPass: [{ validator: validatePass, trigger: "blur" }], }, }; }, mounted() { this.initAdmins(); }, methods: { showUpdatePassword() { this.dialogVisible2 = true; }, submitForm(formName) { /* 获取当前用户信息 */ this.$refs[formName].validate((valid) => { if (valid) { this.ruleForm.adminId = this.admin.id; this.putRequest("/admin-pass", this.ruleForm).then((resp) => { if (resp) { /* 密码更新成功退出登录 */ this.postRequest("/logout"); window.sessionStorage.removeItem("user"); window.sessionStorage.removeItem("tokenStr"); this.$store.commit("initRoutes", []); this.$router.replace("/"); } }); } else { console.log("error submit!!"); return false; } }); }, resetForm(formName) { this.$refs[formName].resetFields(); }, }
|
1.3 编辑个人头像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <div style="display: flex; justify-content: center"> <el-upload action="/admin/userface" :headers="header" :data="admin" :on-success="onSuccess" :show-file-list="false"> <img title="点击修改用户头像" :src="admin.userFace" style="width: 100px; height: 100px; border-radius: 50px" alt="" /> </el-upload> </div> data() { return { header: { Authorization: window.sessionStorage.getItem("tokenStr"), }, }, mounted() { this.initAdmins(); }, methods: { initAdmins() { this.getRequest("/admin/info").then((resp) => { if (resp) { this.admin = resp; /* 防止编辑时界面也会跟着编辑,是个bug */ this.admin2 = Object.assign({}, this.admin); window.sessionStorage.setItem("user", resp); this.$store.commit("INIT_ADMIN", resp); } }); }, onSuccess() { this.initAdmins(); }, }
|
1.4 编辑工资职位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <!-- //表格--stripe border斑马纹和边框 --> <div> <el-table size="small" stripe border :data="positions" style="width: 100%" class="posManaMain" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55"> </el-table-column> <el-table-column prop="id" label="编号" width="180"> </el-table-column> <el-table-column prop="name" label="职位" width="120"> </el-table-column> <el-table-column prop="createDate" label="创建时间" width="200"> </el-table-column> <el-table-column prop="enabled" label="是否启用" width="120"> </el-table-column> <el-table-column label="操作" width="150"> <template slot-scope="scope"> <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)"> 删除</el-button> </template> </el-table-column> </el-table> </div> <!-- //编辑表格 --> <el-dialog title="编辑职位" :visible.sync="dialogVisible" width="30%"> <div> <el-tag>职位名称</el-tag> <!-- //编辑时会显示信息名称 --> <el-input v-model="updatePos.name" size="small" class="updataPosInput"></el-input> </div> <span slot="footer" class="dialog-footer"> <el-button size="small" @click="dialogVisible = false">取 消</el-button> <el-button size="small" type="primary" @click="doupdate">确 定</el-button> </span> data() { return { positions: [], dialogVisible: false, updatePos: { mounted() { //调用信息接口initPositions,下面有详细方法 this.initPositions(); }, methods: { handleSelectionChange(val) { this.multipleSelection = val; }, doupdate() { this.putRequest("/system/basic/position/update", this.updatePos).then( (resp) => { if (resp) { this.initPositions(); this.dialogVisible = false; } } ); }, handleEdit(index, data) { //处理bug->编辑的同时页面的内容也跟着编辑 Object.assign(this.updatePos, data); this.dialogVisible = true; }, //前后端调用信息接口initPositions initPositions() { this.getRequest("/system/basic/position/list").then((resp) => { if (resp) { this.positions = resp; } }); }, }
|
1.5 编辑编号账套


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| <div style="margin-top: 20px"> <el-table :data="salaries" border stripe> <el-table-column type="selection" width="40"> </el-table-column> <el-table-column prop="name" label="账套名称" width="120"> </el-table-column> <el-table-column prop="basicSalary" label="基本工资" width="70"> </el-table-column> <el-table-column prop="trafficSalary" label="交通补助" width="70"> </el-table-column> <el-table-column prop="lunchSalary" label="午餐补助" width="70"> </el-table-column> <el-table-column prop="bonus" label="奖金" width="70"> </el-table-column> <el-table-column prop="createDate" label="启用时间" width="100"> </el-table-column> <el-table-column label="养老金" align="center"> <el-table-column prop="pensionPer" label="比率" width="70"> </el-table-column> <el-table-column prop="pensionBase" label="基数" width="70"> </el-table-column> </el-table-column> <el-table-column label="医疗保险" align="center"> <el-table-column prop="medicalPer" label="比率" width="70" ></el-table-column> <el-table-column prop="medicalBase" label="基数" width="70" ></el-table-column> </el-table-column> <el-table-column label="公积金" align="center"> <el-table-column prop="accumulationFundPer" label="比率" width="70" ></el-table-column> <el-table-column prop="accumulationFundBase" label="基数" width="70" ></el-table-column> </el-table-column> <el-table-column label="操作"> <template slot-scope="scope"> <el-button type="primary" @click="showEditSalary(scope.row)">编辑</el-button> <el-button type="danger" @click="deleteSalary(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> name: "SalSob", data() { return { dialogTitle: "", dialogVisible: false, salaries: [], activeItemIndex: 0, }, mounted() { this.initSalaries(); }, methods: { deleteSalary(data) { this.$confirm("此操作将永久删除该" + data.name + ", 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }) .then(() => { this.deleteRequest("/salary/sob/delete/" + data.id).then((resp) => { if (resp) { this.initSalaries(); } }); }) .catch(() => { this.$message({ type: "info", message: "已取消删除", }); }); }, showEditSalary(data) { this.dialogTitle = "编辑工资账套"; this.activeItemIndex = 0; this.dialogVisible = true; this.salary.id = data.id; this.salary.name = data.name; this.salary.basicSalary = data.basicSalary; this.salary.trafficSalary = data.trafficSalary; this.salary.lunchSalary = data.lunchSalary; this.salary.bonus = data.bonus; this.salary.pensionPer = data.pensionPer; this.salary.pensionBase = data.pensionBase; this.salary.medicalPer = data.medicalPer; this.salary.medicalBase = data.medicalBase; this.salary.accumulationFundPer = data.accumulationFundPer; this.salary.accumulationFundBase = data.accumulationFundBase; },
|
六、删除信息-PC端
1. 云E办
1.1 弹出删除
卡片弹出删除信息

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <el-table-column label="操作"> <template slot-scope="scope"> <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button> </template> </el-table-column> mounted(){ this.initPositions(); }, methods:{ handleDelete(index,data){ this.$confirm('此操作将永久删除['+data.name+']职位, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.deleteRequest('/system/basic/position/delete',{id:data.id}).then(resp=>{ if(resp){ this.initPositions(); } }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }); }); }, initPositions(){ this.getRequest('/system/basic/position/list').then(resp=>{ if(resp){ this.positions = resp; } }) }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| data() { return { admins: [], keywords: "", allRoles: [], selectRoles: [], }; }, mounted() { this.initAdmins(); }, methods: { deleteAdmin(admin) { this.$confirm( "此操作将永久删除" + admin.name + "用户, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", } ) .then(() => { this.deleteRequest("/admin/delete" + admin.id).then((resp) => { if (resp) { this.initAdmins(); } }); }) .catch(() => { this.$message({ type: "info", message: "已取消删除", }); }); }, }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <div style="margin-top: 20px"> <el-table-column label="操作"> <template slot-scope="scope"> <el-button type="primary" @click="showEditSalary(scope.row)">编辑</el-button> <el-button type="danger" @click="deleteSalary(scope.row)">删除</el-button> </template> </el-table-column> </el-table> </div> data() { return { dialogTitle: "", dialogVisible: false, salaries: [], activeItemIndex: 0, }, mounted() { this.initSalaries(); }, methods: { deleteSalary(data) { this.$confirm("此操作将永久删除该" + data.name + ", 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }) .then(() => { this.deleteRequest("/salary/sob/delete/" + data.id).then((resp) => { if (resp) { this.initSalaries(); } }); }) .catch(() => { this.$message({ type: "info", message: "已取消删除", }); }); }, }
|
1.2 批量删除

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <!-- //删除表格--> <el-button type="danger" style="margin-top=10px" :disabled="this.multipleSelection.length == 0" @click="deleteMany">批量删除</el-button> data() { return { //<!-- //批量删除表格数组--> multipleSelection: [], }; }, mounted() { //调用信息接口initPositions,下面有详细方法 this.initPositions(); }, methods: { //<!-- //批量删除表格--> deleteMany() { this.$confirm( "批量删除[" + this.multipleSelection.length + "]条职位, 是否继续?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", } ) .then(() => { let ids = "?"; this.multipleSelection.forEach((item) => { ids += "ids=" + item.id + "&"; }); this.deleteRequest("/system/basic/position/deletes" + ids).then((res) => { if (res) { this.initPositions(); } } ); }) .catch(() => { this.$message({ type: "info", message: "已取消删除", }); }); }, initPositions() { this.getRequest("/system/basic/position/list").then((resp) => { if (resp) { this.positions = resp; } }); }, }
|
七、聊天记录-PC端
1.云E办
1.借助github资源网站,搜索vue-chat
2.有的项目是有bug的,所以用隐身打开窗口来运行。
3.下载解压—->用管理员的身份打开命令提示符,
4.cd 文件路径—>npm install—>npm run dev
5.自动打开浏览器运行
6.打开文件里的代码,在自己的项目创建vue文件
7.在路由文件 router/index.js 中,添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { path: '/home', name: 'Home', component: Home, children: [{ path: '/chat', name: '在线聊天', component: FriendChat, }, { path: '/userinfo', name: '个人中心', component: AdminInfo } ] }
|
8.在home.vue文件添加路口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <div> <!-- 铃铛图标聊天信息,点击会跳到聊天记录 --> <el-button icon="el-icon-my-message" type="text" size="normal" style="color: black; margin-right: 20px" @click="goChat"> </el-button> <!-- //用户头像菜单信息 --> <el-dropdown class="userInfo" @command="commandHandler"> <span class="el-dropdown-link"> {{ user.name }}<i><img :src="user.userFace" alt="" /></i> </span> <el-dropdown-menu slot="dropdown"> <el-dropdown-item command="userinfo">个人中心</el-dropdown-item> <el-dropdown-item command="setting">设置</el-dropdown-item> <el-dropdown-item command="logout">注销登录</el-dropdown-item> </el-dropdown-menu> </el-dropdown> </div> data() { return { }; }, computed: { }, methods: { goChat() { this.$router.push("/chat"); }, }
|
9.用下载第三方的项目,复制一些可以用的组件例如:vue,js,图片等等,替换自己的。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <template> <div id="app"> <div class="sidebar"> <card></card> <list></list> </div> <div class="main"> <message></message> <usertext></usertext> </div> </div> </template> <script> import card from './components/card.vue' import list from './components/list.vue' import message from './components/message.vue' import usertext from './components/usertext.vue'
export default { name: 'app', data () { return { } }, mounted:function() { this.$store.dispatch('initData'); }, components:{ card, list, message, usertext } } </script> <style lang="scss" scoped> #app { margin: 20px auto; width: 800px; height: 600px; overflow: hidden; border-radius: 10px; .sidebar, .main { height: 100%; } .sidebar { float: left; color: #f4f4f4; background-color: #2e3238; width: 200px; } .main { position: relative; overflow: hidden; background-color: #eee; } } </style>
|
10.css用sass写的,安装:npm install sass-loader —save-dev //存放在dev文件里
安装:npm install node-loader —save-dev
11.运行后,点开聊天界面,按F12,点击头像,复制图片地址 //可以忽略

12.最后修改各种bug…
13.服务器与浏览器双向通讯数据发送安装:npm install sockjs-client与npm install stompjs
14.在接口vue.config.js添加
1 2 3 4
| proxyObj['/ws'] = { ws: true, target: 'ws://dongeast.top:8181' };
|
15.在store中的index.js添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import SockJs from 'sockjs-client' import Stomp from 'stompjs' const store = new Vuex.Store({
state: { stomp: null, }, mutations: { initRoutes(state, data) { state.routes = data; }, },
actions: { connect(context) { console.log(context); context.state.stomp = Stomp.over(new SockJs('/ws/ep')); let token = window.sessionStorage.getItem('tokenStr'); context.state.stomp.connect({ 'Auth-Token': token }, success => { context.state.stomp.subscribe('/user/queue/chat', msg => { let receiveMsg = JSON.parse(msg.body); if (context.state.currentSession || receiveMsg.from != context.state.currentAdmin.username) { Notification.info({ title: '[' + receiveMsg.formNickName + ']发来一条消息', message: receiveMsg.content.length > 10 ? receiveMsg.content.substr(0, 10) : receiveMsg.content, position: 'bottom-right' }); Vue.set(context.state.isDot, context.state.currentAdmin.username + '#' + receiveMsg.from, true); }; receiveMsg.notSelf = true; receiveMsg.to = receiveMsg.from; context.commit('addMessage', receiveMsg); }) }, error => {
}) }, initData(context) { context.commit('INIT_DATA'); getRequest('/chat/admin').then(resp => { if (resp) { context.commit('INIT_ADMINS', resp) } }) }, }, modules: {} })
store.watch(function(state) { return state.sessions }, function(val) { console.log('CHANGE: ', val); localStorage.setItem('vue-chat-session', JSON.stringify(val)); }, { deep: true })
|
1 2 3
| state: { stomp: null, },
|
八、更新信息-PC端
1.云E办
1.1 卡片禁用用户状态
卡片中用户状态,启用时可以登录,禁用时不能登录

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <div>用户状态: <el-switch v-model="admin.enabled" active-color="#13ce66" inactive-color="#ff4949" active-text="启用" inactive-text="禁用" @change="enabledChange(admin)"> </el-switch> </div> data() { return { admins: [], }; }, mounted() { this.initAdmins(); }, methods: { enabledChange(admin) { this.putRequest("/admin/update", admin).then((resp) => { if (resp) { this.initAdmins(); } }); }, } }
|
九、前后接口-PC端
1.云E办
1.1 请求头host
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| let proxyObj = {}
proxyObj['/'] = { ws: false, target: 'http://127.0.0.1:9090', changeOrigin: true, pathRewrite: {'^/': '/'} } module.exports = { devServer: { host: 'localhost', port: 8082, proxy: proxyObj } }
|
1.2 请求头host设置target
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| let proxyObj = {}; proxyObj['/'] = { ws: false, target: 'http://dongeast.top:8181', changeOrigin: true, pathWewrite: { "^/": '/', } } proxyObj['/ws'] = { ws: true, target: 'ws://dongeast.top:8181' }; module.exports = { devServer: { host: "localhost", port: 8080, proxy: proxyObj, } }
|
十、导入导出-PC端
先安装—->
vs code—->npm install js-file-download
①使用导出导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import axios from 'axios'
const service = axios.create({ responseType: 'arraybuffer' })
service.interceptors.request.use(config => { config.headers['Authorization'] = window.sessionStorage.getItem('tokenStr'); return config; }, error => { console.log(error); }) service.interceptors.response.use(resp => { const headers = resp.headers; let reg = RegExp(/application\/json/); if (headers['content-type'].match(reg)) { resp.data = unitToString(resp.data); } else { let fileDownload = require('js-file-download'); let fileName = headers['content-disposition'].split(';')[1].split('filename=')[1]; let contentType = headers['content-type']; fileName = decodeURIComponent(fileName); fileDownload(resp.data, fileName, contentType); } }, error => { console.log(error); }) function unitToString(unitArray) { let encodeString = String.fromCharCode.apply(null, new Uint8Array(unitArray)); let decodeString = decodeURIComponent(escape(encodeString)); return JSON.parse(decodeString) } let base = ''; export const downloadRequest = (url, params) => { return service({ method: 'get', url: `${base}${url}`, data: params }) } export default service
|
不要忘了要去main.ja使用—>
——->import {downLoadRequest} from “./utils/downLoad”;
——->Vue.prototype.downLoadRequest = downloadRequest;
1.云E办
1.1 导出导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <div> <el-upload style="display: inline-flex; margin-right: 8px" :show-file-list="false" :before-upload="beforeUpload" :on-success="onSuccess" :headers="headers" :on-error="onError" :disabled="importDataDisabled" action="/employee/basic/import"> <el-button type="success" :disabled="importDataDisabled" :icon="importDataBtnIcon"> {{ importDataBtnText }} </el-button><!--在下边导入--> </el-upload> <el-button type="success" @click="exportData" icon="el-icon-download"> 导出数据 </el-button> </div> data() { return { headers: { Authorization: window.sessionStorage.getItem("tokenStr"), }, importDataBtnText: "导入数据", importDataBtnIcon: "el-icon-upload2", importDataDisabled: false, } }, mounted() { this.initEmps(); this.initData(); this.initPositions(); }, methods: { onSuccess() { this.importDataBtnText = "导入数据"; this.importDataDisabled = false; this.importDataBtnIcon = "el-icon-upload2"; console.log("导入数据成功!"); this.initEmps(); }, onError() { this.importDataBtnText = "导入数据"; this.importDataDisabled = false; this.importDataBtnIcon = "el-icon-upload2"; }, beforeUpload() { this.importDataBtnText = "正在导入"; this.importDataDisabled = true; this.importDataBtnIcon = "el-icon-loading"; }, <!--导出数据--> exportData() { this.downloadRequest("/employee/basic/export"); }, }
|
十一、main方法-PC端
1.云E办
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import Vue from 'vue' import App from './App.vue'
import router from './router' import store from './store' import ElementUI from 'element-ui';
import 'font-awesome/css/font-awesome.css' import 'element-ui/lib/theme-chalk/index.css'; import { postRequest } from "./utils/api"; import { putRequest } from "./utils/api"; import { getRequest } from "./utils/api"; import { deleteRequest } from "./utils/api"; import { initMenu } from './utils/menus'; import { downloadRequest } from './utils/download'; Vue.config.productionTip = false Vue.use(ElementUI, { size: 'small' }); Vue.prototype.postRequest = postRequest; Vue.prototype.putRequest = putRequest; Vue.prototype.getRequest = getRequest; Vue.prototype.deleteRequest = deleteRequest; Vue.prototype.downloadRequest = downloadRequest;
router.beforeEach((to, from, next) => { if (window.sessionStorage.getItem('tokenStr')) { initMenu(router, store); if (!window.sessionStorage.getItem('user')) { return getRequest('/admin/info').then(resp => { if (resp) { window.sessionStorage.setItem('user', JSON.stringify(resp)); store.commit("INIT_ADMIN", resp); next(); } }); } next(); } else { if (to.path == '/') { next(); } else { next('/?redirect=' + to.path) } } }) new Vue({ router, store, render: h => h(App) }).$mount('#app')
|
十二、拦截器-PC端
1.云E办
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| import axios from 'axios' import { Loading, Message } from 'element-ui' import router from 'vue-router'
axios.interceptors.request.use(success => { if (window.sessionStorage.getItem('tokenStr')) { success.headers['Authorization'] = window.sessionStorage.getItem('tokenStr'); } return success; }, error => { console.log(error); })
axios.interceptors.response.use(success => { if (success.status && success.status == 200) { if (success.data.code == 500 || success.data.data == 401 || success.data.code == 403) { Message.error({ message: success.data.message }); return; } if (success.data.message) { Message.success({ message: success.data.message }); } } return success.data; }, error => { if (error.response.code == 504 || error.response.code == 404) { Message.error({ message: "服务器被吃了!" }); } else if (error.response.code == 403) { Message.error({ message: "权限不足,请联系管理员!" }) } else if (error.response.code == 401) { Message.error({ message: "没有登录,请进行登录" }); router.replace('/'); } else { if (error.response.data.message) { Message.error({ message: error.response.data.message }) } else { Message.error({ message: '未知错误' }) } } return; }); let base = '';
export const postRequest = (url, params) => { return axios({ method: 'post', url: `${base}${url}`, data: params }) } export const putRequest = (url, params) => { return axios({ method: 'put', url: `${base}${url}`, data: params }) } export const getRequest = (url, params) => { return axios({ method: 'get', url: `${base}${url}`, data: params, }) } export const deleteRequest = (url, params) => { return axios({ method: 'delete', url: `${base}${url}`, params, }) }
|
十三、路由器-PC端
1.云E办
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import { getRequest } from "./api";
export const initMenu = (router, store) => { if (store.state.routes.length > 0) { return; } getRequest("/system/cfg/menu").then(data => { if (data) { let fmtRoutes = formatRoutes(data); for (let x of fmtRoutes) { router.addRoute(x) } store.commit('initRoutes', fmtRoutes); store.dispatch('connect'); } }) }
export const formatRoutes = (routes) => { let fmtRoutes = []; routes.forEach(item => { let { path, component, name, iconCls, children } = item; if (children && children instanceof Array) { children = formatRoutes(children); } let fmRouter = { path: path, name: name, iconCls: iconCls, children: children, component(resolve) { if (component.startsWith('Home')) { require(['../views/' + component + '.vue'], resolve); } else if (component.startsWith('Emp')) { require(['../views/emp/' + component + '.vue'], resolve); } else if (component.startsWith('Per')) } } fmtRoutes.push(fmRouter) }); return fmtRoutes; }
|
十四、常用语法-PC端
1.云E办
1.输入不能为空时提示规则
1 2 3 4 5 6 7 8 9
| data() { return { rules: { username: [{ required: true, message: "请输入用户名", trigger: "blur" },], password: [{ required: true, message: "请输入密码", trigger: "blur" }], code: [{ required: true, message: "请输入验证码", trigger: "blur" }], }, }; },
|
2.前后端调用信息接口initPositions
1 2 3 4 5 6 7 8 9 10
| methods: { //前后端调用信息接口initPositions initPositions() { this.getRequest("/system/basic/position/list").then((resp) => { if (resp) { this.positions = resp; } }); }, }
|