赞
踩
前端源码:
https://github.com/elunez/eladmin-web
https://gitee.com/elunez/eladmin-web
个简单且易上手的 Spring boot 后台管理框架。我们可以通过这个框架快速的构建出一个前端搭载element-ui组件库,带有权限控制的后台管理系统。
前台页面千变万化,需求不同展现出的效果也不同,我们很难去找出一套模板供大家去参考使用,但后台管理系统则与之不同,他们的需求有很多都是存在共性的。
就像最常见的几种管理模式
admin
test
123456
# 配置镜像加速
https://www.ydyno.com/archives/1219.html
# 安装依赖
npm install
# 启动服务 localhost:8013
npm run dev
# 构建生产环境
npm run build:prod
Vue
vue-router
axios
element ui
|-- public 存放静态资源,存放在该文件夹的东西不会被打包影响,而是会原封不动的输出到dist文件夹中 |-- favicon.ico 网站图标 |-- index.html 主页,项目入口 |-- src |-- api 后端请求接口文件 |-- assets 静态资源 |-- components 公用组件 |-- layout 系统布局:头部、侧边栏、设置、中间内容页面 |-- mixins 混入文件 |-- router 路由配置 |-- store vuex存放数据 |-- utils 工具包 |-- auth.js 授权管理 |-- clipboard.js 简单的剪切板 |-- datetime.js Date对象补充函数 |-- index.js 获取页面标题 |-- permission.js 权限管理工具方法 |-- request.js 拦截器 |-- rsaEncrypt.js 加密、解密 |-- shortcuts.js 日期工具补充 |-- upload.js 上传函数 |-- validate.js 一些正则验证 |-- views 页面 |-- components 组件管理模块 |-- dashboard 首页 |-- features 401、404等页面 |-- generator 代码生成页面 |-- mnt 运维管理模块 |-- monitor 系统监控模块 |-- nested 多级菜单模块 |-- system 系统管理模块 |-- tools 系统工具模块 |-- home.vue 基础页面(导航栏、左侧菜单栏) |-- login.vue 登录页面 |-- app.vue 根组件 |-- main.js 入口文件 |-- settings.js 全局配置文件,存储一些键和值,供全局调用 |-- .gitignore git忽略上传的文件格式 |-- .env.development 开发环境下的接口地址配置 |-- .env.production 生产环境下的接口地址配置 |-- .eslintignore 不用校验的文件 |-- .eslintrc.js ES-lint校验(编码规范、校验规则) |-- package.json 项目描述文件 |-- vue.config.js cli配置文件
新建一个一级菜单(以新建一个数据分析页面为例)
第一步:先在views
目录下,新建文件目录如下:
第二步:在菜单管理新增数据分析菜单
第三步:点击数据分析菜单,即可显示
新建一个二级菜单(以新建一个任务管理,包含二级菜单内容管理与类别管理 为例)
第一步:先在views
目录下,新建文件目录如下:
第二步:在菜单管理新增栏目管理一级目录,内容管理与类别管理二级菜单
第三步:点击内容管理与类别管理菜单,即可显示
权限管理是需要菜单管理与代码配合实现的
以用户管理为例,用户管理有四种操作:用户创建、用户编辑、用户删除、同步,我们可以利用此框架实现给不同的角色分配不同的权限,有的用户只可以增,有的用户可以增删改等,满足不同的需求
用户管理菜单下有三个按钮并对应相应的权限标识
我们可以在角色管理页面为角色分配权限
给哪个角色分配相应的权限操作,则角色对应的用户则具有相应的操作权限
第三步:代码里为相应的按钮添加权限标识
先看user
下的index.vue
crudOperation
,CRUD.operation
是组件,头部增删改查按钮的封装
crudOperation
接收父组件传来的permisssion
参数,并对相应的按钮进行绑定。则可以实现,拥有admin
或 user:add
权限标识的用户可以创建用户,拥有admin
或 user:edit
权限标识的用户可以编辑用户…
经过上述分析,可以知道,使用权限的步骤一般为:
v-permission="XXX"
头部增删改查按钮以及右侧的刷新等,被封装在CRUD.operation
组件里
不显示某个按钮
因为CRUD.operation按钮绑定了显示值可以控制是否显示,以新增按钮为例:v-if=“crud.optShow.add”,所以我们只需要在页面的created生命周期里定义this.crud.optShow.add = false,则新增按钮就不会在页面显示了,其它按钮也一样
从左侧或右侧新增按钮
如图所示,CRUD.operation
组件里分别在左右设置了两个插槽<slot name="left" />
与<slot name="right" />
<crudOperation> <!-- 左侧添加一个导入按钮 --> <el-button slot="left" size="mini" :loading="importLoading" icon="el-icon-upload" type="primary" > 导入 </el-button> <!-- 右侧添加一个导出按钮 --> <el-button slot="right" class="filter-item" size="mini" type="warning" :loading="downloadLoading" icon="el-icon-download" @click="download()" > 导出模板 </el-button> </crudOperation>
因为使用的是混入模式,所以页面会先执行混入模式里的代码,在执行本页面的代码,所以会产生一种情况是本页面需要查询出数据之后,把其中的数据作为参数传递给查询接口。
这时候我们只需要把混入模式里的自动请求查询接口的布尔值(queryOnPresenterCreated)设置为false,即
cruds() {
return CRUD({
url: 'api/fellow',
crudMethod: { ...crudFellowShip },
queryOnPresenterCreated: false
})
},
这样就不会自动查询数据了,我们可以获取到相应的数据之后,把数据作为参数,然后再手动调用toQuery
方法进行查询
views/xxx/index.vue
cruds() {
return CRUD({
title: "部署",
url: "api/deploy",
crudMethod: { ...crudDeploy },
});
},
components/Crud/crud.js
created() { for (const k in this.$crud) { if (this.$crud[k].queryOnPresenterCreated) { // 默认查询 this.$crud[k].toQuery() } } }, // 搜索 toQuery() { crud.page.page = 1 crud.refresh() }, // 刷新 refresh() { if (!callVmHook(crud,CRUD.HOOK.beforeRefresh)) { return } return new Promise((resolve, reject) => { crud.loading = true // 请求数据 initData(crud.url, crud.getQueryParams()).then(res => { // console.log(123456) // console.log(res) const table = crud.getTable() if (table && table.lazy) { // 懒加载子节点数据,清掉已加载的数据 table.store.states.treeData = {} table.store.states.lazyTreeNodeMap = {} } crud.page.total = res.data.pages === undefined ? 0 : res.data.total crud.data = res.data.pages === undefined ? res.data : res.data.records crud.resetDataStatus() // time 毫秒后显示表格 setTimeout(() => { crud.loading = false callVmHook(crud, CRUD.HOOK.afterRefresh) }, crud.time) resolve(data) }).catch(err => { crud.loading = false reject(err) }) }) },
api/data.js
export function initData(url, params) {
return request({
url: url + '?' + qs.stringify(params, { indices: false }),
method: 'get'
})
}
components/Crud/CRUD.operation.vue
<el-button
v-if="crud.optShow.add"
v-permission="permission.add"
class="filter-item"
size="mini"
type="primary"
icon="el-icon-plus"
@click="crud.toAdd"
>
新增
</el-button>
import CRUD, { crud } from '@crud/crud'
component/Crud/crud.js
// 点击新增按钮后,调用toAdd方法 toAdd() { crud.resetForm() //调用重置表单方法,渲染表单 if (!(callVmHook(crud, CRUD.HOOK.beforeToAdd, crud.form) && callVmHook(crud, CRUD.HOOK.beforeToCU, crud.form))) { return } crud.status.add = CRUD.STATUS.PREPARED callVmHook(crud, CRUD.HOOK.afterToAdd, crud.form) callVmHook(crud, CRUD.HOOK.afterToCU, crud.form) }, /** * 重置表单方法 * @param {Array} data 数据 */ resetForm(data) { const form = data || (typeof crud.defaultForm === 'object' ? JSON.parse(JSON.stringify(crud.defaultForm)) : crud.defaultForm.apply(crud.findVM('form'))) const crudFrom = crud.form for (const key in form) { if (crudFrom.hasOwnProperty(key)) { crudFrom[key] = form[key] } else { Vue.set(crudFrom, key, form[key]) } } }, // hook VM function callVmHook(crud, hook) { if (crud.debug) { console.log('callVmHook: ' + hook) } const tagHook = crud.tag ? hook + '$' + crud.tag : null let ret = true const nargs = [crud] for (let i = 2; i < arguments.length; ++i) { nargs.push(arguments[i]) } // 有些组件扮演了多个角色,调用钩子时,需要去重 const vmSet = new Set() crud.vms.forEach(vm => vm && vmSet.add(vm.vm)) vmSet.forEach(vm => { if (vm[hook]) { ret = vm[hook].apply(vm, nargs) !== false && ret } if (tagHook && vm[tagHook]) { ret = vm[tagHook].apply(vm, nargs) !== false && ret } }) return ret } // 当表单新增/编辑完毕后,点击提交 /** * 提交新增/编辑 */ submitCU() { if (!callVmHook(crud, CRUD.HOOK.beforeValidateCU)) { return; } crud.findVM('form').$refs['form'].validate(valid => { if (!valid) { return; } if (!callVmHook(crud, CRUD.HOOK.afterValidateCU)) { return; } // 根据crud状态判断是新增还是编辑 if (crud.status.add === CRUD.STATUS.PREPARED) { crud.doAdd(); //执行添加 } else if (crud.status.edit === CRUD.STATUS.PREPARED) { crud.doEdit(); } }); }, /** * 执行添加 */ doAdd() { if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) { return; } crud.status.add = CRUD.STATUS.PROCESSING; crud.crudMethod.add(crud.form).then(() => { // 发送请求回调成功后,改变crud状态,重置表单,响应,刷新页面 crud.status.add = CRUD.STATUS.NORMAL; crud.resetForm(); crud.addSuccessNotify(); callVmHook(crud, CRUD.HOOK.afterSubmit); crud.toQuery(); }).catch(() => { crud.status.add = CRUD.STATUS.PREPARED; callVmHook(crud, CRUD.HOOK.afterAddError); }); },
新增编辑前做的操作
import crudDeploy from "@/api/mnt/deploy"; [CRUD.HOOK.beforeToCU](crud, form) { this.initSelect(); const deploys = []; form.deploys.forEach(function (deploy, index) { deploys.push(deploy.id); }); this.form.deploys = deploys; }, initSelect() { crudDeploy.getApps().then((res) => { this.apps = res.content; }); crudDeploy.getServers().then((res) => { this.servers = res.content; }); },
api/mnt/deploy.js
export function getApps() {
return request({
url: 'api/app',
method: 'get'
})
}
export function getServers() {
return request({
url: 'api/server-deploy',
method: 'get'
})
}
点击提交前
[CRUD.HOOK.beforeSubmit]() {
const deploys = [];
this.form.deploys.forEach(function (data, index) {
const deploy = { id: data };
deploys.push(deploy);
});
this.form.deploys = deploys;
return true;
}
提交
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU" >确认</el-button> import CRUD, { presenter, header, form, crud } from "@crud/crud"; /** * 提交新增/编辑 */ /components/Crud/crud.js submitCU() { if (!callVmHook(crud, CRUD.HOOK.beforeValidateCU)) { return } crud.findVM('form').$refs['form'].validate(valid => { if (!valid) { return } if (!callVmHook(crud, CRUD.HOOK.afterValidateCU)) { return } if (crud.status.add === CRUD.STATUS.PREPARED) { crud.doAdd() } else if (crud.status.edit === CRUD.STATUS.PREPARED) { crud.doEdit() } }) }, doAdd() { if (!callVmHook(crud, CRUD.HOOK.beforeSubmit)) { return } crud.status.add = CRUD.STATUS.PROCESSING crud.crudMethod.add(crud.form).then(() => { crud.status.add = CRUD.STATUS.NORMAL crud.resetForm() crud.addSuccessNotify() callVmHook(crud, CRUD.HOOK.afterSubmit) crud.toQuery() }).catch(() => { crud.status.add = CRUD.STATUS.PREPARED callVmHook(crud, CRUD.HOOK.afterAddError)2332342442we }) }, crudMethod: { add: (form) => { }, del: (id) => { }, edit: (form) => { }, get: (id) => { } }, /views/xxx/index.vue cruds() { return CRUD({ title: "部署", url: "api/deploy", crudMethod: { ...crudDeploy }, }); }, /api/mnt/deploy.js export function add(data) { return request({ url: 'api/deploy', method: 'post', data }) }
发起获取数据的请求,响应到数据中的res.data.records中
crudDeploy.getApps().then((res) => {
this.apps = res.data.records
})
crudDeploy.getServers().then((res) => {
this.servers = res.data.records
})
自动挂载
var app=new Vue({
el:'#app-3',
data:{
seen:true
}
})
手动挂载
//可以实现延迟按需挂载
<p id="app">
{{name}}
</p>
<button οnclick="test()">挂载
</button>
<script>
var obj= {name: '张三'}
var vm = new Vue({
data: obj
})
function test() {
vm.$mount("#app");
}
</script>
// Vue.extend()创建没有挂载的的子类,可以使用该子累创建多个实例
var app= Vue.extend({
template: '{{message}}',
data: function () {
return {
message: 'message'
}
}
})
new app().$mount('#app') // 创建 app实例,并挂载到一个元素上
①看控制台请求是否返回,查看状态码
②查看响应拦截器
③询问后端返回的状态码是否和前端响应处理的一致
1. 不带参数 <router-link :to="{name:'home'}"> <router-link :to="{path:'/home'}"> //name,path都行, 建议用name // 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。 2.带参数 <router-link :to="{name:'home', params: {id:1}}"> // params传参数 (类似post) // 路由配置 path: "/home/:id" 或者 path: "/home:id" // 不配置path ,第一次可请求,刷新页面id会消失 // 配置path,刷新页面id会保留 // html 取参 $route.params.id // script 取参 this.$route.params.id <router-link :to="{name:'home', query: {id:1}}"> // query传参数 (类似get,url后面会显示参数) // 路由可不配置 // html 取参 $route.query.id // script 取参 this.$route.query.id
1. 不带参数 this.$router.push('/home') this.$router.push({name:'home'}) this.$router.push({path:'/home'}) 2. query传参 this.$router.push({name:'home',query: {id:'1'}}) this.$router.push({path:'/home',query: {id:'1'}}) // html 取参 $route.query.id // script 取参 this.$route.query.id 3. params传参 this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name // 路由配置 path: "/home/:id" 或者 path: "/home:id" , // 不配置path ,第一次可请求,刷新页面id会消失 // 配置path,刷新页面id会保留 // html 取参 $route.params.id // script 取参 this.$route.params.id 4. query和params区别 query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在 params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
repalace和push的区别:push跳转后会向history栈中添加一个记录,而replace不会,点击后退会跳转到上上个页面。
n代表向前或向后跳转几个页面,正数为前,负数为后
v-model=“value”
使用:value="item.label+’/’+item.value "
value.split(’/’)[0]
参考:
https://blog.csdn.net/Superman_peng/article/details/110305237
https://blog.csdn.net/qq_43781399/article/details/110286287
https://blog.csdn.net/weixin_44932487/article/details/114501495
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。