Skip to content

Commit

Permalink
Feat/0.3.2 (#710)
Browse files Browse the repository at this point in the history
  • Loading branch information
zgqgit committed Jun 28, 2024
2 parents 488bf66 + 96a58bd commit 7e93d25
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 44 deletions.
6 changes: 4 additions & 2 deletions src/backend/bisheng/api/services/role_group_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from uuid import UUID

from fastapi.encoders import jsonable_encoder
from fastapi import Request
from fastapi import Request, HTTPException

from bisheng.api.services.assistant import AssistantService
from bisheng.api.services.audit_log import AuditLogService
Expand All @@ -16,7 +16,9 @@
from bisheng.database.models.group import Group, GroupCreate, GroupDao, GroupRead, DefaultGroup
from bisheng.database.models.group_resource import GroupResourceDao, ResourceTypeEnum
from bisheng.database.models.knowledge import KnowledgeDao
from bisheng.database.models.role import AdminRole
from bisheng.database.models.user import User, UserDao
from bisheng.database.models.user_role import UserRoleDao
from bisheng.database.models.user_group import UserGroupCreate, UserGroupDao, UserGroupRead
from loguru import logger

Expand Down Expand Up @@ -141,7 +143,7 @@ def insert_user_group(self, user_group: UserGroupCreate) -> UserGroupRead:
def replace_user_groups(self, request: Request, login_user: UserPayload, user_id: int, group_ids: List[int]):
""" 覆盖用户的所在的用户组 """
# 判断下被操作用户是否是超级管理员
user_role_list = UserRoleDao.get_user_role(user_id)
user_role_list = UserRoleDao.get_user_roles(user_id)
if any(one.role_id == AdminRole for one in user_role_list):
raise HTTPException(status_code=500, detail='系统管理员不允许编辑')

Expand Down
2 changes: 2 additions & 0 deletions src/backend/bisheng/api/v1/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ async def user_addrole(*,
user_role_list = UserRoleDao.get_user_roles(user_role.user_id)
if any(one.role_id == AdminRole for one in user_role_list):
raise HTTPException(status_code=500, detail='系统管理员不允许编辑')
if any(one == AdminRole for one in user_role.role_id):
raise HTTPException(status_code=500, detail='不允许设置为系统管理员')

if not login_user.is_admin():
# 判断拥有哪些用户组的管理权限
Expand Down
6 changes: 3 additions & 3 deletions src/backend/bisheng/database/models/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ class RoleDao(RoleBase):
@classmethod
def get_role_by_groups(cls, group: List[int], keyword: str = None, page: int = 0, limit: int = 0) -> List[Role]:
"""
获取用户组内的角色列表
获取用户组内的角色列表, 不包含系统管理员角色
params:
group: 用户组ID列表
page: 页数
limit: 每页条数
return: 角色列表
"""
statement = select(Role)
statement = select(Role).where(Role.id > AdminRole)
if group:
statement = statement.where(Role.group_id.in_(group))
if keyword:
Expand All @@ -69,7 +69,7 @@ def count_role_by_groups(cls, group: List[int], keyword: str = None) -> int:
"""
统计用户组内的角色数量,参数如上
"""
statement = select(func.count(Role.id))
statement = select(func.count(Role.id)).where(Role.id > AdminRole)
if group:
statement = statement.where(Role.group_id.in_(group))
if keyword:
Expand Down
47 changes: 47 additions & 0 deletions src/frontend/src/components/bs-comp/sheets/TaggingSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
Sheet,
SheetContent,
SheetTitle,
SheetTrigger,
} from "../../bs-ui/sheet";
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';

export default function TaggingSheet({children}) {
const buttons = [
{id:'01',name:'Button01'},
{id:'02',name:'Button02'},
{id:'03',name:'Button03'},
]

return <Sheet>
<SheetTrigger asChild>{children}</SheetTrigger>
<SheetContent className="bg-gray-100 sm:min-w-[800px]">
<SheetTitle>给助手打标签</SheetTitle>
<div className="w-full h-full grid grid-cols-[80%,20%]">
<div className="bg-slate-500">

</div>
<div className="bg-slate-300">
<DragDropContext onDragEnd={() => console.log('-------------')}>
<Droppable droppableId={'list'}>
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{buttons.map((b,index) => (
<Draggable key={'drag' + b.id} draggableId={'drag' + b.id} index={index}>
{(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps}
{...provided.dragHandleProps}>
{b.name}
</div>
)}
</Draggable>
))}
</div>
)}
</Droppable>
</DragDropContext>
</div>
</div>
</SheetContent>
</Sheet>
}
44 changes: 44 additions & 0 deletions src/frontend/src/components/bs-ui/select/select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { ChangeEvent } from "react"
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/bs-ui/select";
import { SearchInput } from "../input";

interface SelectSearchProps {
value: string,
options: {label: string, value: string}[],
selectPlaceholder?:string,
inputPlaceholder?:string,
onOpenChange?: (open:boolean) => void,
onValueChange: (value: string) => void,
onChange: (e:ChangeEvent<HTMLInputElement>) => void,
selectClass?: string,
contentClass?: string
}

const SelectSearch: React.FC<SelectSearchProps> = ({
value,
options,
selectPlaceholder = '',
inputPlaceholder = '',
onOpenChange,
onValueChange,
onChange,
selectClass = '',
contentClass = ''
}) => {
return <Select value={value} onOpenChange={(open) => onOpenChange?.(open)} onValueChange={(v) => onValueChange(v)}>
<SelectTrigger className={selectClass}>
<SelectValue placeholder={selectPlaceholder}/>
</SelectTrigger>
<SelectContent className={contentClass}>
<SearchInput inputClassName="h-8 mb-2" placeholder={inputPlaceholder}
onChange={(e) => onChange(e)} onKeyDown={e => e.stopPropagation()} iconClassName="w-4 h-4" />
<SelectGroup>
{options.map(el => (
<SelectItem key={el.value} value={el.value}>{el.label}</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
}

export default React.memo(SelectSearch)
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import ModelSelect from "./ModelSelect";
import Temperature from "./Temperature";
import { locationContext } from "@/contexts/locationContext";
import { useContext } from "react";
import TaggingSheet from "@/components/bs-comp/sheets/TaggingSheet";

export default function Setting() {
const { t } = useTranslation();
Expand Down Expand Up @@ -303,6 +304,12 @@ export default function Setting() {
</div>
</AccordionContent>
</AccordionItem>
<TaggingSheet>
<PlusIcon
className="mr-2 text-primary hover:text-primary/80"
onClick={(e) => e.stopPropagation()}
></PlusIcon>
</TaggingSheet>
</Accordion>
</div>
);
Expand Down
39 changes: 15 additions & 24 deletions src/frontend/src/pages/SystemPage/components/Roles.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { PlusIcon } from "@/components/bs-icons/plus";
import { bsConfirm } from "@/components/bs-ui/alertDialog/useConfirm";
import { Label } from "@/components/bs-ui/label";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/bs-ui/select";
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Button } from "../../../components/bs-ui/button";
Expand All @@ -19,6 +18,7 @@ import { delRoleApi, getRolesByGroupApi, getUserGroupsApi } from "../../../contr
import { captureAndAlertRequestErrorHoc } from "../../../controllers/request";
import { ROLE } from "../../../types/api/user";
import EditRole from "./EditRole";
import SelectSearch from "@/components/bs-ui/select/select"

interface State {
roles: ROLE[];
Expand Down Expand Up @@ -71,7 +71,7 @@ export default function Roles() {
inputDom.value = '';
}
try {
const data: any = await getRolesByGroupApi('', [state.group]);
const data:any = await getRolesByGroupApi('', [state.group]);
dispatch({ type: 'SET_ROLES', payload: data });
allRolesRef.current = data;
} catch (error) {
Expand All @@ -80,7 +80,7 @@ export default function Roles() {
}, [state.group]);

useEffect(() => {
getUserGroupsApi().then((res: any) => {
getUserGroupsApi().then((res:any) => {
const groups = res.records.map(ug => ({ label: ug.group_name, value: ug.id }))
// 获取最近修改用户组
dispatch({ type: 'SET_GROUP', payload: groups[0].value });
Expand Down Expand Up @@ -142,26 +142,17 @@ export default function Roles() {
<div className="flex justify-between">
<div className="flex items-center">
<Label>{t('system.currentGroup')}</Label>
<Select value={state.group}
onOpenChange={(open) => {
!open && setKeyWord('')
}}
onValueChange={(value) =>
dispatch({ type: 'SET_GROUP', payload: value })
}>
<SelectTrigger className="w-[180px] inline-flex ml-2">
<SelectValue placeholder={t('system.defaultGroup')} />
</SelectTrigger>
<SelectContent className="max-w-[180px] break-all">
<SearchInput inputClassName="h-8 mb-2" placeholder={t('log.selectUserGroup')}
onChange={e => setKeyWord(e.target.value)} onKeyDown={e => e.stopPropagation()} iconClassName="w-4 h-4" />
<SelectGroup>
{options.map(el => (
<SelectItem key={el.value} value={el.value}>{el.label}</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<SelectSearch value={state.group} options={options} selectPlaceholder={t('system.defaultGroup')}
inputPlaceholder={t('log.selectUserGroup')}
selectClass="w-[180px] inline-flex ml-2" contentClass="max-w-[180px] break-all"
onOpenChange={(open) => {
!open && setKeyWord('')
}}
onValueChange={(value) => {
dispatch({ type: 'SET_GROUP', payload: value})
}}
onChange={e => setKeyWord(e.target.value)}
/>
</div>
<div className="flex gap-6 items-center justify-between">
<div className="w-[180px] relative">
Expand All @@ -187,7 +178,7 @@ export default function Roles() {
<TableCell className="font-medium">{el.role_name}</TableCell>
<TableCell>{el.create_time.replace('T', ' ')}</TableCell>
<TableCell className="text-right">
<Button variant="link" disabled={el.id === 1} onClick={() => dispatch({ type: 'SET_ROLE', payload: el })} className="px-0 pl-6">{t('edit')}</Button>
<Button variant="link" onClick={() => dispatch({ type: 'SET_ROLE', payload: el })} className="px-0 pl-6">{t('edit')}</Button>
<Button variant="link" disabled={[1, 2].includes(el.id)} onClick={() => handleDelete(el)} className="text-red-500 px-0 pl-6">{t('delete')}</Button>
</TableCell>
</TableRow>
Expand Down
43 changes: 28 additions & 15 deletions src/frontend/src/pages/SystemPage/components/UserRoleItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,46 @@ import { DelIcon } from "@/components/bs-icons";
import { Button } from "@/components/bs-ui/button";
import MultiSelect from "@/components/bs-ui/select/multi";
import { getRolesByGroupApi, getUserGroupsApi } from "@/controllers/API/user";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import SelectSearch from "@/components/bs-ui/select/select"

export default function UserRoleItem({ showDel, groupId, selectedRoles, onDelete, onChange }:
{ showDel: boolean, groupId: null | string, selectedRoles: any[], onDelete: any, onChange: any }) {
const { t } = useTranslation()

// 用户组
const [groups, setGroups] = useState([])
const groupsRef = useRef([])
const [userGroupSelected, setUserGroupSelected] = useState(groupId ? [groupId] : [])
useEffect(() => {
// 用户组option列表
const loadGroups = () => {
getUserGroupsApi().then((res: any) => {
setGroups(res.records.map((ug) => {
const groups = res.records.map((ug) => {
return {
label: ug.group_name,
value: ug.id.toString()
}
}))
})
setGroups(groups)
groupsRef.current = groups
})
}
useEffect(() => {
// 用户组option列表
loadGroups()
}, [])

const handleSelectGroup = (values) => {
onChange(values, [])
setUserGroupSelected(values);
const handleSelectGroup = (value) => { //单选之后value要改成数组传出去
onChange([value], [])
setUserGroupSelected([value]);
setSelected([])
}
const handleSearch = (e) => {
const keyword = e.target.value
const newGroups = groupsRef.current.filter(g => g.label.toUpperCase().includes(keyword.toUpperCase())
|| g.value === userGroupSelected[0])
setGroups(newGroups)
}

// 角色
const [roles, setRoles] = useState<any[]>([])
Expand All @@ -53,14 +66,14 @@ export default function UserRoleItem({ showDel, groupId, selectedRoles, onDelete
}

return <div className="grid grid-cols-[44%,44%,5%] gap-4">
<MultiSelect
className="max-w-[260px] break-all"
value={userGroupSelected}
<SelectSearch contentClass="max-w-[260px] break-all" selectPlaceholder={t('system.userGroupsSel')}
selectClass="h-[50px]"
value={userGroupSelected[0]}
options={groups}
placeholder={t('system.userGroupsSel')}
onChange={handleSelectGroup}
>
</MultiSelect>
onOpenChange={() => setGroups(groupsRef.current)}
onValueChange={handleSelectGroup}
onChange={handleSearch}
/>
<MultiSelect
multiple
className="max-w-[260px] break-all"
Expand Down

0 comments on commit 7e93d25

Please sign in to comment.