fix: 添加角色增加菜单id”
This commit is contained in:
parent
65f1d7d2bc
commit
7ba3f23684
@ -1,6 +1,7 @@
|
|||||||
from fastapi import Query
|
from fastapi import Query
|
||||||
|
|
||||||
from dbhelper.menu import del_menu, get_menus, insert_menu, put_menu
|
from core.utils import list_to_tree
|
||||||
|
from dbhelper.menu import del_menu, get_menus, get_tree_menu, insert_menu, put_menu
|
||||||
from schemas import ListAll, MenuIn, MenuRead, Response
|
from schemas import ListAll, MenuIn, MenuRead, Response
|
||||||
|
|
||||||
|
|
||||||
@ -11,10 +12,9 @@ async def menu_add(data: MenuIn) -> Response[MenuRead]:
|
|||||||
async def menu_arr(
|
async def menu_arr(
|
||||||
offset: int = Query(default=1, description="偏移量"),
|
offset: int = Query(default=1, description="偏移量"),
|
||||||
limit: int = Query(default=10, description="数量"),
|
limit: int = Query(default=10, description="数量"),
|
||||||
) -> Response[ListAll[list[MenuRead]]]:
|
) -> Response:
|
||||||
skip = (offset - 1) * limit
|
menus = await get_tree_menu()
|
||||||
menus, count = await get_menus(skip, limit)
|
return Response(data=list_to_tree(menus))
|
||||||
return Response(data=ListAll(total=count, items=menus))
|
|
||||||
|
|
||||||
|
|
||||||
async def menu_del(pk: int) -> Response:
|
async def menu_del(pk: int) -> Response:
|
||||||
|
@ -16,7 +16,9 @@ from schemas import ListAll, Response, RoleIn, RoleInfo, RoleMenuIn, RoleQuery,
|
|||||||
|
|
||||||
|
|
||||||
async def role_add(data: RoleIn) -> Response[RoleInfo]:
|
async def role_add(data: RoleIn) -> Response[RoleInfo]:
|
||||||
return Response(data=await new_role(data))
|
if result := await new_role(data):
|
||||||
|
return Response(data=result)
|
||||||
|
return Response(code=400, msg="菜单不存在")
|
||||||
|
|
||||||
|
|
||||||
async def role_has_menu(rid: int):
|
async def role_has_menu(rid: int):
|
||||||
|
@ -19,10 +19,10 @@ async def user_add(data: UserAdd) -> Response[UserRead]:
|
|||||||
"""新增用户并分配角色 一步到位"""
|
"""新增用户并分配角色 一步到位"""
|
||||||
if await get_user({"username": data.username}) is not None:
|
if await get_user({"username": data.username}) is not None:
|
||||||
return Response(code=400, msg="用户名已存在")
|
return Response(code=400, msg="用户名已存在")
|
||||||
roles = data.rids
|
rids = data.roles
|
||||||
del data.rids
|
del data.roles
|
||||||
data.password = get_password_hash(data.password)
|
data.password = get_password_hash(data.password)
|
||||||
result = await insert_user(data, roles)
|
result = await insert_user(data, rids)
|
||||||
if isinstance(result, int):
|
if isinstance(result, int):
|
||||||
return Response(code=400, msg=f"角色{result}不存在")
|
return Response(code=400, msg=f"角色{result}不存在")
|
||||||
return Response(data=result)
|
return Response(data=result)
|
||||||
|
@ -25,7 +25,11 @@ async def get_menus(skip: int, limit: int, kwargs: dict = None):
|
|||||||
else:
|
else:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
result = MenuModel.filter(status__not=9, **kwargs).all().order_by("-created")
|
result = MenuModel.filter(status__not=9, **kwargs).all().order_by("-created")
|
||||||
return await result.offset(skip).limit(limit), await result.count()
|
return await result.offset(skip).limit(limit)
|
||||||
|
|
||||||
|
|
||||||
|
async def get_tree_menu():
|
||||||
|
return await MenuModel.filter(status__not=9).all().values()
|
||||||
|
|
||||||
|
|
||||||
async def get_menu(kwargs):
|
async def get_menu(kwargs):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from tortoise import connections
|
from tortoise import connections
|
||||||
|
|
||||||
from models import RoleModel
|
from models import MenuModel, RoleMenuModel, RoleModel
|
||||||
from schemas.role import RoleIn
|
from schemas.role import RoleIn
|
||||||
|
|
||||||
|
|
||||||
@ -20,7 +20,16 @@ async def get_role_menus(rid: int):
|
|||||||
|
|
||||||
async def new_role(role: RoleIn):
|
async def new_role(role: RoleIn):
|
||||||
"""新增角色"""
|
"""新增角色"""
|
||||||
return await RoleModel.create(**role.dict())
|
# 校验菜单是否存在
|
||||||
|
if not all([await MenuModel.filter(id=mid).first() for mid in role.menus]):
|
||||||
|
return False
|
||||||
|
|
||||||
|
obj = await RoleModel.create(name=role.name, remark=role.remark)
|
||||||
|
# 写入菜单
|
||||||
|
await RoleMenuModel.bulk_create(
|
||||||
|
[RoleMenuModel(rid=obj.id, mid=mid) for mid in role.menus]
|
||||||
|
)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
async def get_roles(skip: int, limit: int, kwargs: dict = None):
|
async def get_roles(skip: int, limit: int, kwargs: dict = None):
|
||||||
|
@ -32,19 +32,9 @@ async def get_user_info(user: UserModel):
|
|||||||
[user.id],
|
[user.id],
|
||||||
)
|
)
|
||||||
|
|
||||||
# 当前激活角色的按钮权限列表
|
|
||||||
perm_result = await db.execute_query_dict(
|
|
||||||
"""
|
|
||||||
select m.identifier from sys_role_menu as rm, sys_menu as m where rm.mid = m.id and rm.rid = (?) and
|
|
||||||
m.identifier not null and m.identifier != "" and rm.status != 9
|
|
||||||
""",
|
|
||||||
[sql_result[0]["id"]],
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
**jsonable_encoder(user),
|
**jsonable_encoder(user),
|
||||||
"roles": sql_result,
|
"roles": sql_result,
|
||||||
"permissions": [i["identifier"] for i in perm_result],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -64,7 +54,6 @@ async def get_users(skip: int, limit: int, kwargs: dict = None):
|
|||||||
else:
|
else:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
result = UserModel.filter(**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()
|
return await result.offset(skip).limit(limit), await result.count()
|
||||||
|
|
||||||
|
|
||||||
|
BIN
backend/mini.db
BIN
backend/mini.db
Binary file not shown.
BIN
backend/mini.db-shm
Normal file
BIN
backend/mini.db-shm
Normal file
Binary file not shown.
BIN
backend/mini.db-wal
Normal file
BIN
backend/mini.db-wal
Normal file
Binary file not shown.
@ -20,7 +20,7 @@ class RoleBasic(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class RoleIn(RoleBasic):
|
class RoleIn(RoleBasic):
|
||||||
pass
|
menus: list[int] = Field(..., description="菜单id列表")
|
||||||
|
|
||||||
|
|
||||||
class RoleRead(RoleBasic, ReadBase):
|
class RoleRead(RoleBasic, ReadBase):
|
||||||
|
@ -41,7 +41,6 @@ class UserInfo(UserRead):
|
|||||||
"""用户信息模型"""
|
"""用户信息模型"""
|
||||||
|
|
||||||
roles: list[UserHasRole] = Field(..., description="用户拥有角色")
|
roles: list[UserHasRole] = Field(..., description="用户拥有角色")
|
||||||
permissions: list[str] = Field(..., description="角色拥有的按钮权限标识")
|
|
||||||
|
|
||||||
|
|
||||||
class RoleActive(BaseModel):
|
class RoleActive(BaseModel):
|
||||||
@ -52,7 +51,7 @@ class RoleActive(BaseModel):
|
|||||||
class UserAdd(UserIn):
|
class UserAdd(UserIn):
|
||||||
"""新增用户模型"""
|
"""新增用户模型"""
|
||||||
|
|
||||||
rids: list[RoleActive] = Field(..., description="选择角色列表")
|
roles: list[RoleActive] = Field(..., description="选择角色列表")
|
||||||
|
|
||||||
|
|
||||||
class UserQuery(QueryData):
|
class UserQuery(QueryData):
|
||||||
|
0
frontend/src/stores/menu.js
Normal file
0
frontend/src/stores/menu.js
Normal file
0
frontend/src/stores/role.js
Normal file
0
frontend/src/stores/role.js
Normal file
@ -3,7 +3,7 @@ import { defineStore } from 'pinia'
|
|||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { loadRouter, loadDefaultMenu } from '@/utils/loadCpn'
|
import { loadRouter, getPermissions } from '@/utils/loadCpn'
|
||||||
import { getMenus, getUserInfo, login, selectRole } from '@/service/user'
|
import { getMenus, getUserInfo, login, selectRole } from '@/service/user'
|
||||||
|
|
||||||
export const userStore = defineStore(
|
export const userStore = defineStore(
|
||||||
@ -12,6 +12,7 @@ export const userStore = defineStore(
|
|||||||
const token = ref('')
|
const token = ref('')
|
||||||
const userInfo = ref({})
|
const userInfo = ref({})
|
||||||
const userMenus = ref([])
|
const userMenus = ref([])
|
||||||
|
const permissions = ref([])
|
||||||
|
|
||||||
const selectKey = ref(null)
|
const selectKey = ref(null)
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ export const userStore = defineStore(
|
|||||||
token.value = ''
|
token.value = ''
|
||||||
userInfo.value = {}
|
userInfo.value = {}
|
||||||
userMenus.value = []
|
userMenus.value = []
|
||||||
|
permissions.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,16 +43,19 @@ export const userStore = defineStore(
|
|||||||
const menus = await getMenus(info.data.roles[0].id)
|
const menus = await getMenus(info.data.roles[0].id)
|
||||||
userMenus.value = menus.data
|
userMenus.value = menus.data
|
||||||
|
|
||||||
// 3.1 加载权限
|
// 3.1 加载路由权限
|
||||||
loadRouter(menus.data)
|
loadRouter(menus.data)
|
||||||
|
|
||||||
// 3.2 默认跳转路由
|
// 3.2 加载按钮权限
|
||||||
const defaultMenu = loadDefaultMenu(menus.data)
|
const [btnPermissions, firstMenu] = getPermissions(menus.data)
|
||||||
|
permissions.value = btnPermissions
|
||||||
|
|
||||||
selectKey.value = [defaultMenu.id]
|
// 3.2 默认打开菜单
|
||||||
// 4. 跳转
|
selectKey.value = [firstMenu.id]
|
||||||
if (defaultMenu.path) {
|
|
||||||
router.push(defaultMenu.path)
|
// 4. 跳转路由
|
||||||
|
if (firstMenu?.path) {
|
||||||
|
router.push(firstMenu.path)
|
||||||
} else {
|
} else {
|
||||||
router.push('/main')
|
router.push('/main')
|
||||||
}
|
}
|
||||||
@ -82,6 +87,7 @@ export const userStore = defineStore(
|
|||||||
accessToken,
|
accessToken,
|
||||||
userInfo,
|
userInfo,
|
||||||
userMenus,
|
userMenus,
|
||||||
|
permissions,
|
||||||
isLoading,
|
isLoading,
|
||||||
selectKey,
|
selectKey,
|
||||||
$reset,
|
$reset,
|
||||||
|
@ -6,7 +6,7 @@ export default (app) => {
|
|||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
if (
|
if (
|
||||||
// 是否存在
|
// 是否存在
|
||||||
userStore().userInfo.permissions.indexOf(binding.value) === -1
|
userStore().permissions.indexOf(binding.value) === -1
|
||||||
) {
|
) {
|
||||||
// 删除元素
|
// 删除元素
|
||||||
el.parentNode && el.parentNode.removeChild(el)
|
el.parentNode && el.parentNode.removeChild(el)
|
||||||
|
@ -35,11 +35,26 @@ function loadRouter(menus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认打开第一个
|
// 获取按钮权限列表,和第一个选中菜单
|
||||||
function loadDefaultMenu(menus) {
|
function getPermissions(menuArr) {
|
||||||
for (const menu of menus) {
|
let arr = []
|
||||||
return menu.children.find((e) => e.type === 1)
|
let firstMenu = null
|
||||||
|
|
||||||
|
function _forMenu(menus) {
|
||||||
|
for (const menu of menus) {
|
||||||
|
if (menu.type === 1 && firstMenu === null) {
|
||||||
|
firstMenu = menu
|
||||||
|
}
|
||||||
|
if (menu.type !== 2 && menu.children) {
|
||||||
|
_forMenu(menu.children)
|
||||||
|
} else {
|
||||||
|
arr.push(menu.identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_forMenu(menuArr)
|
||||||
|
return [arr.filter((e) => e !== null), firstMenu]
|
||||||
}
|
}
|
||||||
|
|
||||||
export { loadIconCpn, loadRouter, loadDefaultMenu }
|
export { loadIconCpn, loadRouter, getPermissions }
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
import { PlusOutlined } from '@ant-design/icons-vue'
|
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
import { columns } from './conf'
|
import { columns } from './conf'
|
||||||
import { formatTime } from '@/utils/format'
|
import { formatTime } from '@/utils/format'
|
||||||
import { userStore } from '@/stores/user'
|
|
||||||
import { loadIconCpn } from '@/utils/loadCpn'
|
import { loadIconCpn } from '@/utils/loadCpn'
|
||||||
|
import { getMenus } from '@/service/menu'
|
||||||
|
|
||||||
// 列表数据
|
// 列表数据
|
||||||
const dataSource = userStore().userMenus
|
const dataSource = ref([])
|
||||||
|
|
||||||
|
getMenus().then((res) => (dataSource.value = res.data))
|
||||||
|
|
||||||
// 菜单类型隐射
|
// 菜单类型隐射
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ export const addRoleRules = [
|
|||||||
remark: [
|
remark: [
|
||||||
{ required: true, message: '请输入描述', trigger: 'blur' },
|
{ required: true, message: '请输入描述', trigger: 'blur' },
|
||||||
{ min: 1, max: 20, message: '1~20', trigger: 'blur' }
|
{ min: 1, max: 20, message: '1~20', trigger: 'blur' }
|
||||||
]
|
],
|
||||||
|
menus: [{ required: true, message: '请选择菜单', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4,6 +4,7 @@ import { ref, reactive, onMounted } from 'vue'
|
|||||||
import { PlusOutlined } from '@ant-design/icons-vue'
|
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
import { getRoles, queryRole, delRole, putRole, addRole } from '@/service/role'
|
import { getRoles, queryRole, delRole, putRole, addRole } from '@/service/role'
|
||||||
|
import { getMenus } from '@/service/menu'
|
||||||
import { columns, addRoleRules } from './conf'
|
import { columns, addRoleRules } from './conf'
|
||||||
import { formatTime } from '@/utils/format'
|
import { formatTime } from '@/utils/format'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
@ -81,17 +82,22 @@ const addVisible = ref(false)
|
|||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
const newRoleForm = reactive({
|
const newRoleForm = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
remark: ''
|
remark: '',
|
||||||
|
menus: []
|
||||||
})
|
})
|
||||||
|
|
||||||
const addClick = () => {
|
const addClick = () => {
|
||||||
addVisible.value = !addVisible.value
|
addVisible.value = !addVisible.value
|
||||||
|
// 弹出modal 并获取菜单树
|
||||||
|
getMenus().then((res) => (treeData.value = res.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增modal 确定的回调
|
// 新增modal 确定的回调
|
||||||
const onOk = () => {
|
const onOk = () => {
|
||||||
formRef.value.validateFields().then(() => {
|
formRef.value.validateFields().then(() => {
|
||||||
// 表单验证通过
|
// 表单验证通过
|
||||||
|
console.log(newRoleForm.menus)
|
||||||
|
newRoleForm.menus = newRoleForm.menus.map((e) => e.id)
|
||||||
addRole(newRoleForm).then((res) => {
|
addRole(newRoleForm).then((res) => {
|
||||||
if (res.msg === '请求成功') {
|
if (res.msg === '请求成功') {
|
||||||
message.success('新增成功')
|
message.success('新增成功')
|
||||||
@ -116,10 +122,14 @@ const onCancel = () => {
|
|||||||
|
|
||||||
const putClick = (record) => {
|
const putClick = (record) => {
|
||||||
// 打开编辑的modal
|
// 打开编辑的modal
|
||||||
|
getMenus().then((res) => (treeData.value = res.data))
|
||||||
|
|
||||||
putVisible.value = !putVisible.value
|
putVisible.value = !putVisible.value
|
||||||
putId.value = record.id
|
putId.value = record.id
|
||||||
putRoleForm.name = record.name
|
putRoleForm.name = record.name
|
||||||
putRoleForm.remark = record.remark
|
putRoleForm.remark = record.remark
|
||||||
|
|
||||||
|
console.log(record)
|
||||||
}
|
}
|
||||||
|
|
||||||
const putVisible = ref(false)
|
const putVisible = ref(false)
|
||||||
@ -127,7 +137,8 @@ const putVisible = ref(false)
|
|||||||
const putRoleFormRef = ref()
|
const putRoleFormRef = ref()
|
||||||
const putRoleForm = reactive({
|
const putRoleForm = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
remark: ''
|
remark: '',
|
||||||
|
menus: []
|
||||||
})
|
})
|
||||||
const putId = ref()
|
const putId = ref()
|
||||||
|
|
||||||
@ -153,6 +164,15 @@ const onOkPut = () => {
|
|||||||
const onCancelPut = () => {
|
const onCancelPut = () => {
|
||||||
putRoleFormRef.value.resetFields()
|
putRoleFormRef.value.resetFields()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tree
|
||||||
|
const treeData = ref()
|
||||||
|
|
||||||
|
// 获取选中的菜单
|
||||||
|
const check = (key, { checkedNodesPositions }) => {
|
||||||
|
// console.log(checkedNodesPositions)
|
||||||
|
newRoleForm.menus = checkedNodesPositions.map((e) => ({ key: e.pos, id: e.node.id }))
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -172,7 +192,7 @@ const onCancelPut = () => {
|
|||||||
|
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<div class="data">
|
<div class="data">
|
||||||
<a-card title="用户列表"
|
<a-card title="角色列表"
|
||||||
><template #extra>
|
><template #extra>
|
||||||
<a-button type="primary" v-per="'role:create'" @click="addClick">
|
<a-button type="primary" v-per="'role:create'" @click="addClick">
|
||||||
<template #icon><plus-outlined /></template>
|
<template #icon><plus-outlined /></template>
|
||||||
@ -229,6 +249,11 @@ const onCancelPut = () => {
|
|||||||
<a-form-item name="remark" label="描述">
|
<a-form-item name="remark" label="描述">
|
||||||
<a-input v-model:value="newRoleForm.remark" />
|
<a-input v-model:value="newRoleForm.remark" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item name="menus" label="菜单">
|
||||||
|
<a-tree checkable :tree-data="treeData" @check="check">
|
||||||
|
<template #title="{ name }"> {{ name }} </template>
|
||||||
|
</a-tree>
|
||||||
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
@ -248,6 +273,11 @@ const onCancelPut = () => {
|
|||||||
<a-form-item name="remark" label="描述">
|
<a-form-item name="remark" label="描述">
|
||||||
<a-input v-model:value="putRoleForm.remark" />
|
<a-input v-model:value="putRoleForm.remark" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item name="menus" label="菜单">
|
||||||
|
<a-tree checkable :tree-data="treeData" @check="check">
|
||||||
|
<template #title="{ name }"> {{ name }} </template>
|
||||||
|
</a-tree>
|
||||||
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
|
@ -106,9 +106,8 @@ const addClick = () => {
|
|||||||
const onOk = () => {
|
const onOk = () => {
|
||||||
formRef.value.validateFields().then(() => {
|
formRef.value.validateFields().then(() => {
|
||||||
// 表单验证通过
|
// 表单验证通过
|
||||||
const { username, nickname, password, roles } = newUserForm
|
newUserForm.roles = newUserForm.roles.map((e, i) => ({ rid: e, status: i === 0 ? 5 : 1 }))
|
||||||
let rids = roles.map((e, i) => ({ rid: e, status: i === 0 ? 5 : 1 }))
|
addUser(newUserForm).then((res) => {
|
||||||
addUser({ username, nickname, password, rids }).then((res) => {
|
|
||||||
if (res.msg === '请求成功') {
|
if (res.msg === '请求成功') {
|
||||||
message.success('新增成功')
|
message.success('新增成功')
|
||||||
// 1. 关闭 modal
|
// 1. 关闭 modal
|
||||||
|
Loading…
Reference in New Issue
Block a user