vue-element-admin
非常推荐使用集成方案。
虽然官网推荐使用基础模板,从集成方案中按需添加功能。因为集成方案有些功能用不上,会形成冗余代码。
但是,使用基础模板,真的是非常基础,好多功能都没有,比如标签页的导航,基础模板只有面包屑导航,这时候如果想添加标签页的功能,像我这种不熟悉源码的人,真找不着该复制些什么内容过来。
所以,集成方案,冗余就冗余吧,删代码总比复制代码简单些。
之前的工作,都是站在巨人的肩膀上,框架按业务需求,都是行内大佬改造的好好的,直接拿过来用,基本上只用操心业务代码。所以,虽然没有用过这个框架,开发起来也没有难度。
现在,新的项目,从头开始,又要用这个框架,真是从github下载框架源码开始开发,所以,好多细节需要总结记录一下。
正文
src/store/modules/user.js
login({ commit }, userInfo) {
const { username, password, code, codeId } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password, code: code.trim(), codeId: codeId }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
// commit('SET_TOKEN', data.token)
// setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
src/utils/request.js
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
//config.headers['X-Token'] = getToken()
config.headers['auth-token'] = 'userToken:' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
src/utils/request.js
timeout: 10000
src/permission.js
const whiteList = ['/login', '/auth-redirect', '/forgetPwd'] // no redirect whitelist
src/router/index.js
export const asyncRoutes = [{}];
src/router/index.js
{
path: '/forgetPwd',
name: 'ForgetPwd',
component: () =>
import ('@/views/user/forgetPwd'),
hidden: true
},
参考我的另一篇博客
https://blog.csdn.net/Irene1991/article/details/111524085
src/store/modules/settings.js
src/setting.js
/**
* @type {boolean} true | false
* @description Whether need tagsView
*/
tagsView: true,
src/permission.js 中修改 Message.error(error) 为 Message.error(error.message)
catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error.message)
next(`/login?redirect=${to.path}`)
NProgress.done()
}
路由中的权限控制是页面级别的。
src/router/index.js
{
path: '/permission',
component: Layout,
redirect: '/permission/page',
alwaysShow: true, // will always show the root menu
name: 'Permission',
meta: {
title: 'Permission',
icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav
},
children: [
{
path: 'page',
component: () => import('@/views/permission/page'),
name: 'PagePermission',
meta: {
title: 'Page Permission',
roles: ['admin'] // or you can only set roles in sub nav
}
},
{
path: 'directive',
component: () => import('@/views/permission/directive'),
name: 'DirectivePermission',
meta: {
title: 'Directive Permission'
// if do not set roles, means: this page does not require permission
}
},
{
path: 'role',
component: () => import('@/views/permission/role'),
name: 'RolePermission',
meta: {
title: 'Role Permission',
roles: ['admin']
}
}
]
},
页面中的权限控制,是按钮级别的。
关键方法
v-if="checkPermission(['admin','editor'])"
v-permission="['admin','editor']"
后端要求获取header中的status code 和 x-api-message 作为响应码和错误消息。
解码消息(base64)
decodeURIComponent(window.atob('dG9rZW4lRTQlQjglOEQlRTglODMlQkQlRTQlQjglQkElRTclQTklQkElRUYlQkMlODE='))
请求拦截器
src/utils/request.js
如下写法的问题在于,当Status Code为403或404时,使用res.status无法获取。需要在错误处理函数中,使用 error.response.status 获取。
// response interceptor
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
//const res = response.data
const res = response
// if the custom code is not 200, it is judged as an error.
// 获取响应状态Status Code信息
if (res.status != 200) {
Message({
message: res.msg || '请求失败',
type: 'error',
duration: 5 * 1000
})
if (res.status == 401) {
// to re-login
MessageBox.confirm('登录失败,请重新登录!', '确定', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.msg || '请求失败'))
} else {
return res
}
},
error => {
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
拓展学习:http://www.axios-js.com/zh-cn/docs/#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86
|
总结:还是使用常规的传参交互吧,整那些幺蛾子干啥。后来咨询了其他人,上述写法还存在功能性问题,当使用其他协议传输,有的协议没有头部消息。另外,后端返回值整体加密,消息和状态码,还是和其他返回值写一起比较方便。
{
"code": "200",
"msg": "成功",
"data": [{...},{...}]
}
设置的路由,跳出框架显示。
原因是没有设置 component: Layout
src/router/index.js
{
path: '/user',
component: Layout,
children: [{
path: 'center',
name: 'Center',
component: () =>
import ('@/views/user/center/index'),
hidden: true,
meta: { title: '个人中心' }
}]
}
排除了
表单需要有ref,formName的名字记得一致。
需要完整 el-form及 form-item 组件中 且 配置 prop,不配置的执行此方法,该输入框值不会重置。
错误原因:注意是refs,不是ref。
resetForm(formName){
this.$refs[formName].resetFields();
}
最开始没意识到是语言问题,全文检索都找不到 Go to。
后来才知道是语言问题。
src/main.js
在默认设置里,采用的是英文。
直接注释,因为默认是中文。注意下面 Vue.use Element 也要注释。
//import enLang from 'element-ui/lib/locale/lang/en'// 如果使用中文语言包请默认支持,无需额外引入,请删除该依赖
Vue.use(Element, {
size: Cookies.get('size') || 'medium', // set element-ui default size
//locale: enLang // 如果使用中文,无需设置,请删除
})
this.$store.dispatch('tagsView/delView', this.$route)
写了不生效,可能是写错了地方。比如如下示例,关闭方法错误写在了文章组件(article)中。
文章管理列表页面(index)==(点击新增,跳转到)==》文章新增页面(add)==(子组件)==》文章组件(article)==填入内容后点击提交==》新增成功,触发父组件(add)关闭当前页并返回列表页的事件。
文章管理列表页面(index)==(点击编辑,通过路由携带文章id,跳转到)==》文章编辑页面(edit)==(子组件)==》文章组件(article)==填入内容后点击提交==》编辑成功,触发父组件(edit)关闭当前页并返回列表页的事件。
备注:
1、停留在编辑页(edit),直接点击浏览器的刷新,刷新会丢失文章id。刷新时会自动关闭其他页面,仅保留当前页。
2、新增和编辑,主要是新增,返回列表页后,列表页需要重新获取数据。列表页将页面初始化的方法写在 activated 中即可。
activated() {
this.getTableData()
}
文章新增页
import ArticleDetail from './components/ArticleDetail'
export default {
name: 'ManageModuleNewsAdd',
components: { ArticleDetail },
methods: {
closeSelectedTag() {
// 关闭当前页面
this.$store.dispatch('tagsView/delView', this.$route)
this.$router.push({
name: 'ManageModuleNews'
})
}
}
}
文章编辑页
import ArticleDetail from './components/ArticleDetail'
export default {
name: 'ManageModuleNewsEdit',
components: { ArticleDetail },
methods: {
closeSelectedTag() {
// 关闭当前页面
this.$store.dispatch('tagsView/delView', this.$route)
this.$router.push({
name: 'ManageModuleNews'
})
}
}
}
文章组件
created() {
if (this.isEdit) { // 编辑 isEdit=true
const id = this.$route.params.id
if (!id) {
// 刷新会丢失id。刷新时会自动关闭其他页面,仅保留当前页。
this.$message({
message: '资讯id丢失,请关闭本页面重新进入!',
type: 'warning'
})
} else {
// 根据id查询文章详情
this.fetchData(id)
}
} else {
// 新增
this.newsForm = this.defaultNews
this.fileObj.fileUrl = ''
}
},
methods: {
handleSubmit() {
if (this.isEdit) {
this.updateNews(this.newsForm)
} else {
this.addNews(this.newsForm)
}
},
async addNews(row) {
const res = await addNews(row)
if (res.code === 200) {
this.$message({
message: '新增成功!',
type: 'success'
})
// 触发父组件 关闭当前页面 跳转列表页
this.$emit('close')
}
},
async updateNews(row) {
const res = await updateNews(row)
if (res.code === 200) {
this.$message({
message: '保存成功!',
type: 'success'
})
// 触发父组件 关闭当前页面 跳转列表页
this.$emit('close')
}
},
}
参考我的另一篇博客
https://blog.csdn.net/Irene1991/article/details/111950733
解决方式
使用行内样式