From 918ab92940bc9dd411dd968a9456f2e144003f05 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Mon, 11 Nov 2024 15:14:13 +0800 Subject: [PATCH] feat: user list --- src/frontend/sa-view/user/user-add.html | 42 ++++++++++----- src/frontend/sa-view/user/user-list.html | 66 ++++++++++++++---------- src/route/users_admin.py | 46 +++++++++++++++++ src/services/users/repositories.py | 52 ++++++++++++++++++- src/services/users/schemas.py | 25 +++++++++ src/services/users/services.py | 17 +++++- 6 files changed, 205 insertions(+), 43 deletions(-) create mode 100644 src/route/users_admin.py diff --git a/src/frontend/sa-view/user/user-add.html b/src/frontend/sa-view/user/user-add.html index d75c7e4..ad12c7f 100644 --- a/src/frontend/sa-view/user/user-add.html +++ b/src/frontend/sa-view/user/user-add.html @@ -21,30 +21,42 @@
用户添加
- +
- + + +
+
+ + +
+
+
- + + +
+
+
- + - - - + + +
- - + +
@@ -58,11 +70,15 @@ new Vue({ el: '.vue-box', data: { - m: { // 查询参数 - username: '', - password: '', + m: { // 查询参数 + student_id: '', phone: '', - sex: 1, + username: '', + nickname: '', + real_name: '', + password: '', + sex: '男', + role_id: 'admin', } }, methods: { diff --git a/src/frontend/sa-view/user/user-list.html b/src/frontend/sa-view/user/user-list.html index 826e342..4cbaf0e 100644 --- a/src/frontend/sa-view/user/user-list.html +++ b/src/frontend/sa-view/user/user-list.html @@ -21,12 +21,20 @@
用户列表
- +
+
+ + +
+
+ + +
- - + -
@@ -49,7 +57,7 @@
新增 查看 - 删除 + 禁用 导出 重置
@@ -57,36 +65,31 @@ - + - - - + + - @@ -117,33 +120,42 @@ data: { p: { // 查询参数 username: '', + nickname: '', + real_name: '', create_type: 0, sortType: 1, - start_time: new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-1', // 本月一号 - end_time: new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-' + new Date().getDate(), // 本月当日 + start_time: new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-1', // 本月一号 + end_time: new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-' + new Date().getDate(), // 本月当日 pageNo: 1, pageSize: 10, }, - dataCount: 1422, + dataCount: 0, dataList: [] }, methods: { // 数据刷新 f5: function() { - sa.ajax2('/user/getList', this.p, function(res){ - this.dataList = res.data; // 数据 - this.dataCount = res.dataCount; // 分页 + 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].status = this.dataList[i].is_active ? 1 : 0; + } + this.dataCount = res.data.count; // 分页 sa.f5TableHeight(); // 刷新表格高度 - }.bind(this), {res: mockData}); + }.bind(this), {}); }, // 查看 get: function(data) { var str = '
'; str += '

编号:' + data.id + '

'; - str += '

昵称:' + data.username + '

'; + str += '

用户名:' + data.username + '

'; + str += '

昵称:' + data.nickname + '

'; + str += '

真实姓名:' + data.real_name + '

'; + str += '

学号:' + data.student_id + '

'; + str += '

电话:' + data.phone + '

'; + str += '

邮箱:' + data.email + '

'; str += '

性别:' + data.sex + '

'; str += '

当前状态:' + (data.status == 1 ? '正常' : '禁用') + '

'; - str += '

注册方式:' + data.create_type + '

'; str += '

注册时间:' + data.create_time + '

'; str += '
'; sa.alert(str); diff --git a/src/route/users_admin.py b/src/route/users_admin.py new file mode 100644 index 0000000..7e9b10c --- /dev/null +++ b/src/route/users_admin.py @@ -0,0 +1,46 @@ +from fastapi import HTTPException +from fastapi_amis_admin.crud import BaseApiOut +from starlette import status + +from src.plugin import handler +from src.plugin.plugin import Plugin +from src.services.users.schemas import UserList +from src.services.users.services import UserServices + + +class UserRoutes(Plugin): + _prefix = "/user/admin" + + def __init__( + self, + user_services: UserServices, + ): + self.user_services = user_services + + @handler.post("/list", student=True) + async def get_user_list(self, data: UserList): + username, nickname, real_name = data.username, data.nickname, data.real_name + start_time, end_time = data.start, data.end + page_no, page_size = data.pageNo, data.pageSize + if page_no < 1: + page_no = 1 + if page_size < 0 or page_size > 100: + page_size = 10 + try: + data, count = await self.user_services.get_user_list( + username, + nickname, + real_name, + start_time, + end_time, + page_no, + page_size, + ) + return BaseApiOut( + code=0, msg="请求成功", data={"data": data, "count": count} + ) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Error Execute SQL:{e}", + ) from e diff --git a/src/services/users/repositories.py b/src/services/users/repositories.py index 8f1c99a..4cad8db 100644 --- a/src/services/users/repositories.py +++ b/src/services/users/repositories.py @@ -1,11 +1,13 @@ -from typing import Optional, Sequence +from datetime import datetime +from typing import Optional, Sequence, Tuple from fastapi_user_auth.auth import Auth from fastapi_user_auth.auth.backends.redis import RedisTokenStore from fastapi_user_auth.auth.models import CasbinRule, LoginHistory from persica.factory.component import AsyncInitializingComponent from pydantic import SecretStr -from sqlmodel import select +from sqlalchemy import func +from sqlmodel import select, col from sqlmodel.ext.asyncio.session import AsyncSession from src.core.database import Database @@ -133,3 +135,49 @@ class UserRepo(AsyncInitializingComponent): await session.commit() await session.refresh(user) return user + + @staticmethod + async def get_count(session, q) -> int: + count_q = ( + q.with_only_columns(func.count()) + .order_by(None) + .select_from(q.get_final_froms()[0]) + ) + iterator = await session.exec(count_q) + for count in iterator: + return count + return 0 + + async def get_user_list( + self, + username: str, + nickname: str, + real_name: str, + start_time: datetime, + end_time: datetime, + page_no: int, + page_size: int, + ) -> Tuple[Sequence[UserModel], int]: + async with AsyncSession(self.engine) as session: + statement = select(self.user_model) + if username: + statement = statement.where( + col(self.user_model.username).like(f"%{username}%") + ) + if nickname: + statement = statement.where( + col(self.user_model.nickname).like(f"%{nickname}%") + ) + if real_name: + statement = statement.where( + col(self.user_model.real_name).like(f"%{real_name}%") + ) + if start_time: + statement = statement.where(self.user_model.create_time >= start_time) + if end_time: + statement = statement.where(self.user_model.create_time <= end_time) + all_count = await self.get_count(session, statement) + offset = (page_no - 1) * page_size + statement = statement.offset(offset).limit(page_size) + r = await session.exec(statement) + return r.all(), all_count diff --git a/src/services/users/schemas.py b/src/services/users/schemas.py index c7d08bb..4af67b7 100644 --- a/src/services/users/schemas.py +++ b/src/services/users/schemas.py @@ -1,3 +1,4 @@ +from datetime import date, datetime from enum import Enum from typing import Optional @@ -107,3 +108,27 @@ class UserRoleEnum(str, Enum): ADMIN = "admin" # 管理员 STUDENT = "student" # 教职工 OUT = "out" # 校外人员 + + +class UserList(BaseModel): + username: str = "" + nickname: str = "" + real_name: str = "" + + sortType: int = 1 + start_time: str + end_time: str + pageNo: int = 1 + pageSize: int = 10 + + @property + def start(self): + 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): + y, m, d = self.end_time.split("-") + end_time = date(int(y), int(m), int(d)) + return datetime.combine(end_time, datetime.max.time()) diff --git a/src/services/users/services.py b/src/services/users/services.py index 4ab0199..3a9ed53 100644 --- a/src/services/users/services.py +++ b/src/services/users/services.py @@ -1,4 +1,5 @@ -from typing import Optional, List, Union, Sequence +from datetime import datetime +from typing import Optional, List, Union, Sequence, Tuple from fastapi_user_auth.auth.models import CasbinRule, LoginHistory from fastapi_user_auth.utils.casbin import update_subject_roles @@ -96,6 +97,20 @@ class UserServices(AsyncInitializingComponent): user.avatar = avatar return await self.repo.update_user(user) + async def get_user_list( + self, + username: str, + nickname: str, + real_name: str, + start_time: datetime, + end_time: datetime, + page_no: int, + page_size: int, + ) -> Tuple[Sequence[UserModel], int]: + return await self.repo.get_user_list( + username, nickname, real_name, start_time, end_time, page_no, page_size + ) + class UserRoleServices(AsyncInitializingComponent): __order__ = 1