feat: 用户管理

This commit is contained in:
zy7y 2022-09-15 17:29:15 +08:00
parent fc8632b16e
commit 62c647c1f2
15 changed files with 356 additions and 71 deletions

View File

@ -48,10 +48,10 @@ async def user_arr(
async def user_list(query: UserQuery) -> Response[ListAll[list[UserRead]]]:
"""post查询用户列表"""
limit = query.size
skip = (query.offset - 1) * limit
del query.offset, query.size
users, count = await get_users(skip, limit, query.dict())
size = query.limit
skip = (query.offset - 1) * size
del query.offset, query.limit
users, count = await get_users(skip, size, query.dict())
return Response(data=ListAll(total=count, items=users))

View File

@ -63,9 +63,8 @@ async def get_users(skip: int, limit: int, kwargs: dict = None):
kwargs = {f"{k}__contains": v for k, v in kwargs.items()}
else:
kwargs = {}
result = (
UserModel.filter(status__not_in=[9, 5], **kwargs).all().order_by("-created")
)
result = UserModel.filter(**kwargs).all().order_by("-created")
print(await result.offset(skip).limit(limit))
return await result.offset(skip).limit(limit), await result.count()
@ -98,9 +97,11 @@ async def put_user(uid: int, data: UserPut):
for role in roles:
if await get_role({"id": role.rid, "status__not": 9}) is None:
return role.rid
# 更新用户
if data.password != "加密之后的密码":
data.password = get_password_hash(data.password)
else:
del data.password
await UserModel.filter(id=uid).update(**data.dict())
# todo 1. 先前有的角色,这次更新成没有 2. 先前没有的角色 这次更新成有, 3. 只更新了状态

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -42,7 +42,7 @@ class QueryData(BaseModel):
"""分页查询基础数据"""
offset: int = 1
size: int = 10
limit: int = 10
class ListAll(GenericModel, Generic[T]):

View File

@ -6,7 +6,6 @@ const route = useRoute()
const cruPath = computed(() => {
return route.path.substring(1, route.path.length).split('/')
})
console.log(route.path, route.fullPath)
</script>
<template>

View File

@ -27,6 +27,8 @@ const handleOk = () => {
setTimeout(() => {
loading.value = false
visible.value = false
// -
location.reload()
}, 1000)
}

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
// 获取角色列表, 需要考虑创建用户选择角色应该是所有未被删除的情况
export function getRoles(parms) {
return request({
url: '/role',
parms
})
}

View File

@ -31,8 +31,44 @@ export function selectRole(rid) {
}
// 获取用户列表
export function getUsers() {
export function getUsers(params) {
return request({
url: '/user'
url: '/user',
params
})
}
// 条件查询用户列表
export function queryUser(data) {
return request({
url: '/user/query',
method: 'post',
data
})
}
// 删除用户
export function delUser(id) {
return request({
url: `/user/${id}`,
method: 'delete'
})
}
// 新增用户
export function addUser(data) {
return request({
url: '/user',
method: 'post',
data
})
}
// 更新用户
export function putUser(id, data) {
return request({
url: `/user/${id}`,
method: 'put',
data
})
}

View File

@ -4,7 +4,6 @@ export default (app) => {
// 按钮权限
app.directive('per', {
mounted(el, binding) {
console.log(el, binding.value)
if (
// 是否存在
userStore().userInfo.permissions.indexOf(binding.value) === -1

View File

@ -0,0 +1,11 @@
// 登录表单验证配置
export const loginRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 20, message: '5~20', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 12, message: '6~12', trigger: 'blur' }
]
}

View File

@ -3,19 +3,9 @@ import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
import { ref, reactive, computed } from 'vue'
import { userStore } from '@/stores/user'
import { loginRules } from './conf'
const store = userStore()
//
const rules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 20, message: '5~20', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 12, message: '6~12', trigger: 'blur' }
]
}
//
const formRef = ref()
@ -40,7 +30,7 @@ const submitForm = (formEl) => {
<div class="continer">
<h1>Mini RBAC</h1>
<a-form ref="formRef" :model="formData" :rules="rules">
<a-form ref="formRef" :model="formData" :rules="loginRules">
<a-form-item has-feedback name="username">
<a-input v-model:value.trim="formData.username" placeholder="Username">
<template #prefix>

View File

@ -1,11 +1,9 @@
// 表格数据列 表头配置
export const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
align: 'center',
customRender: ({ index }) => `${index + 1}`
title: 'ID',
dataIndex: 'id',
key: 'id'
},
{
title: '用户名',
@ -37,3 +35,33 @@ export const columns = [
key: 'action'
}
]
// 新增用户的校验配置
export const addUserRules = {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 5, max: 20, message: '5~20', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 12, message: '6~12', trigger: 'blur' }
],
nickname: [
{ required: true, message: '请输入昵称', trigger: 'blur' },
{ min: 5, max: 20, message: '5~20', trigger: 'blur' }
],
roles: [{ required: true, message: '请配置角色', trigger: 'blur' }]
}
// 编辑用户的校验配置
export const putUserRules = {
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 12, message: '6~12', trigger: 'blur' }
],
nickname: [
{ required: true, message: '请输入昵称', trigger: 'blur' },
{ min: 5, max: 20, message: '5~20', trigger: 'blur' }
],
roles: [{ required: true, message: '请配置角色', trigger: 'blur' }]
}

View File

@ -1,46 +1,193 @@
<script setup>
import { getUsers } from '@/service/user'
import { columns } from './conf'
import { formatTime } from '@/utils/format'
import { ref, reactive, onMounted } from 'vue'
import { PlusOutlined, SearchOutlined } from '@ant-design/icons-vue'
import { PlusOutlined } from '@ant-design/icons-vue'
import { getUsers, queryUser, delUser, addUser, getUserInfo, putUser } from '@/service/user'
import { getRoles } from '@/service/role'
import { columns, addUserRules, putUserRules } from './conf'
import { formatTime } from '@/utils/format'
import { message } from 'ant-design-vue'
import { userStore } from '@/stores/user'
import router from '@/router'
/**查询表单响应式数据 */
const queryFormRef = ref()
const queryForm = reactive({
username: '',
nickname: ''
})
//
const isQuery = ref(false)
//
const dataSource = ref([])
//
const pageSizeChange = (current, size) => {
console.log(current, size, '展示数量变化')
}
//
const pageChange = (page, pageSize) => {
console.log(page, pageSize, '页码变化')
}
//
//
const pagination = reactive({
current: 1, //
pageSize: 10, //
showSizeChanger: true,
total: 200,
pageSizeOptions: ['10', '50', '100'],
showTotal: (total) => `${total}条数据`,
onShowSizeChange: pageSizeChange,
onChange: pageChange
pageSize: 5, //
// showSizeChanger: true,
total: 0,
pageSizeOptions: ['5', '10', '50'],
showTotal: (total) => `${total} 条数据`,
onChange: (page, pageSize) => {
pagination.current = page
pagination.pageSize = pageSize
getPageData()
}
})
onMounted(() => {
getPageData()
})
//
const getPageData = () => {
getUsers().then((res) => {
let offset = pagination.current
let limit = pagination.pageSize
if (!isQuery.value) {
getUsers({ offset, limit }).then((res) => {
dataSource.value = res.data.items
pagination.total = res.data.total
})
} else {
queryUser({ offset, limit, username: queryForm.username, nickname: queryForm.nickname }).then(
(res) => {
dataSource.value = res.data.items
pagination.total = res.data.total
}
)
}
}
//
const clickQuery = () => {
isQuery.value = true
getPageData()
}
//
const resetQueryForm = () => {
queryFormRef.value.resetFields()
isQuery.value = false
getPageData()
}
//
const delClick = (record) => {
delUser(record.id)
getPageData()
}
/**新增用户 */
const addVisible = ref(false)
const formRef = ref(null)
const newUserForm = reactive({
username: '',
nickname: '',
password: '',
roles: []
})
//
const roleOptions = ref([])
const addClick = () => {
addVisible.value = !addVisible.value
//
getRoles({ limit: 100 }).then((res) => {
roleOptions.value = res.data.items.map((e) => ({ label: e.name, value: e.id }))
})
}
// modal
const onOk = () => {
formRef.value.validateFields().then(() => {
//
const { username, nickname, password, roles } = newUserForm
let rids = roles.map((e, i) => ({ rid: e, status: i === 0 ? 5 : 1 }))
addUser({ username, nickname, password, rids }).then((res) => {
if (res.msg === '请求成功') {
message.success('新增成功')
// 1. modal
addVisible.value = !addVisible.value
// 2.
formRef.value.resetFields()
// 3.
getPageData()
}
})
})
}
// modal
const onCancel = () => {
// 2.
formRef.value.resetFields()
}
/**更新用户 */
const putClick = (record) => {
// modal
putVisible.value = !putVisible.value
//
getRoles({ limit: 100 }).then((res) => {
roleOptions.value = res.data.items.map((e) => ({ label: e.name, value: e.id }))
})
putId.value = record.id
// id
getUserInfo(record.id).then((res) => {
//
putUserForm.roles = res.data.roles.map((e) => e.id)
//
putUserForm.nickname = res.data.nickname
putUserForm.password = '加密之后的密码'
})
}
const putVisible = ref(false)
const putUserFormRef = ref()
const putUserForm = reactive({
nickname: '',
password: '',
roles: []
})
const putId = ref()
//modal
const onOkPut = () => {
//
putUserFormRef.value.validateFields().then(() => {
//
const { nickname, password, roles } = putUserForm
let rids = roles.map((e, i) => ({ rid: e, status: i === 0 ? 5 : 1 }))
putUser(putId.value, { nickname, password, rids }).then((res) => {
if (res.msg === '请求成功') {
message.success('修改成功')
// 1. modal
putVisible.value = !putVisible.value
// 2.
putUserFormRef.value.resetFields()
if (putId.value === userStore().userInfo.id) {
//
message.warning('修改了自己,请重新登录')
userStore().$reset()
router.push('/login')
} else {
// 3.
getPageData()
}
}
})
})
}
const onCancelPut = () => {
putUserFormRef.value.resetFields()
}
</script>
@ -48,17 +195,16 @@ const getPageData = () => {
<div class="user">
<!-- 查询 -->
<div class="search">
<a-form layout="inline">
<a-form-item label="用户名">
<a-input placeholder="用户名"> </a-input>
<a-form ref="queryFormRef" layout="inline" :model="queryForm">
<a-form-item label="用户名" name="username">
<a-input placeholder="用户名" v-model:value="queryForm.username"> </a-input>
</a-form-item>
<a-form-item label="昵称">
<a-input placeholder="昵称"> </a-input>
<a-form-item label="昵称" name="nickname">
<a-input placeholder="昵称" v-model:value="queryForm.nickname"> </a-input>
</a-form-item>
<a-form-item>
<a-button type="primary" v-per="'user:query'">
<template #icon> <SearchOutlined /> </template>查询</a-button
>
<a-form-item v-per="'user:query'">
<a-button type="primary" @click="clickQuery">查询</a-button>
<a-button style="margin-left: 10px" @click="resetQueryForm">重置</a-button>
</a-form-item>
</a-form>
</div>
@ -67,18 +213,23 @@ const getPageData = () => {
<div class="data">
<a-card title="用户列表"
><template #extra>
<a-button type="primary" v-per="'user:create'">
<a-button type="primary" v-per="'user:create'" @click="addClick">
<template #icon><plus-outlined /></template>
新增</a-button
>
</template>
<!-- 数据 -->
<a-table :columns="columns" :data-source="dataSource" :pagination="pagination">
<a-table
:columns="columns"
:scroll="{ y: 'calc(100vh - 460px)' }"
:data-source="dataSource"
:pagination="pagination"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<a-tag :color="record.status !== 9 ? 'green' : 'red'">
{{ record.status !== 9 ? '正常' : '已删除' }}
{{ record.status !== 9 ? '正常' : '删除' }}
</a-tag>
</template>
<template v-else-if="column.key === 'created'">
@ -89,10 +240,10 @@ const getPageData = () => {
</template>
<template v-else-if="column.key === 'action'">
<span>
<a v-pre="'user:update'">修改</a>
<a v-per="'user:update'" @click="putClick(record)">编辑</a>
<a-divider type="vertical" />
<template v-if="record.status !== 9">
<a v-per="'user:delete'">删除</a>
<a v-per="'user:delete'" @click="delClick(record)">删除</a>
</template>
</span>
</template>
@ -100,6 +251,65 @@ const getPageData = () => {
</a-table>
</a-card>
</div>
<!-- 新增 用户-->
<a-modal
v-model:visible="addVisible"
title="新建用户"
ok-text="创建"
cancel-text="取消"
@ok="onOk"
@cancel="onCancel"
>
<a-form ref="formRef" :model="newUserForm" :rules="addUserRules">
<a-form-item name="username" label="账号">
<a-input v-model:value="newUserForm.username" placeholder="用于登录" />
</a-form-item>
<a-form-item name="nickname" label="昵称">
<a-input v-model:value="newUserForm.nickname" />
</a-form-item>
<a-form-item name="password" label="密码">
<a-input-password v-model:value="newUserForm.password" autocomplete="on" />
</a-form-item>
<a-form-item name="roles" label="角色">
<a-select
v-model:value="newUserForm.roles"
mode="multiple"
style="width: 100%"
placeholder="默认激活第一个角色"
:options="roleOptions"
></a-select>
</a-form-item>
</a-form>
</a-modal>
<!-- 修改用户 -->
<a-modal
v-model:visible="putVisible"
title="编辑用户"
ok-text="确认"
cancel-text="取消"
@ok="onOkPut"
@cancel="onCancelPut"
>
<a-form ref="putUserFormRef" :model="putUserForm" :rules="putUserRules">
<a-form-item name="nickname" label="昵称">
<a-input v-model:value="putUserForm.nickname" />
</a-form-item>
<a-form-item name="password" label="密码">
<a-input-password v-model:value="putUserForm.password" autocomplete="on" />
</a-form-item>
<a-form-item name="roles" label="角色">
<a-select
v-model:value="putUserForm.roles"
mode="multiple"
style="width: 100%"
placeholder="默认激活第一个角色"
:options="roleOptions"
></a-select>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>