Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified requirements.txt
Binary file not shown.
12 changes: 8 additions & 4 deletions server/crud/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@ def insert(self, db: Session, obj_in):
return obj_in

def update(self, db: Session, db_obj: ModelType, new_obj: ModelType):
# SQLModel直接使用的pydantic的dict方法,没有轮询SQLModel封装的__sqlmodel_relationships__,对于外键的更新,只能手动指定
update_date = new_obj.dict()
"""
使用sqlmodel新函数sqlmodel_update更新
:param db:
:param db_obj:
:param new_obj:
"""
update_date = new_obj.model_dump(exclude_unset=True)
logger.debug(update_date)
for field in update_date:
setattr(db_obj, field, update_date[field])
db_obj.sqlmodel_update(update_date)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
Expand Down
18 changes: 9 additions & 9 deletions server/models/internal/dictonary.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Optional, List, Union
from sqlmodel import SQLModel, Field, Relationship, Column, Boolean, Integer
from sqlmodel import SQLModel, Field, Relationship, Column, Boolean, Integer, String


class DataDictBase(SQLModel):
name: str = Field(max_length=50, sa_column_kwargs={'comment': '字典名称'})
code: str = Field(max_length=100, sa_column_kwargs={'comment': '字典编号'})
desc: Optional[str] = Field(max_length=100, sa_column_kwargs={'comment': '描述'})
name: str = Field(sa_column=Column(String(50), nullable=False, comment='字典名称'))
code: str = Field(sa_column=Column(String(100), nullable=False, comment='字典编号'))
desc: Optional[str] = Field(sa_column=Column(String(100), default=None, comment='描述'))


class DataDict(DataDictBase, table=True):
Expand All @@ -20,11 +20,11 @@ class DataDictSearch(SQLModel):


class DictBase(SQLModel):
label: str = Field(max_length=50, sa_column_kwargs={'comment': '名称'})
value: str = Field(max_length=100, sa_column_kwargs={'comment': '数据值'})
desc: Optional[str] = Field(max_length=100, sa_column_kwargs={'comment': '描述'})
sort: Optional[int] = Field(default=1, sa_column_kwargs={'comment': '排序值,越小越靠前'})
enable: bool = Field(default=True, sa_column=Column(Boolean, comment='是否启用'))
label: str = Field(sa_column=Column(String(50), nullable=False, comment='名称'))
value: str = Field(sa_column=Column(String(100), nullable=False, comment='数据值'))
desc: Optional[str] = Field(sa_column=Column(String(100), default=None, comment='描述'))
sort: Optional[int] = Field(sa_column=Column(Integer, default=1, comment='排序值,越小越靠前'))
enable: bool = Field(sa_column=Column(Boolean, default=True, comment='是否启用'))
dict_id: Optional[int] = Field(foreign_key="data_dict.id")


Expand Down
20 changes: 10 additions & 10 deletions server/models/internal/menu.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
from typing import Optional, List
from sqlmodel import SQLModel, Field, Relationship, Column, Boolean, Integer
from sqlmodel import SQLModel, Field, Relationship, Column, Boolean, Integer, String, Float
from .relationships import RoleMenu


class MenuBase(SQLModel):
id: Optional[int] = Field(sa_column=Column('id', Integer, primary_key=True, autoincrement=True))
name: str = Field(max_length=20, sa_column_kwargs={'comment': '菜单名'})
icon: Optional[str] = Field(default=None, max_length=50, sa_column_kwargs={'comment': 'Icon图标'})
path: Optional[str] = Field(max_length=100, sa_column_kwargs={'comment': '路径'})
component: Optional[str] = Field(max_length=50, sa_column_kwargs={'comment': '组件'})
auth: Optional[str] = Field(max_length=50, sa_column_kwargs={'comment': '授权标识'})
type: str = Field(max_length=10, sa_column_kwargs={'comment': '类型'})
parent_id: Optional[int] = Field(default=None, sa_column_kwargs={'comment': '父级ID'})
sort: Optional[float] = Field(default=None, sa_column_kwargs={'comment': '菜单排序'})
enable: bool = Field(default=True, sa_column=Column(Boolean, comment='启用'))
name: str = Field(sa_column=Column(String(20), nullable=False, comment='菜单名'))
icon: Optional[str] = Field(sa_column=Column(String(50), default=None, comment='Icon图标'))
path: Optional[str] = Field(sa_column=Column(String(100), default=None, comment='路径'))
component: Optional[str] = Field(sa_column=Column(String(50), default=None, comment='组件'))
auth: Optional[str] = Field(sa_column=Column(String(50), default=None, comment='授权标识'))
type: str = Field(sa_column=Column(String(10), nullable=False, comment='类型'))
parent_id: Optional[int] = Field(sa_column=Column(Integer, default=None, comment='父级ID'))
sort: Optional[float] = Field(sa_column=Column(Float, default=None, comment='菜单排序'))
enable: bool = Field(sa_column=Column(Boolean, default=True, comment='启用'))


class Menu(MenuBase, table=True):
Expand Down
19 changes: 11 additions & 8 deletions server/models/internal/role.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
from typing import Optional, List, TYPE_CHECKING, Union
from sqlmodel import SQLModel, Field, Relationship, Column, Integer, Boolean
from sqlmodel import SQLModel, Field, Relationship, Column, Integer, Boolean, String
from .relationships import RoleMenu, UserRole

if TYPE_CHECKING:
from .user import User
from .menu import Menu


class RoleBase(SQLModel):
name: Union[str, None] = Field(max_length=20, default=None, sa_column_kwargs={'unique': True, 'comment': '角色名'})
description: Union[str, None] = Field(max_length=100, default=None, sa_column_kwargs={'comment': '描述'})
enable: Union[bool, None] = Field(default=True, sa_column=Column(Boolean, comment='启用'))


class Role(RoleBase, table=True):
class Role(SQLModel, table=True):
__tablename__ = "roles"
id: Optional[int] = Field(sa_column=Column('id', Integer, primary_key=True, autoincrement=True))
name: Union[str, None] = Field(sa_column=Column(String(20), nullable=False, unique=True, comment='角色名'))
description: Union[str, None] = Field(sa_column=Column(String(100), default=None, comment='描述'))
enable: Union[bool, None] = Field(sa_column=Column(Boolean, default=True, comment='启用'))
menus: List["Menu"] = Relationship(back_populates="roles", link_model=RoleMenu)
users: List["User"] = Relationship(back_populates="roles", link_model=UserRole)


class RoleBase(SQLModel):
name: Union[str, None] = Field(max_length=20, nullable=False)
description: Union[str, None] = Field(max_length=100, default=None)
enable: Union[bool, None] = Field(default=True)


class RoleInsert(RoleBase):
menus: List[int]

Expand Down
30 changes: 18 additions & 12 deletions server/models/internal/user.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional, List, Union, Literal, TYPE_CHECKING
from pydantic import BaseModel
from sqlmodel import SQLModel, Field, Relationship, Column, Integer, Boolean
from sqlmodel import SQLModel, Field, Relationship, Column, Integer, Boolean, String
from .relationships import UserRole, UserJob
from .role import Role

Expand All @@ -9,15 +9,27 @@
from .job import Job


class User(SQLModel, table=True):
__tablename__ = 'user'
id: Optional[int] = Field(sa_column=Column('id', Integer, primary_key=True, autoincrement=True))
name: Union[str, None] = Field(sa_column=Column(String(20), nullable=False, unique=True, comment='用户名'))
enable: Union[bool, None] = Field(sa_column=Column(Boolean, default=True, comment='可用'))
avatar: Union[str, None] = Field(sa_column=Column(String(100), default=None, comment='头像'))
email: Union[str, None] = Field(sa_column=Column(String(20), default=None, comment='邮箱'))
password: Optional[str] = Field(sa_column=Column(String(50), comment='密码'))
roles: List['Role'] = Relationship(back_populates="users", link_model=UserRole)
jobs: List['Job'] = Relationship(back_populates="user", link_model=UserJob)


class UserWithOutPasswd(SQLModel):
name: Union[str, None] = Field(max_length=20, default=None, sa_column_kwargs={'unique': True, 'comment': '用户名'})
enable: Union[bool, None] = Field(default=True, sa_column=Column(Boolean, comment='可用'))
avatar: Union[str, None] = Field(max_length=100, default=None, sa_column_kwargs={'comment': '头像'})
email: Union[str, None] = Field(max_length=20, default=None, sa_column_kwargs={'comment': '邮箱'})
name: Union[str, None] = Field(max_length=20, nullable=False)
enable: Union[bool, None] = Field(default=True)
avatar: Union[str, None] = Field(max_length=100, default=None)
email: Union[str, None] = Field(max_length=20, default=None)


class UserBase(UserWithOutPasswd):
password: Optional[str] = Field(max_length=50, sa_column_kwargs={'comment': '密码'})
password: Optional[str] = Field(sa_column=Column(String(50), comment='密码'))
# age: Optional[int] = Field(..., title='年龄', lt=120)


Expand All @@ -36,12 +48,6 @@ class UserRoles(SQLModel):
enable: List[str] = []


class User(UserBase, table=True):
id: Optional[int] = Field(sa_column=Column('id', Integer, primary_key=True, autoincrement=True))
roles: List['Role'] = Relationship(back_populates="users", link_model=UserRole)
jobs: List['Job'] = Relationship(back_populates="user", link_model=UserJob)


class UserCreateWithRoles(SQLModel):
# POST请求时,传递过来的模型
user: UserBase
Expand Down
15 changes: 15 additions & 0 deletions server/routers/internal/host.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Optional, List
from fastapi import APIRouter, Depends, status, HTTPException
from sqlmodel import Session
from server.models.internal.host import CreateGroup
from ...common.response_code import ApiResponse, SearchResponse
from ...common.database import get_session
from ... import crud

router = APIRouter(prefix='/api')


@router.post('/host/group', summary='添加主机分组')
async def create_group(group: CreateGroup, session: Session = Depends(get_session)):
crud.internal.group.insert(session, group)
return ApiResponse()
8 changes: 4 additions & 4 deletions www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
"axios": "^1.6.2",
"core-js": "^3.34.0",
"echarts": "^5.4.2",
"element-plus": "^2.5.3",
"element-plus": "^2.5.6",
"js-base64": "^3.7.5",
"js-cookie": "^3.0.5",
"jsonref": "^8.0.8",
"pinia": "2.1.7",
"vue": "^3.4.3",
"vue": "^3.4.19",
"vue-draggable-plus": "^0.3.5",
"vue-echarts": "^6.6.5",
"vue-router": "^4.2.5",
"vue-router": "^4.3.0",
"xterm": "^5.3.0",
"xterm-addon-attach": "^0.9.0",
"xterm-addon-fit": "^0.8.0"
Expand All @@ -35,7 +35,7 @@
"unocss": "^0.58.3",
"unplugin-auto-import": "^0.17.2",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.0.10",
"vite": "^5.1.4",
"vite-plugin-dynamic-import": "^1.5.0"
},
"eslintConfig": {
Expand Down
9 changes: 5 additions & 4 deletions www/src/components/MenuList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
<el-menu-item index="/dashboard">首页</el-menu-item>
<template v-for="item in menuList" :key="item.name">
<!-- 有子菜单时处理逻辑 -->
<el-sub-menu v-if="item.children" :index="item.path">
<el-sub-menu v-if="item.children.length>0" :index="item.path">
<template #title>
<el-icon v-if="item.icon">
<component :is="item.icon"/>
</el-icon>
<span>{{ item.name }}</span>
</template>
<template v-if="item.children">
<el-menu-item v-for="(children,index) in item.children" :key="index" :index="item.path + '/' + children.path">
<template v-if="item.children.length >0">
<el-menu-item v-for="(children,index) in item.children" :key="index"
:index="'/'+item.path + '/' + children.path">
<el-icon v-if="children.icon">
<component :is="children.icon"/>
</el-icon>
Expand All @@ -31,7 +32,7 @@
</template>
</el-sub-menu>
<!-- 无子菜单时处理逻辑 -->
<el-menu-item v-else :index="item.path" @click="handleOpen">
<el-menu-item v-else :index="'/'+item.path">
<el-icon v-if="item.icon">
<component :is="item.icon"/>
</el-icon>
Expand Down
108 changes: 54 additions & 54 deletions www/src/permission.js
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
import router from './router';
import { useStore } from './stores';
import router from './router'
import {useStore} from './stores'
import {
getToken
} from '@/utils/auth';
getToken
} from '@/utils/auth'
import {
makeRouter
} from "@/utils/router";
makeRouter
} from '@/utils/router'
import {useTabsStore} from '@/stores/tabs'



const whiteList = ['/login'] // no redirect whitelist

router.beforeEach((to) => {
const store = useStore()
const {tabAdd} = useTabsStore()
console.log('start before each')
router.beforeEach(async (to) => {
const store = useStore()
const {tabAdd} = useTabsStore()
console.log('start before each', to)

if (getToken()) {
console.log('已经有token')
// 已登录且要跳转的页面是登录页
if (to.path === '/login') {
return '/'
} else {
console.log('已经登录成功')
//登录成功,需要判断router是不是已经按照权限要求构建好,并且菜单是否按照权限要求生成,如没有,则生成
// router.push('/')
if (store.asyncRoutes.length === 0) {
console.log('asyncroutes is not set')
store.getInfo().then(() => {
return store.getPermission()
}).then(() => {
let asyncRoutes = makeRouter(store.asyncRoutes)
for (let route of asyncRoutes) {
console.log('add route:')
console.log(route)
router.addRoute(route)
}
return { path: to.fullPath, replace: true }
}).catch((err) => {
console.log('用户权限拉取失败' + err);
store.logOut().then(() => {
location.reload()
})
})
}
console.log('当前生效路由表')
console.log(router.getRoutes())
tabAdd(to)
return true
if (getToken()) {
console.log('已经有token')
// 已登录且要跳转的页面是登录页
if (to.path === '/login') {
return '/'
} else {
console.log('已经登录成功')
//登录成功,需要判断router是不是已经按照权限要求构建好,并且菜单是否按照权限要求生成,如没有,则生成
// router.push('/')
if (store.asyncRoutes.length === 0) {
console.log('asyncroutes is not set')
try {
await store.getInfo()
await store.getPermission()
let asyncRoutes = await makeRouter(store.asyncRoutes)
console.log(asyncRoutes)
for (let route of asyncRoutes) {
console.log('add route:')
console.log(route)
router.addRoute('home', route)
}
return {path: to.fullPath, replace: true}
} catch (e) {
console.log('用户权限拉取失败' + e)
store.logOut().then(() => {
location.reload()
})
}
}
console.log('当前生效路由表')
console.log(router.getRoutes())
tabAdd(to)
return true

}
} else {
// 无token信息,表示未登录
console.log('无token信息')
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
return true
} else {
// return true
router.push(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
}
}
}
} else {
// 无token信息,表示未登录
console.log('无token信息')
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
return true
} else {
// return true
router.push(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
}
}
})
1 change: 1 addition & 0 deletions www/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const constantRouterMap = [
path: '/',
name: 'home',
component: () => import('@/views/Layout'),
children: []
},
{
path: '/dashboard',
Expand Down
Loading