角色和用户管理

This commit is contained in:
wuyanwen
2019-12-25 22:12:16 +08:00
parent ceda3a224a
commit 4a3f043166
12 changed files with 518 additions and 288 deletions

1
extend/catcher/Utils.php Normal file
View File

@@ -0,0 +1 @@
<?php

View File

@@ -0,0 +1,44 @@
/**
* 角色管理模块
*
*/
import { axios } from '@/utils/request'
export function getRoleList (parameter) {
return axios({
url: '/roles',
method: 'get',
params: parameter
})
}
export function store (parameter) {
return axios({
url: '/roles',
method: 'post',
data: parameter
})
}
export function read (id) {
return axios({
url: '/roles/' + id,
method: 'get'
})
}
export function update (id, parameter) {
return axios({
url: '/roles/' + id,
method: 'put',
data: parameter
})
}
export function del (id) {
return axios({
url: '/roles/' + id,
method: 'delete'
})
}

View File

@@ -1,51 +1,51 @@
/** /**
* 用户管理模块 * 用户管理模块
* *
*/ */
import { axios } from '@/utils/request' import { axios } from '@/utils/request'
export function getUsers (parameter) { export function getUserList (parameter) {
return axios({ return axios({
url: '/user', url: '/users',
method: 'get', method: 'get',
params: parameter params: parameter
}) })
} }
export function store (parameter) { export function store (parameter) {
return axios({ return axios({
url: '/user', url: '/users',
method: 'post', method: 'post',
data: parameter data: parameter
}) })
} }
export function read (id) { export function read (id) {
return axios({ return axios({
url: '/user/' + id, url: '/users/' + id,
method: 'get' method: 'get'
}) })
} }
export function update (id, parameter) { export function update (id, parameter) {
return axios({ return axios({
url: '/user/' + id, url: '/users/' + id,
method: 'put', method: 'put',
data: parameter data: parameter
}) })
} }
export function del (id) { export function del (id) {
return axios({ return axios({
url: '/user/' + id, url: '/users/' + id,
method: 'delete' method: 'delete'
}) })
} }
export function swtichStatus (id) { export function swtichStatus (id) {
return axios({ return axios({
url: 'user/switch/status/' + id, url: '/users/switch/status/' + id,
method: 'put' method: 'put'
}) })
} }

View File

@@ -85,8 +85,15 @@ export const asyncRouterMap = [
path: '/permissions/users', path: '/permissions/users',
name: 'users', name: 'users',
hideChildrenInMenu: true, // 强制显示 MenuItem 而不是 SubMenu hideChildrenInMenu: true, // 强制显示 MenuItem 而不是 SubMenu
component: () => import('@/views/permissions/users'), component: () => import('@/views/permissions/users/users'),
meta: { title: '用户管理', keepAlive: true, permission: [ 'permission' ] } meta: { title: '用户管理', keepAlive: true, permission: [ 'permission' ] }
},
{
path: '/permissions/roles',
name: 'roles',
hideChildrenInMenu: true, // 强制显示 MenuItem 而不是 SubMenu
component: () => import('@/views/permissions/roles/roles'),
meta: { title: '角色管理', keepAlive: true, permission: [ 'permission' ] }
} }
] ]
}, },

View File

@@ -1,79 +0,0 @@
<template>
<a-modal :width="640" :visible="visible" title="任务添加" @ok="handleSubmit" @cancel="visible = false">
<a-form @submit="handleSubmit" :form="form">
<a-form-item
label="任务名称"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-input v-decorator="['taskName', {rules:[{required: true, message: '请输入任务名称'}]}]" />
</a-form-item>
<a-form-item
label="开始时间"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-date-picker style="width: 100%" v-decorator="['startTime', {rules:[{required: true, message: '请选择开始时间'}]}]" />
</a-form-item>
<a-form-item
label="任务负责人"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-select v-decorator="['owner', {rules:[{required: true, message: '请选择开始时间'}]}]">
<a-select-option :value="0">付晓晓</a-select-option>
<a-select-option :value="1">周毛毛</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="产品描述"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-textarea v-decorator="['desc']"></a-textarea>
</a-form-item>
</a-form>
</a-modal>
</template>
<script>
export default {
name: 'TaskForm',
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 7 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 13 }
},
visible: false,
form: this.$form.createForm(this)
}
},
methods: {
add () {
this.visible = true
},
edit (record) {
const { form: { setFieldsValue } } = this
this.visible = true
this.$nextTick(() => {
setFieldsValue({ taskName: 'test' })
})
},
handleSubmit () {
const { form: { validateFields } } = this
this.visible = true
validateFields((errors, values) => {
if (!errors) {
console.log('values', values)
}
})
}
}
}
</script>

View File

@@ -0,0 +1,121 @@
<template>
<a-modal
:title="title"
:width="640"
:visible="visible"
:confirmLoading="confirmLoading"
@ok="handleSubmit"
@cancel="handleCancel"
>
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item
label="角色名称"
type="text"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-input v-decorator="['role_name', {rules: [{required: true, min: 3, message: '请输入至少3个字符'}]}]" />
</a-form-item>
<a-form-item
label="描述"
type="textarea"
:labelCol="labelCol"
:wrapperCol="wrapperCol"
>
<a-textarea v-decorator="['description']" />
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script>
import { store, update } from '@/api/role'
import pick from 'lodash.pick'
export default {
data () {
return {
labelCol: {
xs: { span: 24 },
sm: { span: 7 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 13 }
},
visible: false,
title: '新建角色',
confirmLoading: false,
id: null,
parent_id: 0,
form: this.$form.createForm(this)
}
},
methods: {
add () {
this.visible = true
this.title = '新增角色'
},
edit (record) {
this.visible = true
this.title = '编辑角色'
const { form: { setFieldsValue } } = this
this.id = record.id
setFieldsValue(pick(record, ['role_name', 'description']))
},
addSon (record) {
this.visible = true
this.title = '新增子角色 (' + record.role_name + ')'
this.parent_id = record.id
},
handleSubmit () {
const { form: { validateFields } } = this
this.confirmLoading = true
if (this.id) {
validateFields((errors, values) => {
if (!errors) {
update(this.id, values).then((res) => {
this.refresh(res.message)
}).catch(err => this.failed(err))
}
})
} else {
validateFields((errors, values) => {
if (!errors) {
if (this.parent_id > 0) {
values['parent_id'] = this.parent_id
}
store(values).then((res) => {
this.refresh(res.message)
}).catch(err => this.failed(err))
}
})
}
},
failed (errors) {
this.$notification['error']({
message: errors.message,
duration: 4
})
this.handleCancel()
},
handleCancel () {
this.visible = false
this.id = null
this.confirmLoading = false
this.parent_id = 0
this.form.resetFields()
},
refresh (message) {
this.$notification['success']({
message: message,
duration: 4
})
this.handleCancel()
this.$parent.$parent.handleOk()
}
}
}
</script>

View File

@@ -0,0 +1,140 @@
<template>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="48">
<a-col :md="4" :sm="24">
<a-input v-model="queryParam.role_name" placeholder="请输入角色名"/>
</a-col>
<a-col :md="4" :sm="24">
<span class="table-page-search-submitButtons">
<a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
<a-button style="margin-left: 8px" @click="() => queryParam = {}">重置</a-button>
</span>
</a-col>
</a-row>
</a-form>
</div>
<div class="table-operator">
<a-button type="primary" icon="plus" @click="$refs.roleModal.add()">新建</a-button>
</div>
<s-table
ref="table"
size="default"
rowKey="id"
:bordered="true"
:columns="columns"
:data="loadData"
:showPagination="false"
>
<span slot="action" slot-scope="text, record">
<template>
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" />
<a @click="handleAddSon(record)">新增子角色</a>
<a-divider type="vertical" />
<a @click="handleDel(record)">删除</a>
</template>
</span>
</s-table>
<create-role ref="roleModal" @ok="handleOk" />
</a-card>
</template>
<script>
import moment from 'moment'
import { STable } from '@/components'
import CreateRole from './form/create'
import { getRoleList, del } from '@/api/role'
export default {
name: 'Users',
components: {
STable,
CreateRole
},
data () {
return {
// 查询参数
queryParam: {},
// 表头
columns: [
{
title: '角色名称',
dataIndex: 'role_name'
},
{
title: '描述',
dataIndex: 'description'
},
{
title: '创建时间',
dataIndex: 'created_at',
sorter: true
},
{
title: '更新时间',
dataIndex: 'updated_at',
sorter: true
},
{
title: '操作',
dataIndex: 'action',
width: '150px',
scopedSlots: { customRender: 'action' }
}
],
// 加载数据方法 必须为 Promise 对象
loadData: parameter => {
return getRoleList(Object.assign(parameter, this.queryParam))
.then(res => {
return res
})
}
}
},
methods: {
handleEdit (record) {
this.$refs.roleModal.edit(record)
},
handleAddSon (record) {
this.$refs.roleModal.addSon(record)
},
handleDel (record) {
this.$confirm({
title: '确定删除' + record.username + '吗?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => {
del(record.id).then((res) => {
this.$notification['success']({
message: res.message,
duration: 4
})
this.handleOk()
}).catch(err => this.failed(err))
},
onCancel () {}
})
},
handleOk () {
this.$refs.table.refresh(true)
},
failed (errors) {
this.$notification['error']({
message: errors.message,
duration: 4
})
this.handleCancel()
},
resetSearchForm () {
this.queryParam = {
date: moment(new Date())
}
}
}
}
</script>

View File

@@ -45,7 +45,8 @@
<script> <script>
import { validEmail } from '@/utils/validate' import { validEmail } from '@/utils/validate'
import { store } from '@/api/user' import { store, update } from '@/api/user'
import pick from 'lodash.pick'
export default { export default {
data () { data () {
@@ -60,7 +61,7 @@ export default {
}, },
visible: false, visible: false,
confirmLoading: false, confirmLoading: false,
id: null,
form: this.$form.createForm(this) form: this.$form.createForm(this)
} }
}, },
@@ -68,6 +69,12 @@ export default {
add () { add () {
this.visible = true this.visible = true
}, },
edit (record) {
this.visible = true
const { form: { setFieldsValue } } = this
this.id = record.id
setFieldsValue(pick(record, ['username', 'email']))
},
handleEmail (rule, value, callback) { handleEmail (rule, value, callback) {
if (!validEmail(value)) { if (!validEmail(value)) {
callback(new Error('邮箱地址不正确')) callback(new Error('邮箱地址不正确'))
@@ -77,31 +84,46 @@ export default {
handleSubmit () { handleSubmit () {
const { form: { validateFields } } = this const { form: { validateFields } } = this
this.confirmLoading = true this.confirmLoading = true
validateFields((errors, values) => { if (this.id) {
if (!errors) { validateFields(['username', 'email'], (errors, values) => {
store(values).then((res) => { if (!errors) {
this.$notification['success']({ update(this.id, values).then((res) => {
message: res.data.message, this.refresh(res.message)
duration: 4 }).catch(err => this.failed(err))
}) }
this.confirmLoading = false })
this.form.resetFields() } else {
this.handleOk() validateFields((errors, values) => {
this.handleCancel() if (!errors) {
}) store(values).then((res) => {
.catch(err => this.failed(err)) this.refresh(res.message)
} }).catch(err => this.failed(err))
}) }
})
}
}, },
failed (errors) { failed (errors) {
this.$notification['error']({ this.$notification['error']({
message: errors.message, message: errors.message,
duration: 4 duration: 4
}) })
this.confirmLoading = false this.handleCancel()
}, },
handleCancel () { handleCancel (message) {
this.id = null
this.visible = false this.visible = false
this.confirmLoading = false
this.form.resetFields()
},
refresh (message) {
this.$notification['success']({
message: message,
duration: 4
})
this.visible = false
this.form.resetFields()
this.id = null
this.$parent.$parent.handleOk()
} }
} }
} }

View File

@@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
title="编辑用户" title="新建用户"
:width="640" :width="640"
:visible="visible" :visible="visible"
:confirmLoading="confirmLoading" :confirmLoading="confirmLoading"
@@ -29,14 +29,14 @@
:labelCol="labelCol" :labelCol="labelCol"
:wrapperCol="wrapperCol" :wrapperCol="wrapperCol"
> >
<a-input type="password"/> <a-input type="password" v-decorator="['password', {rules: [{required: true, min: 5, message: '请输入密码'}]}]" />
</a-form-item> </a-form-item>
<a-form-item <a-form-item
label="确认密码" label="确认密码"
:labelCol="labelCol" :labelCol="labelCol"
:wrapperCol="wrapperCol" :wrapperCol="wrapperCol"
> >
<a-input type="password"/> <a-input type="password" v-decorator="['passwordConfirm', {rules: [{required: true, min: 5, message: '请确认密码'}]}]" />
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-spin> </a-spin>
@@ -44,12 +44,11 @@
</template> </template>
<script> <script>
import pick from 'lodash.pick'
import { validEmail } from '@/utils/validate' import { validEmail } from '@/utils/validate'
import { update } from '@/api/user' import { store, update } from '@/api/user'
import pick from 'lodash.pick'
export default { export default {
name: 'EditUser',
data () { data () {
return { return {
labelCol: { labelCol: {
@@ -62,16 +61,19 @@ export default {
}, },
visible: false, visible: false,
confirmLoading: false, confirmLoading: false,
mdl: {}, id: null,
form: this.$form.createForm(this) form: this.$form.createForm(this)
} }
}, },
methods: { methods: {
add () {
this.visible = true
},
edit (record) { edit (record) {
console.log(record)
this.visible = true this.visible = true
const { form: { setFieldsValue } } = this const { form: { setFieldsValue } } = this
setFieldsValue(pick({ username: '123' })) this.id = record.id
setFieldsValue(pick(record, ['username', 'email']))
}, },
handleEmail (rule, value, callback) { handleEmail (rule, value, callback) {
if (!validEmail(value)) { if (!validEmail(value)) {
@@ -81,33 +83,47 @@ export default {
}, },
handleSubmit () { handleSubmit () {
const { form: { validateFields } } = this const { form: { validateFields } } = this
validateFields((errors, values) => { this.confirmLoading = true
if (!errors) { if (this.id) {
this.confirmLoading = true validateFields(['username', 'email'], (errors, values) => {
update(values).then((res) => { if (!errors) {
this.$notification['success']({ update(this.id, values).then((res) => {
message: res.data.message, this.refresh(res.message)
duration: 4 }).catch(err => this.failed(err))
}) }
this.confirmLoading = false })
this.destroy() } else {
this.handleCancel() validateFields((errors, values) => {
}) if (!errors) {
.catch(err => this.failed(err)) store(values).then((res) => {
} this.refresh(res.message)
}) }).catch(err => this.failed(err))
}
})
}
}, },
failed (errors) { failed (errors) {
this.$notification['error']({ this.$notification['error']({
message: errors.message, message: errors.message,
duration: 4 duration: 4
}) })
this.confirmLoading = false this.handleCancel()
}, },
handleCancel () { handleCancel (message) {
console.log(12312) this.id = null
// clear form & currentStep
this.visible = false this.visible = false
this.confirmLoading = false
this.form.resetFields()
},
refresh (message) {
this.$notification['success']({
message: message,
duration: 4
})
this.visible = false
this.form.resetFields()
this.id = null
this.$parent.$parent.handleOk()
} }
} }
} }

View File

@@ -16,7 +16,7 @@
</a-select> </a-select>
</a-col> </a-col>
<a-col :md="4" :sm="24"> <a-col :md="4" :sm="24">
<span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} "> <span class="table-page-search-submitButtons">
<a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button> <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
<a-button style="margin-left: 8px" @click="() => queryParam = {}">重置</a-button> <a-button style="margin-left: 8px" @click="() => queryParam = {}">重置</a-button>
</span> </span>
@@ -26,13 +26,12 @@
</div> </div>
<div class="table-operator"> <div class="table-operator">
<a-button type="primary" icon="plus" @click="$refs.createModal.add()">新建</a-button> <a-button type="primary" icon="plus" @click="$refs.userModal.add()">新建</a-button>
<a-button type="dashed" @click="tableOption">{{ optionAlertShow && '关闭' || '开启' }} alert</a-button>
<a-dropdown v-action:edit v-if="selectedRowKeys.length > 0"> <a-dropdown v-action:edit v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay"> <a-menu slot="overlay">
<a-menu-item key="1"><a-icon type="delete" />删除</a-menu-item> <a-menu-item @click="multiDel()"><a-icon type="delete"/>删除</a-menu-item>
<!-- lock | unlock --> <!-- lock | unlock -->
<a-menu-item key="2"><a-icon type="lock" />禁用</a-menu-item> <a-menu-item @click="multiAble()"><a-icon type="lock"/>启用/禁用</a-menu-item>
</a-menu> </a-menu>
<a-button style="margin-left: 8px"> <a-button style="margin-left: 8px">
批量操作 <a-icon type="down" /> 批量操作 <a-icon type="down" />
@@ -43,87 +42,47 @@
<s-table <s-table
ref="table" ref="table"
size="default" size="default"
rowKey="key" rowKey="id"
:bordered="true"
:columns="columns" :columns="columns"
:data="loadData" :data="loadData"
:alert="options.alert" :alert="options.alert"
:rowSelection="options.rowSelection" :rowSelection="options.rowSelection"
showPagination="auto" showPagination="auto"
> >
<span slot="serial" slot-scope="text, record, index">
{{ index + 1 }}
</span>
<span slot="status" slot-scope="text">
<a-badge :status="text | statusTypeFilter" :text="text | statusFilter" />
</span>
<span slot="description" slot-scope="text">
<ellipsis :length="4" tooltip>{{ text }}</ellipsis>
</span>
<span slot="action" slot-scope="text, record"> <span slot="action" slot-scope="text, record">
<template> <template>
<a @click="handleEdit(record)">编辑</a> <a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" /> <a-divider type="vertical" />
<a @click="handleSub(record)">删除</a> <a @click="handleDel(record)">删除</a>
</template> </template>
</span> </span>
</s-table> </s-table>
<create-form ref="createModal" @ok="handleOk" /> <create-user ref="userModal" @ok="handleOk" />
<edit-user ref="modal" @ok="handleOk"/>
</a-card> </a-card>
</template> </template>
<script> <script>
import moment from 'moment' import moment from 'moment'
import { STable, Ellipsis } from '@/components' import { STable } from '@/components'
import EditUser from './modules/EditUser' import CreateUser from './form/create'
import CreateForm from './modules/CreateForm' import { swtichStatus, del, getUserList } from '@/api/user'
import { getRoleList, getUserList } from '@/api/manage'
import { switchStatus } from '@/api/user'
const statusMap = {
0: {
status: 'default',
text: '关闭'
},
1: {
status: 'processing',
text: '运行中'
},
2: {
status: 'success',
text: '已上线'
},
3: {
status: 'error',
text: '异常'
}
}
export default { export default {
name: 'TableList', name: 'Users',
components: { components: {
STable, STable,
Ellipsis, CreateUser
CreateForm,
EditUser
}, },
data () { data () {
return { return {
mdl: {},
// /
advanced: false,
// //
queryParam: {}, queryParam: {},
// //
columns: [ columns: [
{
title: '#',
scopedSlots: { customRender: 'serial' }
},
{ {
title: '用户ID', title: '用户ID',
dataIndex: 'id' key: 'id'
}, },
{ {
title: '用户名', title: '用户名',
@@ -164,83 +123,82 @@ export default {
}, },
selectedRowKeys: [], selectedRowKeys: [],
selectedRows: [], selectedRows: [],
// custom table alert & rowSelection // custom table alert & rowSelection
options: { options: {
alert: { show: true, clear: () => { this.selectedRowKeys = [] } }, alert: { show: false, clear: () => { this.selectedRowKeys = [] } },
rowSelection: { rowSelection: {
selectedRowKeys: this.selectedRowKeys, selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange onChange: this.onSelectChange
} }
}, }
optionAlertShow: false
}
},
filters: {
statusFilter (type) {
return statusMap[type].text
},
statusTypeFilter (type) {
return statusMap[type].status
} }
}, },
created () { created () {
this.tableOption() // this.tableOption()
getRoleList({ t: new Date() })
}, },
methods: { methods: {
tableOption () {
if (!this.optionAlertShow) {
this.options = {
alert: { show: true, clear: () => { this.selectedRowKeys = [] } },
rowSelection: {
selectedRowKeys: this.selectedRowKeys,
onChange: this.onSelectChange,
getCheckboxProps: record => ({
props: {
disabled: record.no === 'No 2', // Column configuration not to be checked
name: record.no
}
})
}
}
this.optionAlertShow = true
} else {
this.options = {
alert: false,
rowSelection: null
}
this.optionAlertShow = false
}
},
renderStatus (value, row, index) { renderStatus (value, row, index) {
return value === 1 ? <a-switch checkedChildren="正常" unCheckedChildren="禁用" defaultChecked onClick={this.handleSwitch} /> return value === 1 ? <a-button type="normal" size="small">正常</a-button> : <a-button type="danger" size="small">禁用</a-button>
: <a-switch checkedChildren="正常" id={row.id} unCheckedChildren="禁用" onClick={this.handleSwitch}/>
}, },
handleEdit (record) { handleEdit (record) {
this.$refs.modal.edit(record) this.$refs.userModal.edit(record)
}, },
handleSwitch (checked, event) { handleDel (record) {
console.log(event) this.$confirm({
switchStatus() title: '确定删除' + record.username + '吗?',
}, okText: '确定',
handleSub (record) { okType: 'danger',
if (record.status !== 0) { cancelText: '取消',
this.$message.info(`${record.no} 订阅成功`) onOk: () => {
} else { del(record.id).then((res) => {
this.$message.error(`${record.no} 订阅失败,规则已关闭`) this.$notification['success']({
} message: res.message,
duration: 4
})
this.handleOk()
})
},
onCancel () {}
})
}, },
handleOk () { handleOk () {
this.$refs.table.refresh() this.$refs.table.refresh(true)
},
multiDel () {
this.$confirm({
title: '确定批量删除吗?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => {
del(this.selectedRowKeys.join(',')).then((res) => {
this.$notification['success']({
message: res.message,
duration: 4
})
this.selectedRowKeys = []
this.handleOk()
})
},
onCancel () {}
})
},
multiAble () {
swtichStatus(this.selectedRowKeys.join(',')).then((res) => {
this.$notification['success']({
message: res.message,
duration: 4
})
console.log(this.selectedRowKeys)
// this.options.rowSelection
this.onSelectChange([], [])
this.handleOk()
})
}, },
onSelectChange (selectedRowKeys, selectedRows) { onSelectChange (selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys this.selectedRowKeys = selectedRowKeys
this.selectedRows = selectedRows this.selectedRows = selectedRows
}, },
toggleAdvanced () {
this.advanced = !this.advanced
},
resetSearchForm () { resetSearchForm () {
this.queryParam = { this.queryParam = {
date: moment(new Date()) date: moment(new Date())