feat: user admin add
This commit is contained in:
parent
dbc3885f9f
commit
293f3ba937
@ -84,9 +84,9 @@
|
||||
methods: {
|
||||
// ok
|
||||
ok: function() {
|
||||
sa.ajax2('/user/add', function(res) {
|
||||
sa.alert('数据添加, 参数为:' + JSON.stringify(this.m));
|
||||
}.bind(this))
|
||||
sa.ajax('/user/admin/add', this.m, function(res) {
|
||||
sa.alert('数据添加成功');
|
||||
}.bind(this), {})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -113,7 +113,7 @@
|
||||
<el-table-column prop="address" label="操作">
|
||||
<template slot-scope="s">
|
||||
<el-button class="c-btn" type="success" icon="el-icon-view" @click="get(s.row)">详情</el-button>
|
||||
<el-button class="c-btn" type="danger" icon="el-icon-delete" @click="del(s.row)">禁用</el-button>
|
||||
<el-button class="c-btn" type="danger" icon="el-icon-delete" @click="del(s.row)">禁/启用</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -165,6 +165,7 @@
|
||||
sa.ajax('/user/admin/list', this.p, function(res){
|
||||
this.dataList = res.data.data; // 数据
|
||||
for (let i = 0; i < this.dataList.length; i++) {
|
||||
this.dataList[i].avatar = this.dataList[i].avatar ? this.dataList[i].avatar : '/user/avatar/default';
|
||||
this.dataList[i].status = this.dataList[i].is_active ? 1 : 0;
|
||||
}
|
||||
this.dataCount = res.data.count; // 分页
|
||||
@ -202,12 +203,16 @@
|
||||
},
|
||||
// 删除
|
||||
del: function(data) {
|
||||
sa.confirm('是否删除,此操作不可撤销', function() {
|
||||
sa.ajax2('/user/delete?id=' + data.id, function(res) {
|
||||
sa.arrayDelete(this.dataList, data);
|
||||
sa.ok('删除成功');
|
||||
sa.f5TableHeight(); // 刷新表格高度
|
||||
}.bind(this))
|
||||
sa.confirm('是否修改,此操作可撤销', function() {
|
||||
sa.ajax('/user/admin/change_status', {user_id: data.id, is_active: !data.is_active}, function(res) {
|
||||
// sa.arrayDelete(this.dataList, data);
|
||||
if (data.is_active) {
|
||||
sa.ok('禁用成功');
|
||||
} else {
|
||||
sa.ok('启用成功');
|
||||
}
|
||||
this.f5();
|
||||
}.bind(this), {})
|
||||
}.bind(this));
|
||||
},
|
||||
// 批量删除
|
||||
@ -219,8 +224,8 @@
|
||||
return sa.msg('请至少选择一条数据')
|
||||
}
|
||||
// 提交删除
|
||||
sa.confirm('是否批量删除选中数据?此操作不可撤销', function() {
|
||||
sa.ajax2('/SysType/deleteByIds', {ids: ids.join(',')}, function(res) {
|
||||
sa.confirm('是否批量禁用选中用户?此操作可撤销', function() {
|
||||
sa.ajax2('/user/admin/change_status', {ids: ids}, function(res) {
|
||||
sa.arrayDelete(this.dataList, selection);
|
||||
sa.ok('删除成功');
|
||||
sa.f5TableHeight(); // 刷新表格高度
|
||||
|
@ -1,5 +1,5 @@
|
||||
import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
from fastapi_amis_admin.crud import BaseApiOut
|
||||
|
||||
@ -17,6 +17,7 @@ from src.services.users.schemas import (
|
||||
UserLoginOut,
|
||||
UserRoleEnum,
|
||||
CreateTypeEnum,
|
||||
UserAdminAdd,
|
||||
)
|
||||
from src.services.users.services import UserServices, UserRoleServices
|
||||
|
||||
@ -33,30 +34,31 @@ class UserRoutes(Plugin):
|
||||
self.user_services = user_services
|
||||
self.user_role_services = user_role_services
|
||||
|
||||
@handler.post("/register", admin=False)
|
||||
async def register(self, data: UserRegIn):
|
||||
if data.username.upper() in SystemUserEnum.__members__:
|
||||
async def before_reg(self, username: str, student_id: str, phone: str):
|
||||
if username.upper() in SystemUserEnum.__members__:
|
||||
return BaseApiOut(status=500, msg="用户名已被注册")
|
||||
user = await self.user_services.get_user(username=data.username)
|
||||
user = await self.user_services.get_user(username=username)
|
||||
if user:
|
||||
return BaseApiOut(status=500, msg="用户名已被注册")
|
||||
role = UserRoleEnum.STUDENT.value
|
||||
create_type = CreateTypeEnum.STUDENT
|
||||
if not (data.student_id or data.phone):
|
||||
if not (student_id or phone):
|
||||
return BaseApiOut(status=500, msg="学号或手机号至少填写一项")
|
||||
if data.student_id:
|
||||
user = await self.user_services.get_user(student_id=data.student_id)
|
||||
if student_id:
|
||||
user = await self.user_services.get_user(student_id=student_id)
|
||||
if user:
|
||||
return BaseApiOut(status=500, msg="学号已被注册")
|
||||
role = UserRoleEnum.STUDENT.value
|
||||
create_type = CreateTypeEnum.STUDENT
|
||||
if data.phone:
|
||||
user = await self.user_services.get_user(phone=data.phone)
|
||||
if phone:
|
||||
user = await self.user_services.get_user(phone=phone)
|
||||
if user:
|
||||
return BaseApiOut(status=500, msg="手机号已被注册")
|
||||
role = UserRoleEnum.OUT.value
|
||||
create_type = CreateTypeEnum.PHONE
|
||||
# 检查通过,注册用户
|
||||
return None
|
||||
|
||||
async def create_user(
|
||||
self,
|
||||
data: Union[UserRegIn, UserAdminAdd],
|
||||
create_type: CreateTypeEnum,
|
||||
role: UserRoleEnum,
|
||||
):
|
||||
sex = "" if not hasattr(data, "sex") else data.sex
|
||||
try:
|
||||
user = await self.user_services.register_user(
|
||||
username=data.username,
|
||||
@ -64,19 +66,39 @@ class UserRoutes(Plugin):
|
||||
student_id=data.student_id,
|
||||
phone=data.phone,
|
||||
real_name=data.real_name,
|
||||
sex=sex,
|
||||
create_type=create_type.value,
|
||||
)
|
||||
if not await self.user_role_services.is_user_in_role_group(
|
||||
data.username, role
|
||||
data.username,
|
||||
role.value,
|
||||
):
|
||||
await self.user_role_services.add_user_to_role_group(
|
||||
data.username, role
|
||||
data.username,
|
||||
role.value,
|
||||
)
|
||||
return user
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Error Execute SQL:{e}",
|
||||
) from e
|
||||
|
||||
@handler.post("/register", admin=False)
|
||||
async def register(self, data: UserRegIn):
|
||||
check = await self.before_reg(data.username, data.student_id, data.phone)
|
||||
if check:
|
||||
return check
|
||||
role = UserRoleEnum.STUDENT
|
||||
create_type = CreateTypeEnum.STUDENT
|
||||
if data.student_id:
|
||||
role = UserRoleEnum.STUDENT
|
||||
create_type = CreateTypeEnum.STUDENT
|
||||
if data.phone:
|
||||
role = UserRoleEnum.OUT
|
||||
create_type = CreateTypeEnum.PHONE
|
||||
# 检查通过,注册用户
|
||||
user = await self.create_user(data, create_type, role)
|
||||
# 注册成功,设置用户信息
|
||||
token_info = UserLoginOut.model_validate(user)
|
||||
token_info.access_token = await self.user_services.login_user(user)
|
||||
|
@ -4,18 +4,27 @@ from starlette import status
|
||||
|
||||
from src.plugin import handler
|
||||
from src.plugin.plugin import Plugin
|
||||
from src.services.users.schemas import UserList
|
||||
from src.route.users import UserRoutes
|
||||
from src.services.users.schemas import (
|
||||
UserList,
|
||||
DisableOrEnableUser,
|
||||
UserAdminAdd,
|
||||
UserRoleEnum,
|
||||
CreateTypeEnum,
|
||||
)
|
||||
from src.services.users.services import UserServices
|
||||
|
||||
|
||||
class UserRoutes(Plugin):
|
||||
class UserAdminRoutes(Plugin):
|
||||
_prefix = "/user/admin"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
user_services: UserServices,
|
||||
user_routes: UserRoutes,
|
||||
):
|
||||
self.user_services = user_services
|
||||
self.user_routes = user_routes
|
||||
|
||||
@handler.post("/list", student=True)
|
||||
async def get_user_list(self, data: UserList):
|
||||
@ -50,3 +59,31 @@ class UserRoutes(Plugin):
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Error Execute SQL:{e}",
|
||||
) from e
|
||||
|
||||
@handler.post("/change_status", student=True)
|
||||
async def disable_or_enable_user(self, data: DisableOrEnableUser):
|
||||
try:
|
||||
if data.is_active:
|
||||
result = await self.user_services.enable_user(data.user_id)
|
||||
else:
|
||||
result = await self.user_services.disable_user(data.user_id)
|
||||
if not result:
|
||||
return BaseApiOut(code=500, msg="操作失败")
|
||||
return BaseApiOut(code=0, msg="请求成功", data={})
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Error Execute SQL:{e}",
|
||||
) from e
|
||||
|
||||
@handler.post("/add", student=True)
|
||||
async def add_user(self, data: UserAdminAdd):
|
||||
check = await self.user_routes.before_reg(
|
||||
data.username, data.student_id, data.phone
|
||||
)
|
||||
if check:
|
||||
return check
|
||||
role = data.role_id
|
||||
create_type = CreateTypeEnum.ADMIN
|
||||
user = await self.user_routes.create_user(data, create_type, role)
|
||||
return BaseApiOut(code=0, msg="注册成功", data=user)
|
||||
|
@ -11,6 +11,7 @@ from src.plugin.plugin import Plugin
|
||||
from src.services.users.models import UserModel
|
||||
from src.services.users.schemas import UserUpdate, UserUpdateAvatar
|
||||
from src.services.users.services import UserServices, UserRoleServices
|
||||
from src.utils import AVATAR_DATA_PATH
|
||||
from src.utils.upload_file import get_avatar, save_avatar, check_avatar
|
||||
|
||||
|
||||
@ -25,6 +26,7 @@ class UserUpdateRoutes(Plugin):
|
||||
self.user_services = user_services
|
||||
self.user_role_services = user_role_services
|
||||
self.avatar_path = "/user/avatar/"
|
||||
self.avatar_path_default = AVATAR_DATA_PATH / "avatar.jpg"
|
||||
|
||||
@handler.get("/me", student=True, out=True)
|
||||
async def get_me(self, request: Request):
|
||||
@ -69,6 +71,10 @@ class UserUpdateRoutes(Plugin):
|
||||
detail=f"Error Execute SQL:{e}",
|
||||
) from e
|
||||
|
||||
@handler.get("/avatar/default", student=True, out=True)
|
||||
async def get_default_avatar(self):
|
||||
return FileResponse(self.avatar_path_default)
|
||||
|
||||
@handler.get("/avatar/{uid}/{file_path}", student=True, out=True)
|
||||
async def get_avatar(self, request: Request, uid: int, file_path: str):
|
||||
can_see = False
|
||||
|
@ -46,6 +46,7 @@ class UserRepo(AsyncInitializingComponent):
|
||||
student_id: Optional[str],
|
||||
phone: Optional[str],
|
||||
real_name: Optional[str],
|
||||
sex: Optional[str],
|
||||
create_type: int,
|
||||
):
|
||||
password = self.AUTH.pwd_context.hash(password.get_secret_value())
|
||||
@ -55,6 +56,7 @@ class UserRepo(AsyncInitializingComponent):
|
||||
"student_id": student_id,
|
||||
"phone": phone,
|
||||
"real_name": real_name,
|
||||
"sex": sex,
|
||||
"create_type": create_type,
|
||||
}
|
||||
user = self.user_model.model_validate(values)
|
||||
@ -66,12 +68,15 @@ class UserRepo(AsyncInitializingComponent):
|
||||
|
||||
async def get_user(
|
||||
self,
|
||||
user_id: Optional[int] = None,
|
||||
username: Optional[str] = None,
|
||||
student_id: Optional[str] = None,
|
||||
phone: Optional[str] = None,
|
||||
) -> Optional[UserModel]:
|
||||
async with AsyncSession(self.engine) as session:
|
||||
statement = select(self.user_model)
|
||||
if user_id:
|
||||
statement = statement.where(self.user_model.id == user_id)
|
||||
if username:
|
||||
statement = statement.where(self.user_model.username == username)
|
||||
if student_id:
|
||||
@ -159,8 +164,8 @@ class UserRepo(AsyncInitializingComponent):
|
||||
phone: str,
|
||||
student_id: str,
|
||||
create_type: int,
|
||||
start_time: datetime,
|
||||
end_time: datetime,
|
||||
start_time: Optional[datetime],
|
||||
end_time: Optional[datetime],
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
) -> Tuple[Sequence[UserModel], int]:
|
||||
|
@ -128,19 +128,42 @@ class UserList(BaseModel):
|
||||
|
||||
create_type: CreateTypeEnum = CreateTypeEnum.ALL
|
||||
sortType: int = 1
|
||||
start_time: str
|
||||
end_time: str
|
||||
start_time: Optional[str] = ""
|
||||
end_time: Optional[str] = ""
|
||||
pageNo: int = 1
|
||||
pageSize: int = 10
|
||||
|
||||
@property
|
||||
def start(self):
|
||||
if not self.start_time:
|
||||
return None
|
||||
y, m, d = self.start_time.split("-")
|
||||
start_time = date(int(y), int(m), int(d))
|
||||
return datetime.combine(start_time, datetime.min.time())
|
||||
|
||||
@property
|
||||
def end(self):
|
||||
if not self.end_time:
|
||||
return None
|
||||
y, m, d = self.end_time.split("-")
|
||||
end_time = date(int(y), int(m), int(d))
|
||||
return datetime.combine(end_time, datetime.max.time())
|
||||
|
||||
|
||||
class DisableOrEnableUser(BaseModel):
|
||||
user_id: int
|
||||
is_active: bool = False
|
||||
|
||||
|
||||
class UserAdminAdd(
|
||||
UsernameMixin,
|
||||
RealNameMixin,
|
||||
PasswordMixin,
|
||||
StudentIdMixin,
|
||||
PhoneMixin,
|
||||
SexMixin,
|
||||
):
|
||||
"""管理员添加"""
|
||||
|
||||
nickname: Optional[str] = Field("", title=_("Nickname"), max_length=40)
|
||||
role_id: UserRoleEnum
|
||||
|
@ -26,6 +26,7 @@ class UserServices(AsyncInitializingComponent):
|
||||
student_id: Optional[str],
|
||||
phone: Optional[str],
|
||||
real_name: Optional[str],
|
||||
sex: Optional[str],
|
||||
create_type: int = 0,
|
||||
):
|
||||
return await self.repo.register_user(
|
||||
@ -34,6 +35,7 @@ class UserServices(AsyncInitializingComponent):
|
||||
student_id,
|
||||
phone,
|
||||
real_name,
|
||||
sex,
|
||||
create_type,
|
||||
)
|
||||
|
||||
@ -42,11 +44,12 @@ class UserServices(AsyncInitializingComponent):
|
||||
|
||||
async def get_user(
|
||||
self,
|
||||
user_id: Optional[int] = None,
|
||||
username: Optional[str] = None,
|
||||
student_id: Optional[str] = None,
|
||||
phone: Optional[str] = None,
|
||||
) -> Optional[UserModel]:
|
||||
return await self.repo.get_user(username, student_id, phone)
|
||||
return await self.repo.get_user(user_id, username, student_id, phone)
|
||||
|
||||
async def create_login_history(
|
||||
self, user: "UserModel", ip: str, ua: str, forwarded_for: str
|
||||
@ -108,8 +111,8 @@ class UserServices(AsyncInitializingComponent):
|
||||
phone: str,
|
||||
student_id: str,
|
||||
create_type: int,
|
||||
start_time: datetime,
|
||||
end_time: datetime,
|
||||
start_time: Optional[datetime],
|
||||
end_time: Optional[datetime],
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
) -> Tuple[Sequence[UserModel], int]:
|
||||
@ -127,6 +130,22 @@ class UserServices(AsyncInitializingComponent):
|
||||
page_size,
|
||||
)
|
||||
|
||||
async def disable_user(self, user_id: int) -> bool:
|
||||
user = await self.get_user(user_id)
|
||||
if not user or not user.is_active:
|
||||
return False
|
||||
user.is_active = False
|
||||
await self.repo.update_user(user)
|
||||
return True
|
||||
|
||||
async def enable_user(self, user_id: int) -> bool:
|
||||
user = await self.get_user(user_id)
|
||||
if not user or user.is_active:
|
||||
return False
|
||||
user.is_active = True
|
||||
await self.repo.update_user(user)
|
||||
return True
|
||||
|
||||
|
||||
class UserRoleServices(AsyncInitializingComponent):
|
||||
__order__ = 1
|
||||
|
@ -1 +1 @@
|
||||
from ._path import PROJECT_ROOT, SERVICES_PATH, FRONTEND_PATH
|
||||
from ._path import PROJECT_ROOT, SERVICES_PATH, FRONTEND_PATH, AVATAR_DATA_PATH
|
||||
|
Loading…
Reference in New Issue
Block a user