feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
测试数据模块
|
||||
|
||||
提供测试数据管理和生成功能。
|
||||
"""
|
||||
|
||||
from .factories.user_factory import UserDataFactory
|
||||
from .factories.role_factory import RoleDataFactory
|
||||
from .factories.almanac_factory import AlmanacDataFactory
|
||||
|
||||
__all__ = [
|
||||
"UserDataFactory",
|
||||
"RoleDataFactory",
|
||||
"AlmanacDataFactory",
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
"""
|
||||
数据工厂模块
|
||||
|
||||
提供测试数据生成功能。
|
||||
"""
|
||||
@@ -0,0 +1,114 @@
|
||||
"""
|
||||
黄历数据工厂
|
||||
|
||||
提供黄历测试数据生成功能。
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
class AlmanacDataFactory:
|
||||
"""黄历数据工厂"""
|
||||
|
||||
@staticmethod
|
||||
def get_test_dates() -> Dict[str, str]:
|
||||
"""获取测试日期数据"""
|
||||
return {
|
||||
"spring_festival": "2026-02-17", # 春节
|
||||
"lantern_festival": "2026-03-03", # 元宵节
|
||||
"dragon_boat": "2026-06-19", # 端午节
|
||||
"mid_autumn": "2026-09-25", # 中秋节
|
||||
"national_day": "2026-10-01", # 国庆节
|
||||
"new_year": "2026-01-01", # 元旦
|
||||
"valentine": "2026-02-14", # 情人节
|
||||
"labour_day": "2026-05-01", # 劳动节
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_current_date() -> str:
|
||||
"""获取当前日期"""
|
||||
return datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
@staticmethod
|
||||
def get_previous_date(days: int = 1) -> str:
|
||||
"""获取前几天日期"""
|
||||
date = datetime.now() - timedelta(days=days)
|
||||
return date.strftime("%Y-%m-%d")
|
||||
|
||||
@staticmethod
|
||||
def get_next_date(days: int = 1) -> str:
|
||||
"""获取后几天日期"""
|
||||
date = datetime.now() + timedelta(days=days)
|
||||
return date.strftime("%Y-%m-%d")
|
||||
|
||||
@staticmethod
|
||||
def get_date_range(start_days: int = -7, end_days: int = 7) -> List[str]:
|
||||
"""获取日期范围"""
|
||||
dates = []
|
||||
start_date = datetime.now() + timedelta(days=start_days)
|
||||
end_date = datetime.now() + timedelta(days=end_days)
|
||||
|
||||
current = start_date
|
||||
while current <= end_date:
|
||||
dates.append(current.strftime("%Y-%m-%d"))
|
||||
current += timedelta(days=1)
|
||||
|
||||
return dates
|
||||
|
||||
@staticmethod
|
||||
def get_month_dates(year: int, month: int) -> List[str]:
|
||||
"""获取指定月份的所有日期"""
|
||||
dates = []
|
||||
start_date = datetime(year, month, 1)
|
||||
|
||||
# 获取下个月的第一天
|
||||
if month == 12:
|
||||
next_month = datetime(year + 1, 1, 1)
|
||||
else:
|
||||
next_month = datetime(year, month + 1, 1)
|
||||
|
||||
current = start_date
|
||||
while current < next_month:
|
||||
dates.append(current.strftime("%Y-%m-%d"))
|
||||
current += timedelta(days=1)
|
||||
|
||||
return dates
|
||||
|
||||
@staticmethod
|
||||
def get_expected_almanac_fields() -> List[str]:
|
||||
"""获取黄历预期字段"""
|
||||
return [
|
||||
"solar_date", # 公历日期
|
||||
"lunar_date", # 农历日期
|
||||
"ganzhi", # 干支
|
||||
"shengxiao", # 生肖
|
||||
"yi", # 宜
|
||||
"ji", # 忌
|
||||
"chongsha", # 冲煞
|
||||
"wuxing", # 五行
|
||||
"taishen", # 胎神
|
||||
"caishen", # 财神方位
|
||||
"shichen", # 时辰
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_expected_yi_ji_items() -> Dict[str, List[str]]:
|
||||
"""获取预期的宜忌事项示例"""
|
||||
return {
|
||||
"yi": [
|
||||
"嫁娶", "祭祀", "祈福", "求嗣", "开光", "出行", "解除",
|
||||
"拆卸", "修造", "动土", "起基", "上梁", "安床", "入宅",
|
||||
"移徙", "安香", "纳畜", "安葬", "入殓", "破土", "修坟",
|
||||
],
|
||||
"ji": [
|
||||
"开市", "立券", "纳财", "出货", "开仓", "盖屋", "造船",
|
||||
"掘井", "作灶", "出火", "伐木", "斋醮", "词讼", "行丧",
|
||||
],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def validate_almanac_data(data: Dict[str, Any]) -> bool:
|
||||
"""验证黄历数据是否完整"""
|
||||
required_fields = AlmanacDataFactory.get_expected_almanac_fields()
|
||||
return all(field in data for field in required_fields)
|
||||
@@ -0,0 +1,151 @@
|
||||
"""
|
||||
数据工厂基类
|
||||
|
||||
提供数据工厂的通用功能。
|
||||
"""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from typing import Dict, Any, List, Optional
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class BaseDataFactory(ABC):
|
||||
"""数据工厂基类"""
|
||||
|
||||
# 存储生成的数据
|
||||
_data_store: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def create(cls, **kwargs) -> Dict[str, Any]:
|
||||
"""创建单个数据"""
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def batch_create(cls, count: int, **kwargs) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
批量创建数据
|
||||
|
||||
Args:
|
||||
count: 创建数量
|
||||
**kwargs: 额外参数
|
||||
|
||||
Returns:
|
||||
数据列表
|
||||
"""
|
||||
results = []
|
||||
for i in range(count):
|
||||
# 添加索引确保唯一性
|
||||
item_kwargs = kwargs.copy()
|
||||
item_kwargs['_index'] = i
|
||||
item = cls.create(**item_kwargs)
|
||||
results.append(item)
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def create_from_template(cls, template: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
基于模板创建数据
|
||||
|
||||
Args:
|
||||
template: 模板数据
|
||||
**kwargs: 额外参数
|
||||
|
||||
Returns:
|
||||
生成的数据
|
||||
"""
|
||||
# 先创建基础数据
|
||||
data = cls.create(**kwargs)
|
||||
|
||||
# 应用模板
|
||||
for key, value in template.items():
|
||||
data[key] = value
|
||||
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def serialize(cls, data: Dict[str, Any]) -> str:
|
||||
"""
|
||||
序列化数据为JSON字符串
|
||||
|
||||
Args:
|
||||
data: 数据字典
|
||||
|
||||
Returns:
|
||||
JSON字符串
|
||||
"""
|
||||
return json.dumps(data, ensure_ascii=False, default=str)
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, json_str: str) -> Dict[str, Any]:
|
||||
"""
|
||||
从JSON字符串反序列化数据
|
||||
|
||||
Args:
|
||||
json_str: JSON字符串
|
||||
|
||||
Returns:
|
||||
数据字典
|
||||
"""
|
||||
return json.loads(json_str)
|
||||
|
||||
@classmethod
|
||||
def cleanup(cls, data_id: str) -> bool:
|
||||
"""
|
||||
清理指定数据
|
||||
|
||||
Args:
|
||||
data_id: 数据ID
|
||||
|
||||
Returns:
|
||||
是否成功清理
|
||||
"""
|
||||
if data_id in cls._data_store:
|
||||
del cls._data_store[data_id]
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def exists(cls, data_id: str) -> bool:
|
||||
"""
|
||||
检查数据是否存在
|
||||
|
||||
Args:
|
||||
data_id: 数据ID
|
||||
|
||||
Returns:
|
||||
是否存在
|
||||
"""
|
||||
return data_id in cls._data_store
|
||||
|
||||
@classmethod
|
||||
def get_all(cls) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取所有数据
|
||||
|
||||
Returns:
|
||||
数据列表
|
||||
"""
|
||||
return list(cls._data_store.values())
|
||||
|
||||
@classmethod
|
||||
def clear_all(cls):
|
||||
"""清除所有数据"""
|
||||
cls._data_store.clear()
|
||||
|
||||
@classmethod
|
||||
def _store_data(cls, data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
存储数据
|
||||
|
||||
Args:
|
||||
data: 数据字典
|
||||
|
||||
Returns:
|
||||
存储的数据
|
||||
"""
|
||||
data_id = data.get("id") or str(uuid.uuid4())
|
||||
data["id"] = data_id
|
||||
cls._data_store[data_id] = data
|
||||
return data
|
||||
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
角色数据工厂
|
||||
|
||||
提供角色测试数据生成功能。
|
||||
"""
|
||||
|
||||
from faker import Faker
|
||||
from typing import Dict, Any, List
|
||||
|
||||
faker = Faker("zh_CN")
|
||||
|
||||
|
||||
class RoleDataFactory:
|
||||
"""角色数据工厂"""
|
||||
|
||||
@staticmethod
|
||||
def create_admin_role() -> Dict[str, Any]:
|
||||
"""创建管理员角色数据"""
|
||||
return {
|
||||
"name": f"管理员_{faker.random_int(1000, 9999)}",
|
||||
"code": f"admin_{faker.random_int(1000, 9999)}",
|
||||
"description": "系统管理员,拥有所有权限",
|
||||
"status": "active",
|
||||
"permissions": ["*"],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_user_role() -> Dict[str, Any]:
|
||||
"""创建普通用户角色数据"""
|
||||
return {
|
||||
"name": f"普通用户_{faker.random_int(1000, 9999)}",
|
||||
"code": f"user_{faker.random_int(1000, 9999)}",
|
||||
"description": "普通用户,拥有基本权限",
|
||||
"status": "active",
|
||||
"permissions": ["user:read", "user:write"],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_viewer_role() -> Dict[str, Any]:
|
||||
"""创建只读角色数据"""
|
||||
return {
|
||||
"name": f"只读用户_{faker.random_int(1000, 9999)}",
|
||||
"code": f"viewer_{faker.random_int(1000, 9999)}",
|
||||
"description": "只读用户,仅可查看数据",
|
||||
"status": "active",
|
||||
"permissions": ["user:read"],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_invalid_role() -> Dict[str, Any]:
|
||||
"""创建无效角色数据(用于测试验证)"""
|
||||
return {
|
||||
"name": "", # 空角色名
|
||||
"code": "", # 空角色编码
|
||||
"description": "",
|
||||
"status": "active",
|
||||
"permissions": [],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_duplicate_role(existing_code: str) -> Dict[str, Any]:
|
||||
"""创建重复角色编码数据"""
|
||||
return {
|
||||
"name": faker.job(),
|
||||
"code": existing_code,
|
||||
"description": faker.text(max_nb_chars=50),
|
||||
"status": "active",
|
||||
"permissions": ["user:read"],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_bulk_roles(count: int = 5) -> List[Dict[str, Any]]:
|
||||
"""批量创建角色数据"""
|
||||
return [RoleDataFactory.create_user_role() for _ in range(count)]
|
||||
|
||||
@staticmethod
|
||||
def get_test_roles() -> Dict[str, Dict[str, Any]]:
|
||||
"""获取预定义测试角色"""
|
||||
return {
|
||||
"admin": {
|
||||
"name": "系统管理员",
|
||||
"code": "admin",
|
||||
"description": "拥有所有权限",
|
||||
"status": "active",
|
||||
},
|
||||
"user": {
|
||||
"name": "普通用户",
|
||||
"code": "user",
|
||||
"description": "拥有基本权限",
|
||||
"status": "active",
|
||||
},
|
||||
"viewer": {
|
||||
"name": "只读用户",
|
||||
"code": "viewer",
|
||||
"description": "仅可查看数据",
|
||||
"status": "active",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
"""
|
||||
用户数据工厂
|
||||
|
||||
提供用户测试数据生成功能。
|
||||
"""
|
||||
|
||||
from faker import Faker
|
||||
from typing import Dict, Any, List
|
||||
from .base_factory import BaseDataFactory
|
||||
|
||||
faker = Faker("zh_CN")
|
||||
|
||||
|
||||
class UserDataFactory(BaseDataFactory):
|
||||
"""用户数据工厂"""
|
||||
|
||||
@classmethod
|
||||
def create(cls, **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
创建用户数据
|
||||
|
||||
Args:
|
||||
**kwargs: 自定义字段
|
||||
|
||||
Returns:
|
||||
用户数据字典
|
||||
"""
|
||||
# 获取索引(用于批量创建时确保唯一性)
|
||||
index = kwargs.get('_index', 0)
|
||||
|
||||
# 生成基础数据
|
||||
data = {
|
||||
"id": kwargs.get("id") or str(faker.uuid4()),
|
||||
"username": kwargs.get("username") or f"user_{faker.random_int(1000, 9999)}_{index}",
|
||||
"nickname": kwargs.get("nickname") or faker.name(),
|
||||
"password": kwargs.get("password") or "User@123456",
|
||||
"email": kwargs.get("email") or faker.email(),
|
||||
"phone": kwargs.get("phone") or faker.phone_number(),
|
||||
"role": kwargs.get("role") or "user",
|
||||
"role_id": kwargs.get("role_id") or None,
|
||||
"status": kwargs.get("status") or "active",
|
||||
"department": kwargs.get("department") or "",
|
||||
"avatar": kwargs.get("avatar") or "",
|
||||
"created_at": kwargs.get("created_at") or faker.date_time_this_year().isoformat(),
|
||||
}
|
||||
|
||||
# 存储数据
|
||||
return cls._store_data(data)
|
||||
|
||||
@staticmethod
|
||||
def create_admin_user() -> Dict[str, Any]:
|
||||
"""创建管理员用户数据"""
|
||||
return {
|
||||
"id": str(faker.uuid4()),
|
||||
"username": f"admin_{faker.random_int(1000, 9999)}",
|
||||
"nickname": f"管理员_{faker.random_int(1000, 9999)}",
|
||||
"password": "Admin@123456",
|
||||
"email": faker.email(),
|
||||
"phone": faker.phone_number(),
|
||||
"role": "admin",
|
||||
"role_id": None,
|
||||
"status": "active",
|
||||
"department": "",
|
||||
"avatar": "",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_normal_user() -> Dict[str, Any]:
|
||||
"""创建普通用户数据"""
|
||||
return {
|
||||
"id": str(faker.uuid4()),
|
||||
"username": f"user_{faker.random_int(1000, 9999)}",
|
||||
"nickname": faker.name(),
|
||||
"password": "User@123456",
|
||||
"email": faker.email(),
|
||||
"phone": faker.phone_number(),
|
||||
"role": "user",
|
||||
"role_id": None,
|
||||
"status": "active",
|
||||
"department": "",
|
||||
"avatar": "",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def create_with_role(cls, role: Dict[str, Any], **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
创建带角色的用户
|
||||
|
||||
Args:
|
||||
role: 角色数据
|
||||
**kwargs: 额外参数
|
||||
|
||||
Returns:
|
||||
用户数据
|
||||
"""
|
||||
# 设置角色信息
|
||||
kwargs['role'] = role.get('name', 'user')
|
||||
kwargs['role_id'] = role.get('id')
|
||||
|
||||
# 创建用户
|
||||
return cls.create(**kwargs)
|
||||
|
||||
@staticmethod
|
||||
def create_invalid_user() -> Dict[str, Any]:
|
||||
"""创建无效用户数据(用于测试验证)"""
|
||||
return {
|
||||
"id": str(faker.uuid4()),
|
||||
"username": "", # 空用户名
|
||||
"nickname": "",
|
||||
"password": "123", # 密码太短
|
||||
"email": "invalid-email", # 无效邮箱
|
||||
"phone": "123", # 无效电话
|
||||
"role": "user",
|
||||
"role_id": None,
|
||||
"status": "active",
|
||||
"department": "",
|
||||
"avatar": "",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_duplicate_user(existing_username: str) -> Dict[str, Any]:
|
||||
"""创建重复用户名用户数据"""
|
||||
return {
|
||||
"id": str(faker.uuid4()),
|
||||
"username": existing_username,
|
||||
"nickname": faker.name(),
|
||||
"password": "User@123456",
|
||||
"email": faker.email(),
|
||||
"phone": faker.phone_number(),
|
||||
"role": "user",
|
||||
"role_id": None,
|
||||
"status": "active",
|
||||
"department": "",
|
||||
"avatar": "",
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def create_bulk_users(count: int = 10) -> List[Dict[str, Any]]:
|
||||
"""批量创建用户数据"""
|
||||
return [UserDataFactory.create_normal_user() for _ in range(count)]
|
||||
|
||||
@staticmethod
|
||||
def get_test_users() -> Dict[str, Dict[str, Any]]:
|
||||
"""获取预定义测试用户"""
|
||||
return {
|
||||
"admin": {
|
||||
"id": "test-admin-id",
|
||||
"username": "admin",
|
||||
"password": "admin123",
|
||||
"role": "admin",
|
||||
"role_id": "admin-role-id",
|
||||
},
|
||||
"test_user": {
|
||||
"id": "test-user-id",
|
||||
"username": "testuser",
|
||||
"password": "test123",
|
||||
"role": "user",
|
||||
"role_id": "user-role-id",
|
||||
},
|
||||
"invalid_user": {
|
||||
"id": "invalid-user-id",
|
||||
"username": "invalid",
|
||||
"password": "wrong",
|
||||
"role": "user",
|
||||
"role_id": None,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user