用户管理、菜单管理、角色管理功能页面开发

This commit is contained in:
aoli.qu 2021-08-31 09:26:31 +08:00
parent 3c3e7065c6
commit 7339321e5f
31 changed files with 1978 additions and 1222 deletions

View File

@ -2,11 +2,11 @@ import request from '@/utils/request'
const menuApi = { const menuApi = {
add: 'sys/menu/add', add: 'sys/menu/add',
get: 'sys/menu/get', edit: 'sys/menu/edit',
update: 'sys/menu/update', del: 'sys/menu/del',
del: 'sys/menu/delete', list: 'sys/menu/list',
updateStatus: 'sys/menu/updateStatus', tree: 'sys/menu/tree',
list: 'sys/menu/listByParentId' treeForGrant: 'sys/menu/treeForGrant'
} }
export function menuAdd (params) { export function menuAdd (params) {
@ -16,38 +16,38 @@ export function menuAdd (params) {
data: params data: params
}) })
} }
export function menuGet (params) { export function menuEdit (params) {
return request({ return request({
url: menuApi.get, url: menuApi.edit,
method: 'post', method: 'post',
data: params data: params
}) })
} }
export function menuUpdate (params) { export function menuDel (params) {
return request({
url: menuApi.update,
method: 'post',
data: params
})
}
export function menuDelete (params) {
return request({ return request({
url: menuApi.del, url: menuApi.del,
method: 'post', method: 'post',
data: params params: params
}) })
} }
export function menuList (params) { export function menuList (params) {
return request({ return request({
url: menuApi.list, url: menuApi.list,
method: 'post', method: 'get',
data: params params: params
}) })
} }
export function menuUpdateStatus (params) { export function menuTree (params) {
return request({ return request({
url: menuApi.updateStatus, url: menuApi.tree,
method: 'post', method: 'get',
data: params params: params
})
}
export function menuTreeForGrant (params) {
return request({
url: menuApi.treeForGrant,
method: 'get',
params: params
}) })
} }

View File

@ -2,11 +2,12 @@ import request from '@/utils/request'
const roleApi = { const roleApi = {
add: '/sys/role/add', add: '/sys/role/add',
get: '/sys/role/getById', edit: '/sys/role/edit',
update: '/sys/role/update', del: '/sys/role/del',
del: '/sys/role/delete', page: '/sys/role/pageList',
page: '/sys/role/page', list: '/sys/role/list',
updateStatus: '/sys/role/updateStatus' ownMenu: '/sys/role/ownMenu',
grantMenu: '/sys/role/grantMenu'
} }
export function roleAdd (params) { export function roleAdd (params) {
@ -16,37 +17,44 @@ export function roleAdd (params) {
data: params data: params
}) })
} }
export function roleGet (params) { export function roleEdit (params) {
return request({ return request({
url: roleApi.get, url: roleApi.edit,
method: 'post', method: 'post',
data: params data: params
}) })
} }
export function roleUpdate (params) { export function roleDel (params) {
return request({
url: roleApi.update,
method: 'post',
data: params
})
}
export function roleDelete (params) {
return request({ return request({
url: roleApi.del, url: roleApi.del,
method: 'post', method: 'post',
data: params params: params
}) })
} }
export function rolePage (params) { export function rolePage (params) {
return request({ return request({
url: roleApi.page, url: roleApi.page,
method: 'post', method: 'get',
data: params params: params
}) })
} }
export function roleUpdateStatus (params) { export function roleList (params) {
return request({ return request({
url: roleApi.updateStatus, url: roleApi.list,
method: 'get',
params: params
})
}
export function roleOwnMenu (params) {
return request({
url: roleApi.ownMenu,
method: 'post',
params: params
})
}
export function roleGrantMenu (params) {
return request({
url: roleApi.grantMenu,
method: 'post', method: 'post',
data: params data: params
}) })

View File

@ -4,16 +4,17 @@ const userApi = {
login: '/login', login: '/login',
logout: '/logout', logout: '/logout',
add: '/sys/user/add', add: '/sys/user/add',
get: '/sys/user/get', edit: '/sys/user/edit',
update: '/sys/user/update', del: '/sys/user/del',
del: '/sys/user/delete', page: '/sys/user/pageList',
page: '/sys/user/page', getInfo: '/sys/user/getInfo',
updateEnabled: '/sys/user/updateEnabled', ownRole: '/sys/user/ownRole',
getInfo: '/sys/user/getInfo' grantRole: '/sys/user/grantRole'
} }
const userPasswordApi = { const userPasswordApi = {
update: '/sys/user/passwordUpdate', update: '/sys/user/passwordUpdate',
reset: '/sys/user/passwordReset'
} }
export function userLogin (params) { export function userLogin (params) {
@ -24,48 +25,35 @@ export function userLogin (params) {
}) })
} }
export function userAdd (params) { export function userAdd (params,password) {
return request({ return request({
url: userApi.add, url: userApi.add,
method: 'post', method: 'post',
data: params data: params,
params: password
}) })
} }
export function userGet (params) { export function userEdit (params) {
return request({ return request({
url: userApi.get, url: userApi.edit,
method: 'post', method: 'post',
data: params data: params
}) })
} }
export function userUpdate (params) { export function userDel (params) {
return request({
url: userApi.update,
method: 'post',
data: params
})
}
export function userDelete (params) {
return request({ return request({
url: userApi.del, url: userApi.del,
method: 'post', method: 'post',
data: params params: params
}) })
} }
export function userPage (params) { export function userPage (params) {
return request({ return request({
url: userApi.page, url: userApi.page,
method: 'post', method: 'get',
data: params params: params
}) })
} }
export function userLogout (params) {
// return request({
// url: userApi.logout,
// method: 'post',
// data: params
// })
}
export function getInfo (params) { export function getInfo (params) {
return request({ return request({
url: userApi.getInfo, url: userApi.getInfo,
@ -73,9 +61,16 @@ export function getInfo (params) {
data: params data: params
}) })
} }
export function userUpdateEnabled (params) { export function userOwnRole (params) {
return request({ return request({
url: userApi.updateEnabled, url: userApi.ownRole,
method: 'post',
params: params
})
}
export function userGrantRole (params) {
return request({
url: userApi.grantRole,
method: 'post', method: 'post',
data: params data: params
}) })
@ -87,3 +82,10 @@ export function passwordUpdate (params) {
data: params data: params
}) })
} }
export function passwordReset (params) {
return request({
url: userPasswordApi.reset,
method: 'post',
data: params
})
}

View File

@ -162,6 +162,10 @@ export default {
pageSize: (pagination && pagination.pageSize) || pageSize: (pagination && pagination.pageSize) ||
this.localPagination.pageSize this.localPagination.pageSize
}) || false }) || false
// 后端数据rows为null保存修复
if (r.rows == null) {
r.rows = []
}
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页 // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
if (r.rows.length === 0 && this.showPagination && this.localPagination.current > 1) { if (r.rows.length === 0 && this.showPagination && this.localPagination.current > 1) {
this.localPagination.current-- this.localPagination.current--
@ -178,7 +182,13 @@ export default {
// } catch (e) { // } catch (e) {
// this.localPagination = false // this.localPagination = false
// } // }
this.localDataSource = r.rows // 返回结果中的数组数据 // 返回结果中的数组数据
if (this.showPagination === false) {
// 不分页的直接是在data中我们在界面中直接就是返回了data
this.localDataSource = r
} else {
this.localDataSource = r.rows
}
this.localLoading = false this.localLoading = false
}) })
} }

View File

@ -45,7 +45,9 @@ import {
Descriptions, Descriptions,
message, message,
notification, notification,
space space,
Tree,
TreeSelect
} from 'ant-design-vue' } from 'ant-design-vue'
import Viser from 'viser-vue' import Viser from 'viser-vue'
@ -99,6 +101,8 @@ Vue.use(Result)
Vue.use(Statistic) Vue.use(Statistic)
Vue.use(Descriptions) Vue.use(Descriptions)
Vue.use(space) Vue.use(space)
Vue.use(Tree)
Vue.use(TreeSelect)
Vue.prototype.$confirm = Modal.confirm Vue.prototype.$confirm = Modal.confirm
Vue.prototype.$message = message Vue.prototype.$message = message

View File

@ -49,7 +49,7 @@ const errorHandler = (error) => {
request.interceptors.request.use(config => { request.interceptors.request.use(config => {
// const token = storage.get(ACCESS_TOKEN) // const token = storage.get(ACCESS_TOKEN)
// 由于登录接口待联调token使用默认值 // 由于登录接口待联调token使用默认值
const token = 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImU1MmNhNTQ4LThmYmMtNGUyNC1iZjZjLWEzZjgwNDAwMDNiMCJ9._j_AHCd4I_PTWk4mt9euUzlABBoiqsNAIjVGrFJPWv8ZyoqgH9JPs2QFHtoj1Vly8cgtOri8X0ylbttglCcUQQ' const token = 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImY1ODZhMzc5LWQ3MjYtNDYxZS04MmFiLTUyNWRhNzI1ZjBhZCJ9.4AsSbHaR9W7dz1wBJ-u6-dL8VS5Su12eoXPnFriX-nn-CIiOMtSctMciECijN4F7uYrzUU8KP8jwkCJbPlMaQA'
// 如果 token 存在,让每个请求携带自定义 token 请根据实际情况自行修改 // 如果 token 存在,让每个请求携带自定义 token 请根据实际情况自行修改
if (token) { if (token) {
config.headers[ACCESS_TOKEN] = token config.headers[ACCESS_TOKEN] = token

View File

@ -65,3 +65,23 @@ export function removeLoadingAnimate (id = '', timeout = 1500) {
document.body.removeChild(document.getElementById(id)) document.body.removeChild(document.getElementById(id))
}, timeout) }, timeout)
} }
export function listToTree (list, tree, parentId) {
list.forEach(item => {
if (item.pid === parentId) {
const child = {
...item,
scopedSlots: {
icon: 'icon'
},
children: []
}
listToTree(list, child.children, item.id)
if (child.children.length <= 0) {
delete child.children
}
tree.push(child)
}
})
return tree
}

View File

@ -0,0 +1,5 @@
export const menuTypeMap = {
0: '目录',
1: '菜单',
2: '按钮'
}

View File

@ -0,0 +1,5 @@
export const sexMap = {
0: '未知',
1: '男',
2: '女'
}

View File

@ -303,6 +303,7 @@ export default {
}, },
onSelectChange (selectedRowKeys, selectedRows) { onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys this.selectedRowKeys = selectedRowKeys
console.log(this.selectedRowKeys.length)
this.selectedRows = selectedRows this.selectedRows = selectedRows
}, },
toggleAdvanced () { toggleAdvanced () {

View File

@ -1,5 +0,0 @@
export const typeMap = {
'CORPORATION': '公司',
'MALL': '门店',
'STORE': '店铺'
}

View File

@ -0,0 +1,388 @@
<template>
<a-modal
:title="modalTitle"
:width="1000"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
:destroyOnClose="true"
>
<a-spin :spinning="formLoading">
<a-form :form="form" >
<a-form-item v-show="false" >
<a-input v-decorator="['id']" />
</a-form-item>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-item
label="菜单名称"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
hasFeedback
>
<a-input placeholder="请输入菜单名称" v-decorator="['name',{rules: [{required: true, min: 1, message: '请输入菜单名称'}]}]" />
</a-form-item>
</a-col>
<a-col :md="12" :sm="24">
<a-form-item
style="width: 100%"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="菜单编号"
hasFeedback
>
<a-input placeholder="请输入菜单编号" v-decorator="['code', {rules: [{required: true, min: 1, message: '请输入菜单编号'}]}]" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="菜单层级"
>
<a-radio-group v-decorator="['type',{rules: [{ required: true, message: '请选择菜单层级' }]}]" >
<a-radio value="0" @click="meneTypeFunc(0)">目录</a-radio>
<a-radio value="1" @click="meneTypeFunc(1)">菜单</a-radio>
<a-radio value="2" @click="meneTypeFunc(2)">按钮</a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<a-col :md="12" :sm="24">
<div v-show="pidShow">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="父级菜单"
has-feedback
>
<a-tree-select
v-decorator="['pid', {rules: [{ required: true, message: '请选择父级菜单!' }]}]"
style="width: 100%"
:dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"
:treeData="menuTreeData"
placeholder="请选择父级菜单"
treeDefaultExpandAll
:replaceFields="{
children:'children',
title:'name',
key:'id',
value:'id'
}"
>
<span slot="title" slot-scope="{ id }">{{ id }}
</span>
</a-tree-select>
</a-form-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24" >
<a-col :md="12" :sm="24">
<div v-show="componentShow">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
hasFeedback
>
<span slot="label">
<a-tooltip title="前端vue组件 views文件夹下路径system/menu/index。注目录级填写RouteView(不带面包屑)PageView(带面包屑)菜单级内链打开http链接填写Iframe">
<a-icon type="question-circle-o" />
</a-tooltip>&nbsp;
前端组件
</span>
<a-input placeholder="请输入前端组件" :disabled="componentDisabled" prop="component" v-decorator="['component',{rules: [{required: componentRequired, message: '请输入前端组件'}]}]"/><!-- ,{rules: [{required: componentRequired, min: 1, message: '请输入前端组件!'}]} -->
</a-form-item>
</div>
</a-col>
<a-col :md="12" :sm="24">
<div v-show="routerShow">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
hasFeedback
>
<span slot="label">
<a-tooltip title="浏览器显示的URL/menu对应打开页面为菜单页面">
<a-icon type="question-circle-o" />
</a-tooltip>&nbsp;
路由地址
</span>
<a-input placeholder="请输入路由" v-decorator="['router', {rules: [{required: routerRequired, message: '请输入路由'}]}]" />
</a-form-item>
</div>
<div v-show="permissionShow">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="权限标识"
hasFeedback
>
<a-input placeholder="请输入权限标识" v-decorator="['permission', {rules: [{required: permissionRequired, message: '请输入权限标识'}]}]" />
</a-form-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="是否可见"
>
<a-switch id="visible" checkedChildren="是" unCheckedChildren="否" v-decorator="['visible', { valuePropName: 'checked' }]"/><!-- defaultChecked -->
</a-form-item>
</a-col>
<a-col :md="12" :sm="24">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="排序"
>
<a-input-number style="width: 100%" v-decorator="['intCode', { initialValue: 100 }]" :min="1" :max="1000" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="备注"
hasFeedback
>
<a-input placeholder="请输入备注" v-decorator="['remark']"></a-input>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
import { menuTree, menuAdd, menuEdit } from '@/api/security/menu'
export default {
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
modalTitle: "新增菜单",
visible: false,
confirmLoading: false,
menuTreeData: [],
componentShow: true,
componentDisabled: false,
componentRequired: true,
routerRequired: true,
routerShow: true,
pidShow: true,
permissionShow: true,
permissionRequired: true,
formLoading: true,
type: '',
form: this.$form.createForm(this)
}
},
methods: {
//
add (type) {
this.modalTitle = "新增菜单"
this.visible = true
//
this.form.getFieldDecorator('type', { valuePropName: 'checked', initialValue: '1' })
this.meneTypeFunc('1')
//
this.form.getFieldDecorator('visible', { initialValue: true })
//
this.getMenuTree()
this.formLoading = false
},
//
edit (record) {
this.modalTitle = "编辑菜单"
this.visible = true
//
this.form.getFieldDecorator('type', { valuePropName: 'checked', initialValue: record.type.toString() })
this.meneTypeFunc(record.type.toString())
//
// eslint-disable-next-line no-unused-vars
const visibleDef = false
// eslint-disable-next-line eqeqeq
if (record.visible == 1) {
this.visibleDef = true
}
this.form.getFieldDecorator('visible', { valuePropName: 'checked', initialValue: this.visibleDef })
setTimeout(() => {
this.setMenuItem(record)
//
this.getMenuTree()
}, 100)
this.formLoading = false
},
getMenuTree () {
menuTree().then((res) => {
if (res.code == 200) {
this.form.resetFields(`pid`, [])
this.menuTreeData = [{
'id': '-1',
'parentId': '0',
'name': '顶级',
'value': '0',
'pid': '0',
'children': res.data
}]
console.log(this.menuTreeData)
} else {
this.$message.warning(res.msg)
}
})
},
/**
* 选择菜单类型执行初始化表单变量
*/
meneTypeFunc (type) {
this.type = type
// eslint-disable-next-line eqeqeq
if (type == '0' || type == '1') {
//
this.routerRequired = true
this.form.getFieldDecorator('router', { initialValue: '' })
this.routerShow = true
//
this.permissionShow = false
this.permissionRequired = false
this.form.getFieldDecorator('permission', { initialValue: '' })
}
// eslint-disable-next-line eqeqeq
if (type == '0') {
// PageView
this.componentShow = true
this.componentDisabled = false
this.form.getFieldDecorator('component', { initialValue: 'PageView' })
this.componentRequired = true
//
this.form.getFieldDecorator('pid', { initialValue: '0' })
this.pidShow = false
} else {
// eslint-disable-next-line eqeqeq
if (type == '1') {
//
this.componentDisabled = false
this.form.getFieldDecorator('component', { initialValue: '' })
}
//
this.pidShow = true
}
// eslint-disable-next-line eqeqeq
if (type == '2') {
//
this.componentRequired = false
this.componentDisabled = true
this.form.resetFields(`component`, [])
this.form.getFieldDecorator('component', { initialValue: '' })
//
this.routerRequired = false
this.form.getFieldDecorator('router', { initialValue: '' })
this.routerShow = false
//
this.permissionShow = true
this.permissionRequired = true
this.form.getFieldDecorator('permission', { initialValue: '' })
}
},
handleSubmit () {
const { form: { validateFields } } = this
this.confirmLoading = true
validateFields((errors, values) => {
if (!errors) {
if (values.visible) {
values.visible = 1
} else {
values.visible = 0
}
console.log(values)
if (values.id) {
menuEdit(values).then((res) => {
this.confirmLoading = false
if (res.code == 200) {
this.$message.success('编辑成功')
this.$emit('ok', values)
this.handleCancel()
} else {
this.$message.error('编辑失败:' + res.msg)
}
}).finally((res) => {
this.confirmLoading = false
})
} else {
menuAdd(values).then((res) => {
this.confirmLoading = false
if (res.code == 200) {
this.$message.success('新增成功')
this.$emit('ok', values)
this.handleCancel()
} else {
this.$message.error('新增失败:' + res.msg)
}
}).finally((res) => {
this.confirmLoading = false
})
}
} else {
this.confirmLoading = false
}
})
},
handleCancel () {
this.form.resetFields()
this.confirmLoading = false
this.visible = false
},
setMenuItem (record) {
console.log(record)
this.form.setFieldsValue(
{
id: record.id,
name: record.name,
code: record.code,
component: record.component,
permission: record.permission,
router: record.router,
intCode: record.intCode,
remark: record.remark
}
)
this.form.getFieldDecorator('pid', { initialValue: record.pid })
this.pid = record.pid
}
}
}
</script>

View File

@ -0,0 +1,372 @@
<template>
<a-modal
title="新增菜单"
:width="1000"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
:destroyOnClose="true"
>
<a-spin :spinning="formLoading">
<a-form-model ref="ruleForm" :model="form" :rules="rules" >
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-model-item
label="菜单名称"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
hasFeedback
prop="name"
>
<a-input v-model="form.name" />
</a-form-model-item>
</a-col>
<a-col :md="12" :sm="24">
<a-form-model-item
style="width: 100%"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="菜单编号"
hasFeedback
prop="code"
>
<a-input v-model="form.code" />
</a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="菜单层级"
prop="type"
>
<a-radio-group v-model="form.type" >
<a-radio :value="0" @click="meneTypeFunc(0)">目录</a-radio>
<a-radio :value="1" @click="meneTypeFunc(1)">菜单</a-radio>
<a-radio :value="2" @click="meneTypeFunc(2)">按钮</a-radio>
</a-radio-group>
</a-form-model-item>
</a-col>
<a-col :md="12" :sm="24">
<div v-show="pidShow">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="父级菜单"
has-feedback
prop="pid"
>
<a-tree-select
v-model="form.pid"
style="width: 100%"
:dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"
:treeData="menuTreeData"
placeholder="请选择父级菜单"
treeDefaultExpandAll
:replaceFields="{
children:'children',
title:'name',
key:'id',
value:'id'
}"
>
<span slot="title" slot-scope="{ id }">{{ id }}
</span>
</a-tree-select>
</a-form-model-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24" >
<a-col :md="12" :sm="24">
<div v-show="componentShow">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
hasFeedback
prop="component"
>
<span slot="label">
<a-tooltip title="前端vue组件 views文件夹下路径system/menu/index。注目录级填写RouteView(不带面包屑)PageView(带面包屑)菜单级内链打开http链接填写Iframe">
<a-icon type="question-circle-o" />
</a-tooltip>&nbsp;
前端组件
</span>
<a-input placeholder="请输入前端组件" :disabled="componentDisabled" v-model="form.component"/><!-- ,{rules: [{required: componentRequired, min: 1, message: '请输入前端组件!'}]} -->
</a-form-model-item>
</div>
</a-col>
<a-col :md="12" :sm="24">
<div v-show="routerShow">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
hasFeedback
prop="router"
>
<span slot="label">
<a-tooltip title="浏览器显示的URL/menu对应打开页面为菜单页面">
<a-icon type="question-circle-o" />
</a-tooltip>&nbsp;
路由地址
</span>
<a-input placeholder="请输入路由" v-model="form.router" />
</a-form-model-item>
</div>
<div v-show="permissionShow">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="权限标识"
hasFeedback
prop="permission"
>
<a-input placeholder="请输入权限标识" v-model="form.permission" />
</a-form-model-item>
</div>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="是否可见"
prop="visible"
>
<a-switch checked-children="" un-checked-children="" default-checked v-model="form.visible"/><!-- defaultChecked -->
</a-form-model-item>
</a-col>
<a-col :md="12" :sm="24">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="排序"
prop="intCode"
>
<a-input-number style="width: 100%" v-model="form.intCode" />
</a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form-model-item
:labelCol="labelCol"
:wrapperCol="wrapperCol"
label="备注"
hasFeedback
prop="remark"
>
<a-input v-model="form.remark"></a-input>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</a-spin>
</a-modal>
</template>
<script>
import { menuTree, menuAdd, menuEdit } from '@/api/security/menu'
export default {
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
form: {
name: '',
code: '',
pid: '',
type: 1,
router: '',
component: '',
permission: '',
visible: true,
intCode: 0,
remark: ''
},
rules: {
name: [{ required: true, message: '请输入用户名', trigger: 'blur' }, { min: 5, message: '长度不能小于5', trigger: 'blur' }],
code: [{ required: true, message: '请输入姓名', trigger: 'blur' }, { min: 2, message: '长度不能小于5', trigger: 'blur' }]
},
visible: false,
confirmLoading: false,
menuTreeData: [],
componentShow: true,
componentDisabled: false,
componentRequired: true,
routerRequired: true,
routerShow: true,
pidShow: true,
permissionShow: true,
permissionRequired: true,
formLoading: true
}
},
methods: {
//
add (type) {
this.visible = true
//
this.meneTypeFunc(1)
//
this.getMenuTree()
this.formLoading = false
},
//
edit (record) {
this.visible = true
//
this.meneTypeFunc(record.type)
setTimeout(() => {
//
this.getMenuTree()
this.form = record
//
this.form.visible = record.visible === 1
this.formLoading = false
}, 100)
},
getMenuTree () {
menuTree().then((res) => {
if (res.code == 200) {
this.form.pid = ''
this.menuTreeData = [{
'id': '-1',
'parentId': '0',
'name': '顶级',
'value': '0',
'pid': '0',
'children': res.data
}]
console.log(this.menuTreeData)
} else {
this.$message.warning(res.msg)
}
})
},
/**
* 选择菜单类型执行初始化表单变量
*/
meneTypeFunc (type) {
if (type === 0 || type === 1) {
//
this.routerRequired = true
this.routerShow = true
this.form.router = ''
//
this.permissionShow = false
this.permissionRequired = false
this.form.permission = ''
}
// eslint-disable-next-line eqeqeq
if (type === 0) {
// PageView
this.componentShow = true
this.componentDisabled = false
this.form.component = 'PageView'
this.componentRequired = true
//
this.form.pid = 0
this.pidShow = false
} else {
// eslint-disable-next-line eqeqeq
if (type === 1) {
//
this.componentDisabled = false
this.form.component = ''
}
//
this.pidShow = true
}
// eslint-disable-next-line eqeqeq
if (type === 2) {
//
this.componentRequired = false
this.componentDisabled = true
// this.form.resetFields(`component`, [])
this.form.component = ''
//
this.routerRequired = true
this.form.router = ''
this.routerShow = false
//
this.permissionShow = true
this.permissionRequired = true
this.form.permission = ''
}
},
handleSubmit () {
this.$refs.ruleForm.validate(valid => {
if (valid) {
if (this.form.visible) {
this.form.visible = 1
} else {
this.form.visible = 0
}
if (this.form.id) {
menuAdd(this.form).then((res) => {
this.confirmLoading = false
if (res.code == 200) {
this.$message.success('新增成功')
this.$emit('ok', this.form)
this.handleCancel()
} else {
this.$message.error('新增失败:' + res.msg)
}
}).finally((res) => {
this.confirmLoading = false
})
} else {
menuEdit(this.form).then((res) => {
this.confirmLoading = false
if (res.code == 200) {
this.$message.success('新增成功')
this.$emit('ok', this.form)
this.handleCancel()
} else {
this.$message.error('新增失败:' + res.msg)
}
}).finally((res) => {
this.confirmLoading = false
})
}
} else {
return false
}
})
},
handleCancel () {
this.$refs.ruleForm.resetFields()
delete this.form.id
this.confirmLoading = false
this.visible = false
}
}
}
</script>

View File

@ -0,0 +1,159 @@
<template>
<div>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="48">
<a-col :md="8" :sm="24">
<a-form-item label="菜单名称">
<a-input v-model="queryParam.name" allow-clear placeholder="请输入菜单名称"/>
</a-form-item>
</a-col>
<a-col :md="8" :sm="24">
<a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
<a-button @click="() => {queryParam = {}, this.loadData()}">重置</a-button>
</a-col>
</a-row>
</a-form>
</div>
<div class="table-operator">
<a-button type="primary" icon="plus" @click="$refs.menuForm.add()">新增菜单</a-button>
</div>
<s-table
ref="table"
:rowKey="(record) => record.id"
:columns="columns"
:alert="false"
:data="loadData"
:showPagination="false"
:expandRowByClick="true"
>
<span slot="type" slot-scope="text, record">
<a-tag color="cyan" v-if="text === 0">
{{ record.type | typeFilter }}
</a-tag>
<a-tag color="blue" v-if="text === 1">
{{ record.type | typeFilter }}
</a-tag>
<a-tag color="purple" v-if="text === 2">
{{ record.type | typeFilter }}
</a-tag>
</span>
<span slot="action" slot-scope="text, record">
<template>
<a @click="$refs.menuForm.edit(record)">编辑</a>
<a-divider type="vertical"/>
<a-popconfirm placement="topRight" title="删除本菜单与下级?" @confirm="() => handleDel(record)">
<a>删除</a>
</a-popconfirm>
</template>
</span>
</s-table>
<menu-form ref="menuForm" @ok="handleOk"/>
</a-card>
</div>
</template>
<script>
import { STable } from '@/components'
import { menuList, menuDel } from '@/api/security/menu'
import MenuForm from './MenuForm'
import { listToTree } from '@/utils/util'
import { menuTypeMap } from '@/views/filterMap/menuTypeMap'
const rootParentId = 0
export default {
components: {
STable,
MenuForm
},
data () {
return {
data: [],
queryParam: {},
loading: true,
columns: [
{
title: '菜单名称',
dataIndex: 'name',
width: '20%'
},
{
title: '菜单类型',
dataIndex: 'type',
scopedSlots: { customRender: 'type' }
},
{
title: '组件',
dataIndex: 'component',
width: '20%',
ellipsis: true
},
{
title: '路由地址',
dataIndex: 'router',
key: 'router',
ellipsis: true
},
{
title: '排序',
dataIndex: 'intCode'
},
{
title: '操作',
dataIndex: 'action',
width: '150px',
scopedSlots: { customRender: 'action' }
}
],
loadData: parameter => {
return menuList(Object.assign(parameter, this.queryParam)).then((res) => {
return res.data
})
}
}
},
created () {
//
// if (this.hasPerm('sysMenu:edit') || this.hasPerm('sysMenu:delete')) {
// this.columns.push({
// title: '',
// dataIndex: 'action',
// width: '150px',
// scopedSlots: { customRender: 'action' }
// })
// }
},
filters: {
typeFilter (type) {
return menuTypeMap[type]
}
},
methods: {
handleDel (record) {
menuDel({id: record.id, deleteReason: ""}).then((res) => {
if (res.code == 200) {
this.$message.success('删除成功')
this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
})
},
handleOk () {
this.$refs.table.refresh()
}
}
}
</script>
<style scoped>
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -1,83 +0,0 @@
<template>
<a-modal v-model="visible" :title="modalTitle" @ok="onSubmit" @cancel="onCancel" :width="1020">
<template slot="footer">
<a-button key="cancel" @click="onCancel">取消</a-button>
<a-button key="submit" type="primary" @click="onSubmit">保存</a-button>
</template>
<a-form-model ref="ruleForm" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-model-item ref="name" label="名称" prop="name">
<a-input v-model="form.name"/>
</a-form-model-item>
</a-form-model>
</a-modal>
</template>
<script>
import { userGet, userAdd, userUpdate } from '@/api/security/user'
export default {
props: {
id: {
type: String,
default: undefined
}
},
data () {
return {
modalTitle: '新增',
visible: false,
labelCol: { span: 4 },
wrapperCol: { span: 16 },
form: {
name: ''
},
rules: {
name: [
{ required: true, message: '请输入名称', trigger: 'blur' },
{ min: 2, message: '长度不能小于2', trigger: 'blur' }
]
}
}
},
methods: {
add () {
this.modalTitle = '新增'
this.visible = true
},
edit (obj) {
this.modalTitle = '修改'
this.visible = true
userGet({ id: obj.id }).then(data => {
const form = data.data
this.form = form
})
},
onSubmit (e) {
this.$refs.ruleForm.validate(valid => {
if (valid) {
if (this.form.id) {
userUpdate(this.form).then(data => {
this.$emit('ok')
this.onCancel()
})
} else {
userAdd(this.form).then(data => {
this.$emit('ok')
this.onCancel()
})
}
} else {
return false
}
})
},
onCancel () {
this.$refs.ruleForm.resetFields()
this.visible = false
},
onReset () {
this.$refs.ruleForm.resetFields()
}
}
}
</script>

View File

@ -1,48 +0,0 @@
<template>
<a-drawer
title="品牌详情"
width="640"
placement="right"
:visible="visible"
@close="onClose">
<a-descriptions :column="{ sm: 2, xs: 1 }">
<a-descriptions-item label="名称">{{ model.name }}</a-descriptions-item>
<a-descriptions-item label="编码">{{ model.code }}</a-descriptions-item>
<a-descriptions-item label="创建时间">{{ model.createdAt | moment('YYYY-MM-DD') }}</a-descriptions-item>
<a-descriptions-item label="上次修改时间">{{ model.updatedAt }}</a-descriptions-item>
<a-descriptions-item label="状态">{{ model.status | statusFilter }}</a-descriptions-item>
<a-descriptions-item label="排序">{{ model.sortOrder }}</a-descriptions-item>
</a-descriptions>
</a-drawer>
</template>
<script>
import { userGet } from '@/api/security/user'
import { statusMap } from '@/views/status/statusMap'
export default {
data () {
return {
visible: false,
model: {}
}
},
filters: {
statusFilter (status) {
return statusMap[status]
}
},
methods: {
show (id) {
this.visible = true
userGet({ id: id }).then(data => {
this.model = data.data
})
},
onClose () {
this.model = {}
this.visible = false
}
}
}
</script>

View File

@ -1,186 +0,0 @@
<template>
<a-card :bordered="false">
<a-row :gutter="8">
<a-col :span="5">
<s-tree
:dataSource="orgTree"
:openKeys.sync="openKeys"
:search="true"
@click="handleClick"
@add="handleAdd"
@titleClick="handleTitleClick"></s-tree>
</a-col>
<a-col :span="19">
<s-table
ref="table"
size="default"
:columns="columns"
:data="loadData"
:alert="false"
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
>
<span slot="action" slot-scope="text, record">
<template v-if="$auth('table.update')">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" />
</template>
<a-dropdown>
<a class="ant-dropdown-link">
更多 <a-icon type="down" />
</a>
<a-menu slot="overlay">
<a-menu-item>
<a href="javascript:;">详情</a>
</a-menu-item>
<a-menu-item v-if="$auth('table.disable')">
<a href="javascript:;">禁用</a>
</a-menu-item>
<a-menu-item v-if="$auth('table.delete')">
<a href="javascript:;">删除</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
</s-table>
</a-col>
</a-row>
<org-modal ref="modal" @ok="handleSaveOk" @close="handleSaveClose" />
</a-card>
</template>
<script>
import STree from '@/components/Tree/Tree'
import { STable } from '@/components'
import OrgModal from './modules/OrgModal'
import { menuList } from '@/api/security/menu'
export default {
name: 'MenuTree',
components: {
STable,
STree,
OrgModal
},
data () {
return {
queryParam: {
parentId: '-1'
},
openKeys: ['key-01'],
orgTree: [],
selectedRowKeys: [],
selectedRows: [],
columns: [
{
title: '#',
dataIndex: 'no'
},
{
title: '成员名称',
dataIndex: 'description'
},
{
title: '登录次数',
dataIndex: 'callNo',
sorter: true,
needTotal: true,
customRender: (text) => text + ' 次'
},
{
title: '状态',
dataIndex: 'status',
needTotal: true
},
{
title: '更新时间',
dataIndex: 'updatedAt',
sorter: true
},
{
title: '操作',
dataIndex: 'action',
width: '150px',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: parameter => {
return menuList(Object.assign(parameter, this.queryParam))
.then(res => {
return res.result
})
}
}
},
created () {
menuList({
parentId: '-1'
}).then(res => {
this.orgTree = res.data
})
},
methods: {
handleClick (e) {
this.queryParam = {
key: e.key
}
this.$refs.table.refresh(true)
},
handleAdd (item) {
this.$message.info(`提示:你点了 ${item.key} - ${item.title} `)
this.$refs.modal.add(item.key)
},
handleTitleClick (item) {
console.log('handleTitleClick', item)
},
titleClick (e) {
console.log('titleClick', e)
},
handleSaveOk () {
},
handleSaveClose () {
},
onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows
}
}
}
</script>
<style lang="less">
.custom-tree {
/deep/ .ant-menu-item-group-title {
position: relative;
&:hover {
.btn {
display: block;
}
}
}
/deep/ .ant-menu-item {
&:hover {
.btn {
display: block;
}
}
}
/deep/ .btn {
display: none;
position: absolute;
top: 0;
right: 10px;
width: 20px;
height: 40px;
line-height: 40px;
z-index: 1050;
&:hover {
transform: scale(1.2);
transition: 0.5s all;
}
}
}
</style>

View File

@ -1,100 +0,0 @@
<template>
<a-modal
title="操作"
:width="600"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item
label="父级ID"
>
<a-input v-decorator="['parentId', {}]" disabled />
</a-form-item>
<a-form-item
label="机构名称"
>
<a-input v-decorator="['orgName', {}]" />
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
export default {
name: 'OrgModal',
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 5 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
visible: false,
confirmLoading: false,
mdl: {}
}
},
beforeCreate () {
this.form = this.$form.createForm(this)
console.log('form::', this.form)
},
created () {
},
methods: {
add (id) {
this.edit({ parentId: id })
},
edit (record) {
this.mdl = Object.assign({}, record)
this.visible = true
this.$nextTick(() => {
this.form.setFieldsValue({ ...record })
})
},
close () {
this.$emit('close')
this.visible = false
},
handleOk () {
const _this = this
//
this.form.validateFields((err, values) => {
//
if (!err) {
console.log('form values', values)
_this.confirmLoading = true
// 2000
new Promise((resolve) => {
setTimeout(() => resolve(), 2000)
}).then(() => {
// Do something
_this.$message.success('保存成功')
_this.$emit('ok')
}).catch(() => {
// Do something
}).finally(() => {
_this.confirmLoading = false
_this.close()
})
}
})
},
handleCancel () {
this.close()
}
}
}
</script>

View File

@ -1,147 +0,0 @@
<template>
<a-modal
title="操作"
:width="800"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleOk"
@cancel="handleCancel"
>
<a-steps :current="1">
<a-step>
<!-- <span slot="title">Finished</span> -->
<template slot="title">
Finished
</template>
<span slot="description">This is a description.</span>
</a-step>
<a-step title="In Progress" description="This is a description." />
<a-step title="Waiting" description="This is a description." />
</a-steps>
</a-modal>
</template>
<script>
import { getPermissions } from '@/api/manage'
import { actionToObject } from '@/utils/permissions'
import pick from 'lodash.pick'
export default {
name: 'RoleModal',
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 5 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
visible: false,
confirmLoading: false,
mdl: {},
form: this.$form.createForm(this),
permissions: []
}
},
created () {
this.loadPermissions()
},
methods: {
add () {
this.edit({ id: 0 })
},
edit (record) {
this.mdl = Object.assign({}, record)
this.visible = true
//
if (this.mdl.permissions && this.permissions) {
//
const permissionsAction = {}
this.mdl.permissions.forEach(permission => {
permissionsAction[permission.permissionId] = permission.actionEntitySet.map(entity => entity.action)
})
// action
this.permissions.forEach(permission => {
permission.selected = permissionsAction[permission.id] || []
})
}
this.$nextTick(() => {
this.form.setFieldsValue(pick(this.mdl, 'id', 'name', 'status', 'describe'))
})
console.log('this.mdl', this.mdl)
},
close () {
this.$emit('close')
this.visible = false
},
handleOk () {
const _this = this
//
this.form.validateFields((err, values) => {
//
if (!err) {
console.log('form values', values)
_this.confirmLoading = true
// 2000
new Promise((resolve) => {
setTimeout(() => resolve(), 2000)
}).then(() => {
// Do something
_this.$message.success('保存成功')
_this.$emit('ok')
}).catch(() => {
// Do something
}).finally(() => {
_this.confirmLoading = false
_this.close()
})
}
})
},
handleCancel () {
this.close()
},
onChangeCheck (permission) {
permission.indeterminate = !!permission.selected.length && (permission.selected.length < permission.actionsOptions.length)
permission.checkedAll = permission.selected.length === permission.actionsOptions.length
},
onChangeCheckAll (e, permission) {
Object.assign(permission, {
selected: e.target.checked ? permission.actionsOptions.map(obj => obj.value) : [],
indeterminate: false,
checkedAll: e.target.checked
})
},
loadPermissions () {
const that = this
getPermissions().then(res => {
const result = res.result
that.permissions = result.map(permission => {
const options = actionToObject(permission.actionData)
permission.checkedAll = false
permission.selected = []
permission.indeterminate = false
permission.actionsOptions = options.map(option => {
return {
label: option.describe,
value: option.action
}
})
return permission
})
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,117 @@
<template>
<a-modal :visible="visible" :title="modalTitle" :width="500" @cancel="onCancel" @ok="onSubmit">
<a-form-model ref="ruleForm" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-model-item ref="name" label="名称" prop="name">
<a-input v-model="form.name" />
</a-form-model-item>
<a-form-model-item ref="code" label="编码" prop="code">
<a-input v-model="form.code" />
</a-form-model-item>
<a-form-model-item ref="sort" label="排序" prop="sort">
<a-input-number v-model="form.sort" />
</a-form-model-item>
<a-form-model-item ref="remark" label="备注" prop="remark">
<a-textarea :rows="4" v-model="form.remark" />
</a-textarea>
</a-form-model-item>
</a-form-model>
</a-modal>
</template>
<script>
import {
roleAdd,
roleEdit
} from '@/api/security/role'
export default {
props: {
id: {
type: String,
default: undefined
}
},
data() {
return {
modalTitle: '新增角色',
visible: false,
labelCol: {
xs: {
span: 24
},
sm: {
span: 5
}
},
wrapperCol: {
xs: {
span: 24
},
sm: {
span: 18
}
},
form: {
name: '',
code: '',
sort: 0,
remark: ''
},
rules: {
name: [{
required: true,
message: '请输入角色名称',
trigger: 'blur'
}],
code: [{
required: true,
message: '请输入编码',
trigger: 'blur'
}]
}
}
},
methods: {
add() {
this.modalTitle = '新增角色'
this.visible = true
},
edit(obj) {
this.modalTitle = '修改角色'
this.visible = true
this.form = obj
},
onSubmit(e) {
this.$refs.ruleForm.validate(valid => {
if (valid) {
if (this.form.id) {
roleEdit(this.form).then(res => {
if (res.code == 200) {
this.$message.success('编辑成功')
this.onCancel()
} else {
this.$message.error('编辑失败:' + res.msg)
}
})
} else {
roleAdd(this.form).then(data => {
if (res.code == 200) {
this.$message.success('新增成功')
this.onCancel()
} else {
this.$message.error('新增失败:' + res.msg)
}
})
}
} else {
return false
}
})
},
onCancel() {
this.$refs.ruleForm.resetFields()
this.visible = false
}
}
}
</script>

View File

@ -1,168 +1,129 @@
<template> <template>
<div>
<a-card :bordered="false"> <a-card :bordered="false">
<div class="table-page-search-wrapper"> <div class="table-page-search-wrapper">
<a-form layout="inline"> <a-form layout="inline">
<a-row :gutter="48"> <a-row :gutter="48">
<a-col :md="6" :sm="24"> <a-col :md="8" :sm="24">
<a-form-item label="名称"> <a-form-item label="角色名称">
<a-input v-model="queryParam.name" placeholder="请输入名称" @pressEnter="handleFefresh"/> <a-input v-model="queryParam.name" allow-clear placeholder="请输入角色名称"/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :md="6" :sm="24"> <a-col :md="8" :sm="24">
<a-form-item label="状态"> <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
<a-select v-model="queryParam.status" placeholder="请选择" default-value="0" @pressEnter="handleFefresh"> <a-button @click="() => {queryParam = {}, this.loadData()}">重置</a-button>
<a-select-option value="">全部</a-select-option>
<a-select-option v-for="(item, index) in statusMap" :key="index" :value="index">{{ item }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :md="6" :sm="24">
<a-button type="primary" @click="handleFefresh">查询</a-button>
<a-button @click="() => {queryParam = {}, handleFefresh()}">重置</a-button>
</a-col>
<a-col :md="6" :sm="24" align="right">
<a-button type="primary" @click="handleCreate">新增</a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
</div> </div>
<div class="table-operator">
<a-button type="primary" icon="plus" @click="$refs.roleForm.add()">新增角色</a-button>
</div>
<s-table <s-table
ref="table" ref="table"
size="default" :rowKey="(record) => record.id"
rowKey="id"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
:rowSelection="rowSelection"
> >
<template slot="time" slot-scope="text, record">{{record.createdAt | moment}}</template> <span slot="action" slot-scope="text, record">
<template slot="tbStatus" slot-scope="text, record"> <a @click="$refs.roleForm.edit(record)">编辑</a>
<a-switch checked-children="启用" un-checked-children="停用" v-model="record.status" @change="updateStatus(record.id, record.status)"/> <a-divider type="vertical"/>
</template> <a-dropdown>
<template slot="action" slot-scope="text, record"> <a class="ant-dropdown-link">
<a href="javascript:;" @click="handleEdit(record)">修改</a> 更多 <a-icon type="down" />
<a-divider type="vertical" /> </a>
<a-popconfirm title="是否删除?" @confirm="() => handleDelete(record)"> <a-menu slot="overlay">
<a href="javascript:;">删除</a> <a-menu-item>
<a @click="$refs.roleMenuForm.roleMenu(record)">授权菜单</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm placement="topRight" title="确认删除?" @confirm="() => handleDel(record)">
<a>删除</a>
</a-popconfirm> </a-popconfirm>
<a-divider type="vertical" /> </a-menu-item>
<a href="javascript:;" @click="handleDetail(record.id)">详情</a> </a-menu>
</template> </a-dropdown>
</span>
</s-table> </s-table>
<create-form ref="modal" @ok="handleOk" /> <role-form ref="roleForm" @ok="handleOk"/>
<role-detail ref="detail"></role-detail> <role-menu-form ref="roleMenuForm" @ok="handleOk"/>
</a-card> </a-card>
</div>
</template> </template>
<script> <script>
import { rolePage, roleUpdateStatus, roleDelete } from '@/api/security/role'
import { STable } from '@/components' import { STable } from '@/components'
import CreateForm from './modules/CreateForm' import { rolePage, roleDel } from '@/api/security/role'
import RoleDetail from './modules/RoleDetail' import RoleForm from './RoleForm'
import { statusMap } from '@/views/status/statusMap' import RoleMenuForm from './RoleMenuForm'
export default { export default {
name: 'roleList',
components: { components: {
STable, STable,
CreateForm, RoleForm,
RoleDetail RoleMenuForm
}, },
data () { data () {
return { return {
statusMap: statusMap, data: [],
queryParam: { name: '', status: '' }, queryParam: {},
selectedRowKeys: [], // key loading: true,
selectedRows: [], //
columns: [ columns: [
{ title: '名称', width: 30, dataIndex: 'name', key: 'name' },
{ title: '编码', width: 30, dataIndex: 'code', key: 'code' },
{ {
title: '创建时间', title: '角色名称',
width: 10, dataIndex: 'name',
key: 'createdAt', width: '20%'
align: 'center',
scopedSlots: { customRender: 'time' }
}, },
{ {
title: '状态', title: '唯一编码',
width: 10, dataIndex: 'code'
key: 'tbStatus', },
align: 'center', {
scopedSlots: { customRender: 'tbStatus' } title: '排序',
dataIndex: 'sort'
}, },
{ {
title: '操作', title: '操作',
key: 'operation', dataIndex: 'action',
width: 10, width: '150px',
align: 'right',
scopedSlots: { customRender: 'action' } scopedSlots: { customRender: 'action' }
} }
], ],
loadData: parameter => { loadData: parameter => {
return rolePage(Object.assign(parameter, this.queryParam)) return rolePage(Object.assign(parameter, this.queryParam)).then((res) => {
.then(res => { return res
const data = res.data
data.entities.forEach((item) => {
item.status = item.status === 1
})
return data
}) })
} }
} }
}, },
computed: { created () {
rowSelection () { //
return {
selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange
}
}
}, },
methods: { methods: {
// handleDel (record) {
updateStatus (id, status) { roleDel({id: record.id}).then((res) => {
roleUpdateStatus({ if (res.code == 200) {
id: id, this.$message.success('删除成功')
status: status ? 1 : 0
}).then(res => {
this.$notification.success({
message: '操作成功',
duration: 1,
description: status ? '角色已启用' : '角色已停用'
})
this.$refs.table.refresh() this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
}) })
}, },
//
handleCreate () {
this.$refs.modal.add()
},
//
handleEdit (record) {
this.$refs.modal.edit(record)
},
//
handleDelete (record) {
roleDelete({ id: record.id }).then(() => {
this.loadData()
})
},
//
handleOk () { handleOk () {
this.$refs.table.refresh() this.$refs.table.refresh()
},
//
handleDetail (id) {
this.$refs.detail.show(id)
},
handleFefresh () {
this.$refs.table.refresh(true)
},
//
onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows
} }
} }
} }
</script> </script>
<style scoped>
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,186 @@
<template>
<a-modal
title="授权菜单"
:width="600"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
>
<a-spin :spinning="formLoading">
<a-form :form="form">
<a-form-item
label="菜单权限"
:labelCol="labelCol"
:wrapperCol="wrapperCol">
<a-tree
v-model="checkedKeys"
multiple
checkable
:auto-expand-parent="autoExpandParent"
:expanded-keys="expandedKeys"
:tree-data="menuTreeData"
:selected-keys="selectedKeys"
:replaceFields="replaceFields"
@expand="onExpand"
@check="onCheck"
/>
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
import { menuTreeForGrant } from '@/api/security/menu'
import { roleOwnMenu, roleGrantMenu } from '@/api/security/role'
export default {
data() {
return {
labelCol: {
style: { 'padding-right': '20px' },
xs: { span: 24 },
sm: { span: 5 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 15 }
},
menuTreeData: [],
expandedKeys: [],
checkedKeys: [],
visible: false,
confirmLoading: false,
formLoading: true,
autoExpandParent: true,
selectedKeys: [],
subValues: [],
roleEntity: [],
replaceFields: {
children:'children',
title:'name',
key:'id',
value:'id'
},
form: this.$form.createForm(this),
commitKeys: [],
leastChilds: []
}
},
methods: {
//
roleMenu(record) {
this.formLoading = true
this.roleEntity = record
this.visible = true
this.getMenuTree()
},
/**
* 获取菜单列表
*/
getMenuTree() {
const _this = this
menuTreeForGrant().then((res) => {
if (res.code == 200) {
_this.menuTreeData = res.data
_this.getLeastChilds(res.data)
//
_this.menuTreeData.forEach(item => {
_this.expandedKeys.push(item.id)
})
_this.expandedMenuKeys(_this.roleEntity)
}
})
},
getLeastChilds(data) {
for (let i = 0; i < data.length; i++) {
this.pushLeastChilds(data[i])
}
},
pushLeastChilds(e) {
if (e.children.length > 0) {
this.getLeastChilds(e.children)
return
}
this.leastChilds.push(e.id)
},
/**
* 此角色已有菜单权限
*/
expandedMenuKeys(record) {
const _this = this
roleOwnMenu({ id: record.id }).then((res) => {
if (res.code == 200) {
_this.pickCheckedKeys(res.data)
_this.commitKeys = res.data
}
_this.formLoading = false
})
},
pickCheckedKeys(data) {
for (let i = 0; i < data.length; i++) {
if (this.leastChilds.includes(data[i])) {
this.checkedKeys.push(data[i])
}
}
},
onExpand(expandedKeys) {
this.expandedKeys = expandedKeys
this.autoExpandParent = false
},
onCheck(checkedKeys, info) {
this.checkedKeys = checkedKeys
this.commitKeys = checkedKeys.concat(info.halfCheckedKeys)
},
onSelect(selectedKeys, info) {
this.selectedKeys = selectedKeys
},
handleSubmit() {
const _this = this
const { form: { validateFields } } = this
this.confirmLoading = true
validateFields((errors, values) => {
if (!errors) {
roleGrantMenu({ id: _this.roleEntity.id, grantMenuIdList: _this.commitKeys }).then((res) => {
if (res.code == 200) {
_this.$message.success('授权成功')
_this.confirmLoading = false
_this.$emit('ok', values)
_this.handleCancel()
} else {
_this.$message.error('授权失败:' + res.message)
}
}).finally((res) => {
_this.confirmLoading = false
})
} else {
_this.confirmLoading = false
}
})
},
handleCancel() {
//
this.checkedKeys = []
//
this.expandedKeys = []
this.leastChilds = []
this.visible = false
}
}
}
</script>

View File

@ -1,116 +0,0 @@
<template>
<a-modal centered :visible="visible" :title="modalTitle" :width="720" @close="onCancel">
<a-form-model ref="ruleForm" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="16">
<a-col :span="12">
<a-form-model-item ref="name" label="名称" prop="name"><a-input v-model="form.name" /></a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="code" label="编码" prop="code"><a-input v-model="form.code" /></a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-model-item ref="description" label="描述" prop="description"><a-input v-model="form.description" /></a-form-model-item>
</a-col>
</a-row>
</a-form-model>
<div class="draw-button-container align-center">
<a-button @click="onCancel">取消</a-button>
<a-button type="primary" @click="onSubmit">保存</a-button>
</div>
</a-modal>
</template>
<script>
import { roleGet, roleAdd, roleUpdate } from '@/api/security/role'
import { typeMap } from '../../maps/map.js'
export default {
props: {
id: {
type: String,
default: undefined
}
},
data () {
return {
typeMap: typeMap,
orgList: [],
modalTitle: '新增',
visible: false,
labelCol: { span: 4 },
wrapperCol: { span: 16 },
form: {
rolename: '',
realName: '',
mobile: '',
password: '',
type: undefined,
orgId: undefined,
orgName: '',
address: '',
email: ''
},
rules: {
rolename: [{ required: true, message: '请输入用户名', trigger: 'blur' }, { min: 5, message: '长度不能小于5', trigger: 'blur' }],
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }, { min: 2, message: '长度不能小于5', trigger: 'blur' }],
mobile: [{ required: true, message: '请输入正确的手机号', pattern: /^1[3456789]\d{9}$/, trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }, { min: 6, message: '长度不能小于6', trigger: 'blur' }],
orgId: [{ required: true, message: '请选择机构', trigger: 'blur' }]
}
}
},
filters: {
typeFilter (type) {
return typeMap[type]
}
},
methods: {
add () {
this.modalTitle = '新增'
this.visible = true
},
edit (obj) {
this.modalTitle = '修改'
this.visible = true
roleGet({ id: obj.id }).then(data => {
const form = data.data
this.form = form
})
},
onSubmit (e) {
this.$refs.ruleForm.validate(valid => {
if (valid) {
if (this.form.id) {
roleUpdate(this.form).then(data => {
this.$emit('ok')
this.onCancel()
})
} else {
roleAdd(this.form).then(data => {
this.$emit('ok')
this.onCancel()
})
}
} else {
return false
}
})
},
onCancel () {
this.$refs.ruleForm.resetFields()
this.visible = false
},
onReset () {
this.$refs.ruleForm.resetFields()
},
onChange (index) {
const org = this.orgList[index]
this.form.orgName = org.name
this.form.orgId = org.id
this.form.type = 'MALL'
}
}
}
</script>

View File

@ -1,46 +0,0 @@
<template>
<a-drawer
title="角色详情"
width="640"
placement="right"
:visible="visible"
@close="onClose">
<a-descriptions :column="{ sm: 2, xs: 1 }">
<a-descriptions-item label="名称">{{ model.name }}</a-descriptions-item>
<a-descriptions-item label="描述">{{ model.description }}</a-descriptions-item>
<a-descriptions-item label="创建时间">{{ model.createdAt | moment }}</a-descriptions-item>
<a-descriptions-item label="修改时间">{{ model.updatedAt | moment }}</a-descriptions-item>
</a-descriptions>
</a-drawer>
</template>
<script>
import { roleGet } from '@/api/security/role'
import { statusMap } from '@/views/status/statusMap'
export default {
data () {
return {
visible: false,
model: {}
}
},
filters: {
statusFilter (status) {
return statusMap[status + '']
}
},
methods: {
show (id) {
this.visible = true
roleGet({ id: id }).then(data => {
this.model = data.data
})
},
onClose () {
this.model = {}
this.visible = false
}
}
}
</script>

View File

@ -0,0 +1,282 @@
<template>
<a-modal
:title="modalTitle"
:width="900"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-divider orientation="left">基本信息</a-divider>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item style="display: none;">
<a-input v-decorator="['id']" />
</a-form-item>
<a-form-item
label="账号"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input placeholder="请输入账号" v-decorator="['loginName', {rules: [{required: true, min: 5, message: '请输入至少五个字符的账号'}]}]" />
</a-form-item>
</a-form>
</a-col>
<a-col :md="12" :sm="24" >
<a-form :form="form">
<a-form-item
label="姓名"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input placeholder="请输入姓名" v-decorator="['userName', {rules: [{required: true, message: '请输入姓名'}]}]" />
</a-form-item>
</a-form>
</a-col>
</a-row>
<a-row :gutter="24" v-if="isAdd">
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="密码"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input
placeholder="请输入密码"
type="password"
v-decorator="['password', {rules: [{required: true, message: '请输入密码!'},{
validator: validateToNextPassword,
},]}]" />
</a-form-item>
</a-form>
</a-col>
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="重复密码"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input
placeholder="请再次输入密码"
type="password"
v-decorator="['confirm', {rules: [{required: true, message: '请再次输入密码!'},
{
validator: compareToFirstPassword,
}]}]" />
</a-form-item>
</a-form>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="昵称"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input placeholder="请输入昵称" v-decorator="['nickName']" />
</a-form-item>
</a-form>
</a-col>
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="生日"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-date-picker placeholder="请选择生日" @change="onChange" style="width: 100%" v-decorator="['birthday']" />
</a-form-item>
</a-form>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="性别"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-radio-group v-decorator="['sex',{rules: [{ required: true, message: '请选择性别' }]}]" >
<a-radio :value="1"></a-radio>
<a-radio :value="2"></a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</a-col>
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="邮箱"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input placeholder="请输入邮箱" v-decorator="['email']" />
</a-form-item>
</a-form>
</a-col>
</a-row>
<a-row :gutter="24">
<a-col :md="12" :sm="24">
<a-form :form="form">
<a-form-item
label="手机号"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
has-feedback
>
<a-input placeholder="请输入手机号" v-decorator="['phoneNumber',{rules: [{ required: true, message: '请输入手机号' }]}]" />
</a-form-item>
</a-form>
</a-col>
</a-row>
</a-spin>
</a-modal>
</template>
<script>
import { userAdd, userEdit } from '@/api/security/user'
import moment from 'moment'
export default {
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
},
modalTitle: '新增菜单',
visible: false,
confirmLoading: false,
form: this.$form.createForm(this),
birthdayString: [],
isAdd: false
}
},
methods: {
//
add () {
this.modalTitle = '新增用户'
this.visible = true
this.isAdd = true
},
//
edit (record) {
this.modalTitle = '编辑用户'
this.confirmLoading = true
this.visible = true
this.isAdd = false
//
setTimeout(() => {
this.form.setFieldsValue(
{
id: record.id,
loginName: record.loginName,
userName: record.userName,
nickName: record.nickName,
sex: record.sex,
email: record.email,
phoneNumber: record.phoneNumber
}
)
}, 100)
//
if (record.birthday != null) {
this.form.getFieldDecorator('birthday', { initialValue: moment(record.birthday, 'YYYY-MM-DD') })
}
this.birthdayString = moment(record.birthday).format('YYYY-MM-DD')
this.confirmLoading = false
},
compareToFirstPassword (rule, value, callback) {
const form = this.form
if (value && value !== form.getFieldValue('password')) {
// eslint-disable-next-line standard/no-callback-literal
callback('请确认两次输入密码的一致性!')
} else {
callback()
}
},
validateToNextPassword (rule, value, callback) {
const form = this.form
if (value && this.confirmDirty) {
form.validateFields(['confirm'], { force: true })
}
callback()
},
/**
* 日期需单独转换
*/
onChange (date, dateString) {
if (date == null) {
this.birthdayString = []
} else {
this.birthdayString = moment(date).format('YYYY-MM-DD')
}
},
handleSubmit () {
const { form: { validateFields } } = this
this.confirmLoading = true
validateFields((errors, values) => {
if (!errors) {
if (this.birthdayString.length > 0) {
values.birthday = this.birthdayString
}
if (values.id) {
userEdit(values).then((res) => {
this.confirmLoading = false
if (res.code === 200) {
this.$message.success('编辑成功')
this.$emit('ok', values)
this.handleCancel()
} else {
this.$message.error('编辑失败:' + res.msg)
}
}).finally((res) => {
this.confirmLoading = false
})
} else {
userAdd(values, { password: values.password }).then((res) => {
this.confirmLoading = false
if (res.code === 200) {
this.$message.success('新增成功')
this.$emit('ok', values)
this.handleCancel()
} else {
this.$message.error('新增失败:' + res.msg)
}
}).finally((res) => {
this.confirmLoading = false
})
}
} else {
this.confirmLoading = false
}
})
},
handleCancel () {
this.form.resetFields()
this.visible = false
//
this.birthdayString = ''
this.form.getFieldDecorator('birthday', { initialValue: null })
}
}
}
</script>

View File

@ -1,152 +1,188 @@
<template> <template>
<page-header-wrapper :title="false"> <div>
<a-card :bordered="false"> <a-card :bordered="false">
<div class="table-page-search-wrapper"> <div class="table-page-search-wrapper">
<a-form layout="inline"> <a-form layout="inline">
<a-row :gutter="48"> <a-row :gutter="24">
<a-col :md="6" :sm="24"> <a-col :md="6" :sm="24">
<a-form-item label="名称"> <a-form-item label="用户名称" >
<a-input v-model="queryParam.realName" placeholder="请输入名称" @pressEnter="handleFefresh"/> <a-input v-model="queryParam.userName" placeholder="请输入用户名称"/>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :md="6" :sm="24"> <a-col :md="6" :sm="24">
<a-form-item label="状态"> <a-form-item label="账号" >
<a-select v-model="queryParam.enabled" placeholder="请选择" default-value="0" @pressEnter="handleFefresh"> <a-input v-model="queryParam.loginName" placeholder="请输入账号"/>
<a-select-option value="">全部</a-select-option>
<a-select-option v-for="(item, index) in statusMap" :key="index" :value="index">{{ item }}</a-select-option>
</a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :md="6" :sm="24"> <a-col :md="6" :sm="24">
<a-button type="primary" @click="handleFefresh">查询</a-button> <a-form-item label="手机号码" >
<a-button @click="() => {queryParam = {}, handleFefresh()}">重置</a-button> <a-input v-model="queryParam.phoneNumber" placeholder="请输入手机号码"/>
</a-form-item>
</a-col> </a-col>
<a-col :md="6" :sm="24" align="right"> <a-col :md="4" :sm="24">
<a-button type="primary" @click="handleCreate">新增</a-button> <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
<a-button style="margin-left: 8px" @click="() => queryParam = {}">重置</a-button>
</a-col> </a-col>
</a-row> </a-row>
</a-form> </a-form>
</div> </div>
<div class="table-operator">
<a-button type="primary" icon="plus" @click="$refs.userForm.add()">新增用户</a-button>
<a-button type="danger" :disabled="selectedRowKeys.length < 1" @click="batchDelete">
<a-icon type="delete"/>批量删除
</a-button>
</div>
<s-table <s-table
ref="table" ref="table"
size="default"
rowKey="id"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
:rowSelection="rowSelection" :alert="options.alert"
:rowKey="(record) => record.id"
:rowSelection="options.rowSelection"
> >
<template slot="tbStatus" slot-scope="text, record"> <span slot="sex" slot-scope="text, record">
<a-switch checked-children="启用" un-checked-children="停用" v-model="record.enabled" @change="updateStatus(record.id, record.enabled)"/> {{ record.sex | sexFilter }}
</template> </span>
<template slot="action" slot-scope="text, record"> <span slot="action" slot-scope="text, record">
<a href="javascript:;" @click="handleEdit(record)">修改</a> <a @click="$refs.userForm.edit(record)">编辑</a>
<a-divider type="vertical" /> <a-divider type="vertical" />
<a href="javascript:;" @click="handleDetail(record.id)">详情</a> <a-dropdown >
<a-divider type="vertical" /> <a class="ant-dropdown-link">
<a href="javascript:;" @click="handleDetail(record.id)">修改密码</a> 更多 <a-icon type="down" />
</template> </a>
<a-menu slot="overlay">
<a-menu-item>
<a-popconfirm placement="topRight" title="确认重置密码?" @confirm="() => resetPwd(record)">
<a>重置密码</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a @click="$refs.userRoleForm.userRole(record)">授权角色</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm placement="topRight" title="确认删除?" @confirm="() => singleDelete(record)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
</s-table> </s-table>
<create-form ref="modal" @ok="handleOk" /> <user-form ref="userForm" @ok="handleOk" />
<user-detail ref="detail"></user-detail> <user-role-form ref="userRoleForm" @ok="handleOk"/>
</a-card> </a-card>
</page-header-wrapper> </div>
</template> </template>
<script> <script>
import { userPage, userUpdateEnabled } from '@/api/security/user'
import { STable } from '@/components' import { STable } from '@/components'
import CreateForm from './modules/CreateForm' import { userPage, userDel, passwordReset } from '@/api/security/user'
import UserDetail from './modules/UserDetail' import UserForm from './UserForm'
import { statusMap } from '@/views/status/statusMap' import UserRoleForm from './UserRoleForm'
import { sexMap } from '@/views/filterMap/sexMap'
export default { export default {
name: 'UserList',
components: { components: {
STable, STable,
CreateForm, UserForm,
UserDetail UserRoleForm
}, },
data () { data () {
return { return {
statusMap: statusMap, //
queryParam: { realName: '', enabled: '' }, queryParam: {},
selectedRowKeys: [], // key //
selectedRows: [], //
columns: [ columns: [
{ title: '名称', width: 40, dataIndex: 'realName', key: 'realName' },
{ title: '手机号', width: 40, dataIndex: 'mobile', key: 'mobile' },
{ title: '邮箱', width: 40, dataIndex: 'email', key: 'email' },
{ {
title: '状态', title: '账号',
width: 10, dataIndex: 'loginName'
key: 'tbStatus', },
align: 'center', {
scopedSlots: { customRender: 'tbStatus' } title: '姓名',
dataIndex: 'userName'
},
{
title: '昵称',
dataIndex: 'nickName'
},
{
title: '性别',
dataIndex: 'sex',
scopedSlots: { customRender: 'sex' }
}, {
title: '手机',
dataIndex: 'phoneNumber'
}, },
{ {
title: '操作', title: '操作',
key: 'operation', width: '150px',
width: 10, dataIndex: 'action',
align: 'right',
scopedSlots: { customRender: 'action' } scopedSlots: { customRender: 'action' }
} }
], ],
// Promise
loadData: parameter => { loadData: parameter => {
const enabled = this.queryParam.enabled return userPage(Object.assign(parameter, this.queryParam)).then((res) => {
const queryParam = { return res
realName: this.queryParam.realName,
enabled: enabled === '1' ? true : enabled === '0' ? false : ''
}
return userPage(Object.assign(parameter, queryParam))
.then(res => {
return res.data
}) })
}
}
}, },
computed: { selectedRowKeys: [], // key
rowSelection () { selectedRows: [], //
return { options: {
alert: { show: true, clear: () => { this.selectedRowKeys = [] } },
rowSelection: {
selectedRowKeys: this.selectedRowKeys, selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange onChange: this.onSelectChange
} }
} }
}
},
filters: {
sexFilter (sex) {
return sexMap[sex]
}
},
created () {
//
}, },
methods: { methods: {
// //
updateStatus (id, status) { resetPwd (record) {
userUpdateEnabled({ passwordReset({ id: record.id }).then(res => {
id: id, if (res.code === 200) {
enabled: status ? 1 : 0 this.$message.success('重置成功')
}).then(res => { // this.$refs.table.refresh()
this.$notification.success({ } else {
message: '操作成功', this.$message.error('重置失败:' + res.message)
duration: 1, }
description: status ? '用户已启用' : '用户已停用'
}) })
},
//
singleDelete (record) {
const param = { 'ids': record.id }
this.sysUserDelete(param)
},
//
batchDelete () {
const paramIds = this.selectedRowKeys.join(',')
const param = { 'ids': paramIds }
this.sysUserDelete(param)
},
sysUserDelete (param) {
userDel(param).then((res) => {
if (res.code === 200) {
this.$message.success('删除成功')
this.$refs.table.refresh() this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.message)
}
}).catch((err) => {
this.$message.error('删除错误:' + err.message)
}) })
}, },
//
handleCreate () {
this.$refs.modal.add()
},
//
handleEdit (record) {
this.$refs.modal.edit(record)
},
//
handleOk () { handleOk () {
this.$refs.table.refresh() this.$refs.table.refresh()
}, },
//
handleDetail (id) {
this.$refs.detail.show(id)
},
handleFefresh () {
this.$refs.table.refresh(true)
},
//
onSelectChange (selectedRowKeys, selectedRows) { onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows this.selectedRows = selectedRows
@ -154,3 +190,11 @@ export default {
} }
} }
</script> </script>
<style lang="less">
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,114 @@
<template>
<a-modal
title="授权角色"
:width="800"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
>
<a-card :bordered="false">
<div>
<a-table
size="middle"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:columns="columns"
:dataSource="loadData"
:pagination="false"
:loading="loading"
:rowKey="(record) => record.id"
/>
</div>
</a-card>
</a-modal>
</template>
<script>
import { roleList } from '@/api/security/role'
import { userOwnRole, userGrantRole } from '@/api/security/user'
const columns = [
{
title: '角色名称',
dataIndex: 'name'
},
{
title: '唯一编码',
dataIndex: 'code'
}
]
export default {
name: 'UserRoleIndex',
data () {
return {
columns,
loadData: [],
selectedRowKeys: [], // Check here to configure the default column
loading: true,
visible: false,
confirmLoading: false,
recordEntity: []
}
},
computed: {
hasSelected () {
return this.selectedRowKeys.length > 0
}
},
methods: {
//
userRole (record) {
this.recordEntity = record
this.visible = true
//
this.sysUserOwnRole()
// ,
roleList().then((res) => {
this.loadData = res.data
})
},
/**
* 获取用户已有角色
*/
sysUserOwnRole () {
this.loading = true
userOwnRole({ id: this.recordEntity.id }).then((res) => {
//
this.selectedRowKeys = res.data
this.loading = false
})
},
onSelectChange (selectedRowKeys) {
this.selectedRowKeys = selectedRowKeys
},
handleSubmit () {
this.confirmLoading = false
userGrantRole({ id: this.recordEntity.id, grantRoleIdList: this.selectedRowKeys }).then((res) => {
if (res.code == 200) {
this.$message.success('授权成功')
this.confirmLoading = false
this.$emit('ok', this.recordEntity)
this.handleCancel()
} else {
this.$message.error('授权失败:' + res.message)
}
}).finally((res) => {
this.confirmLoading = false
})
this.visible = false
},
handleCancel () {
this.recordEntity = []
this.selectedRowKeys = []
this.visible = false
}
}
}
</script>

View File

@ -1,127 +0,0 @@
<template>
<a-drawer :visible="visible" :title="modalTitle" :width="720" @close="onCancel">
<a-form-model ref="ruleForm" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="16">
<a-col :span="12">
<a-form-model-item ref="username" label="用户名" prop="username"><a-input v-model="form.username" /></a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="realName" label="姓名" prop="realName"><a-input v-model="form.realName" /></a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-model-item ref="mobile" label="手机号" prop="mobile"><a-input v-model="form.mobile" /></a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="password" label="密码" prop="password"><a-input-password v-model="form.password" /></a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-model-item ref="address" label="地址" prop="address"><a-input v-model="form.address" /></a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="email" label="邮箱" prop="email"><a-input v-model="form.email" /></a-form-model-item>
</a-col>
</a-row>
</a-form-model>
<div class="draw-button-container align-center">
<a-button @click="onCancel">取消</a-button>
<a-button type="primary" @click="onSubmit">保存</a-button>
</div>
</a-drawer>
</template>
<script>
import { userGet, userAdd, userUpdate } from '@/api/security/user'
import { typeMap } from '../../maps/map.js'
export default {
props: {
id: {
type: String,
default: undefined
}
},
data () {
return {
typeMap: typeMap,
orgList: [],
modalTitle: '新增',
visible: false,
labelCol: { span: 4 },
wrapperCol: { span: 16 },
form: {
username: '',
realName: '',
mobile: '',
password: '',
type: undefined,
orgId: undefined,
orgName: '',
address: '',
email: ''
},
rules: {
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }, { min: 5, message: '长度不能小于5', trigger: 'blur' }],
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }, { min: 2, message: '长度不能小于5', trigger: 'blur' }],
mobile: [{ required: true, message: '请输入正确的手机号', pattern: /^1[3456789]\d{9}$/, trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }, { min: 6, message: '长度不能小于6', trigger: 'blur' }],
orgId: [{ required: true, message: '请选择机构', trigger: 'blur' }]
}
}
},
filters: {
typeFilter (type) {
return typeMap[type]
}
},
methods: {
add () {
this.modalTitle = '新增'
this.visible = true
},
edit (obj) {
this.modalTitle = '修改'
this.visible = true
userGet({ id: obj.id }).then(data => {
const form = data.data
this.form = form
})
},
onSubmit (e) {
this.$refs.ruleForm.validate(valid => {
if (valid) {
if (this.form.id) {
userUpdate(this.form).then(data => {
this.$emit('ok')
this.onCancel()
})
} else {
userAdd(this.form).then(data => {
this.$emit('ok')
this.onCancel()
})
}
} else {
return false
}
})
},
onCancel () {
this.$refs.ruleForm.resetFields()
this.visible = false
},
onReset () {
this.$refs.ruleForm.resetFields()
},
onChange (index) {
const org = this.orgList[index]
this.form.orgName = org.name
this.form.orgId = org.id
this.form.type = 'MALL'
}
}
}
</script>

View File

@ -1,56 +0,0 @@
<template>
<a-drawer
title="用户详情"
width="640"
placement="right"
:visible="visible"
@close="onClose">
<a-descriptions :column="{ sm: 2, xs: 1 }">
<a-descriptions-item label="用户名">{{ model.username }}</a-descriptions-item>
<a-descriptions-item label="姓名">{{ model.realName }}</a-descriptions-item>
<a-descriptions-item label="创建时间">{{ model.createdAt | moment }}</a-descriptions-item>
<a-descriptions-item label="修改时间">{{ model.updatedAt | moment }}</a-descriptions-item>
<a-descriptions-item label="状态">{{ model.enabled | statusFilter }}</a-descriptions-item>
<a-descriptions-item label="手机号">{{ model.mobile }}</a-descriptions-item>
<a-descriptions-item label="机构">{{ model.orgName }}</a-descriptions-item>
<a-descriptions-item label="类型">{{ model.type | typeFilter}}</a-descriptions-item>
<a-descriptions-item label="地址">{{ model.address }}</a-descriptions-item>
<a-descriptions-item label="邮箱">{{ model.email }}</a-descriptions-item>
</a-descriptions>
</a-drawer>
</template>
<script>
import { userGet } from '@/api/security/user'
import { enabledMap } from '@/views/status/enabledMap'
import { typeMap } from '../../maps/map.js'
export default {
data () {
return {
visible: false,
model: {}
}
},
filters: {
statusFilter (status) {
return enabledMap[status + '']
},
typeFilter (type) {
return typeMap[type]
}
},
methods: {
show (id) {
this.visible = true
userGet({ id: id }).then(data => {
this.model = data.data
})
},
onClose () {
this.model = {}
this.visible = false
}
}
}
</script>

View File

@ -1,4 +0,0 @@
export const enabledMap = {
'false': '停用',
'true': '启用'
}

View File

@ -1,4 +0,0 @@
export const statusMap = {
'0': '停用',
'1': '启用'
}