Files
SMANAGE/gvsds/apps/gerp/views/user_detail.py
T

400 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""用户详情 API — 查询用户关联的角色、权限、订单等信息
支持主服务器和子服务器(通过 MSYNC form proxy 查询)。"""
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from . import ELTAuthenticatedAPIView
from gvsdsdk.auth.permissions import PermissionVerifier
from gvsdsdk.model_utils import UUIDObj
import datetime
import logging
logger = logging.getLogger(__name__)
class UserDetailView(ELTAuthenticatedAPIView):
"""查询指定用户的详细信息:角色、权限、订单等
GET /api/gerp/users/detail/?server=<name>&UserUUID=<uuid>
参数:
server: 服务器名称(默认 gvsds-master 查主库)
UserUUID: 用户 UUID(十六进制字符串)
"""
permission_classes = [IsAuthenticated]
def get(self, request):
if not PermissionVerifier(True, ['admin:saas_server'], user=request.user, request=request):
return Response({'code': 403, 'msg': '权限不足'}, status=403)
server_name = request.query_params.get('server', 'gvsds-master')
user_uuid_str = request.query_params.get('UserUUID', '')
if not user_uuid_str:
return Response({'code': 1, 'msg': '缺少 UserUUID 参数'})
# 主服务器直接 ORM 查询
if server_name == 'gvsds-master':
return self._query_master(user_uuid_str)
# 子服务器通过 form proxy 查询
return self._query_sub(server_name, user_uuid_str)
def _query_master(self, user_uuid_str):
"""主服务器:直接 ORM 查询"""
from gvsds.apps.core.models import User
from gvsds.apps.gerp.models import UserRole, Role, RolePermission, Permission
try:
user_uuid = UUIDObj(user_uuid_str).bytes
except Exception:
return Response({'code': 1, 'msg': '无效的 UserUUID'})
# 用户基本信息
try:
user = User.objects.get(UserUUID=user_uuid)
except User.DoesNotExist:
return Response({'code': 1, 'msg': '用户不存在'})
user_info = {
'UserUUID': user_uuid_str,
'UserName': user.UserName,
'UserEmail': user.UserEmail or '',
'UserTele': user.UserTele or '',
'UserGender': user.UserGender,
'UserAccountLicense': user.UserAccountLicense,
'UserPositionStatus': user.UserPositionStatus,
'UserCreateTime': str(user.UserCreateTime) if user.UserCreateTime else '',
'UserLastLoginDate': str(user.UserLastLoginDate) if user.UserLastLoginDate else '',
'IsStaff': user.IsStaff,
'IsSuperuser': user.IsSuperuser,
}
# 角色列表(通过 UserRole.CompanyUUID 获取关联公司)
roles = []
user_roles = UserRole.objects.filter(UserUUID=user_uuid)
for ur in user_roles:
role = Role.objects.filter(RoleUUID=ur.RoleUUID).first()
if role:
company_name = ''
company_short = ''
if ur.CompanyUUID:
from gvsds.apps.gerp.models import Company
company = Company.objects.filter(CompanyUUID=ur.CompanyUUID).first()
if company:
company_name = company.CompanyName
company_short = company.CompanyShort or ''
roles.append({
'RoleUUID': str(UUIDObj(role.RoleUUID)) if role.RoleUUID else '',
'RoleName': role.RoleName,
'RoleType': role.RoleType,
'RoleStatus': role.RoleStatus,
'AssignScope': role.AssignScope,
'RoleDesc': role.RoleDesc or '',
'CompanyName': company_name,
'CompanyShort': company_short,
})
# 权限列表(通过 UserRole → RolePermission → Permission 链路查询,按公司过滤)
permissions = []
role_uuids = [ur.RoleUUID for ur in user_roles if ur.RoleUUID]
company_uuids = [ur.CompanyUUID for ur in user_roles if ur.CompanyUUID]
if role_uuids:
rp_qs = RolePermission.objects.filter(
RoleUUID__in=role_uuids
)
if company_uuids:
rp_qs = rp_qs.filter(CompanyUUID__in=company_uuids)
perm_uuids = rp_qs.values_list('PermUUID', flat=True)
perms = Permission.objects.filter(PermUUID__in=perm_uuids, PermStatus=1)
seen = set()
for p in perms:
key = p.PermCode
if key not in seen:
seen.add(key)
permissions.append({
'PermName': p.PermName,
'PermCode': p.PermCode,
'PermCategory': p.PermCategory or '',
'PermDesc': p.PermDesc or '',
})
# 订单列表(最近 20 条)
orders = []
try:
from gvsdsdk.order.models import Order
user_orders = Order.objects.filter(
BuyerUserUUID=user_uuid
).order_by('-CreateTime')[:20]
for o in user_orders:
orders.append({
'OrderNO': o.OrderNO,
'OrderTitle': o.OrderTitle,
'OrderType': o.OrderType,
'TotalAmount': str(o.TotalAmount),
'PayAmount': str(o.PayAmount),
'Currency': o.Currency,
'OrderStatus': o.OrderStatus,
'CreateTime': str(o.CreateTime) if o.CreateTime else '',
})
except Exception:
pass # 订单表可能不存在
return Response({
'code': 0,
'data': {
'User': user_info,
'Roles': roles,
'Permissions': permissions,
'Orders': orders,
}
})
def _query_sub(self, server_name, user_uuid_str):
"""子服务器:通过 form proxy 查询 User 表"""
from gvsds.apps.msync.models import ServiceNode
from gvsds.apps.gerp.views.msync_admin import _get_sub_db_connection
node = ServiceNode.objects.filter(ServiceName=server_name).first()
if not node:
return Response({'code': 1, 'msg': f'服务不存在: {server_name}'})
conn, err = _get_sub_db_connection(node)
if err:
return Response({'code': 1, 'msg': err})
try:
conn.ensure_connection()
except Exception as e:
return Response({'code': 1, 'msg': f'数据库连接失败: {e}'})
try:
import uuid as _uuid
user_uuid_bytes = _uuid.UUID(user_uuid_str).bytes
except Exception:
return Response({'code': 1, 'msg': '无效的 UserUUID'})
try:
with conn.cursor() as cursor:
# 查用户基本信息
cursor.execute(
"SELECT UserUUID, UserName, UserEmail, UserTele, UserGender, "
"UserAccountLicense, UserPositionStatus, UserCreateTime, UserLastLoginDate, "
"IsStaff, IsSuperuser FROM `User` WHERE UserUUID = %s",
[user_uuid_bytes]
)
row = cursor.fetchone()
if not row:
return Response({'code': 1, 'msg': '用户不存在'})
cols = [desc[0] for desc in cursor.description]
user_info = {}
for i, col in enumerate(cols):
val = row[i]
if isinstance(val, bytes) and len(val) == 16:
try:
val = str(_uuid.UUID(bytes=val))
except Exception:
val = val.hex()
elif isinstance(val, datetime.datetime):
val = str(val)
user_info[col] = val
# 查角色(通过 UserRole.CompanyUUID 获取关联公司)
cursor.execute(
"SELECT r.RoleUUID, r.RoleName, r.RoleType, r.RoleStatus, "
"r.AssignScope, r.RoleDesc, c.CompanyName, c.CompanyShort "
"FROM UserRole ur "
"JOIN Role r ON ur.RoleUUID = r.RoleUUID "
"LEFT JOIN Company c ON ur.CompanyUUID = c.CompanyUUID "
"WHERE ur.UserUUID = %s",
[user_uuid_bytes]
)
roles = []
for r in cursor.fetchall():
roles.append({
'RoleUUID': str(_uuid.UUID(bytes=r[0])) if isinstance(r[0], bytes) and len(r[0]) == 16 else str(r[0]),
'RoleName': r[1],
'RoleType': r[2],
'RoleStatus': r[3],
'AssignScope': r[4],
'RoleDesc': r[5] or '',
'CompanyName': r[6] or '',
'CompanyShort': r[7] or '',
})
# 查权限(通过 UserRole → RolePermission → Permission 链路)
cursor.execute(
"SELECT DISTINCT p.PermName, p.PermCode, p.PermCategory, p.PermDesc "
"FROM Permission p "
"JOIN RolePermission rp ON p.PermUUID = rp.PermUUID "
"JOIN UserRole ur ON rp.RoleUUID = ur.RoleUUID "
"WHERE ur.UserUUID = %s AND p.PermStatus = 1",
[user_uuid_bytes]
)
permissions = []
for p in cursor.fetchall():
permissions.append({
'PermName': p[0],
'PermCode': p[1],
'PermCategory': p[2] or '',
'PermDesc': p[3] or '',
})
# 查订单(如果 Order 表存在)
orders = []
try:
cursor.execute(
"SELECT OrderNO, OrderTitle, OrderType, TotalAmount, PayAmount, "
"Currency, OrderStatus, CreateTime FROM `Order` "
"WHERE BuyerUserUUID = %s ORDER BY CreateTime DESC LIMIT 20",
[user_uuid_bytes]
)
for o in cursor.fetchall():
orders.append({
'OrderNO': o[0],
'OrderTitle': o[1],
'OrderType': o[2],
'TotalAmount': str(o[3]),
'PayAmount': str(o[4]),
'Currency': o[5],
'OrderStatus': o[6],
'CreateTime': str(o[7]) if o[7] else '',
})
except Exception:
pass
return Response({
'code': 0,
'data': {
'User': user_info,
'Roles': roles,
'Permissions': permissions,
'Orders': orders,
}
})
except Exception as e:
logger.error(f'查询子服务器 {server_name} 用户详情失败: {e}')
return Response({'code': 1, 'msg': f'查询失败: {e}'})
class UserListAPIView(ELTAuthenticatedAPIView):
"""查询用户列表(支持主服务器和子服务器)
GET /api/gerp/users/list/?server=<name>&PageIndex=1&PageSize=20&Keyword=xxx
参数:
server: 服务器名称(默认 gvsds-master)
PageIndex: 页码
PageSize: 每页条数
Keyword: 搜索关键词(可选,匹配用户名/邮箱)
"""
permission_classes = [IsAuthenticated]
def get(self, request):
if not PermissionVerifier(True, ['admin:saas_server'], user=request.user, request=request):
return Response({'code': 403, 'msg': '权限不足'}, status=403)
server_name = request.query_params.get('server', 'gvsds-master')
page_index = int(request.query_params.get('PageIndex', 1))
page_size = int(request.query_params.get('PageSize', 20))
keyword = request.query_params.get('Keyword', '').strip()
if server_name == 'gvsds-master':
return self._query_master(page_index, page_size, keyword)
return self._query_sub(server_name, page_index, page_size, keyword)
def _query_master(self, page_index, page_size, keyword):
"""主服务器:直接 ORM 查询"""
from gvsds.apps.core.models import User
qs = User.objects.all()
if keyword:
qs = qs.filter(UserName__icontains=keyword) | qs.filter(UserEmail__icontains=keyword)
total = qs.count()
offset = (page_index - 1) * page_size
users = qs[offset:offset + page_size]
records = []
for u in users:
records.append({
'UserUUID': UUIDObj(u.UserUUID).str if u.UserUUID else '',
'UserName': u.UserName or '',
'UserEmail': u.UserEmail or '',
'UserTele': u.UserTele or '',
'UserGender': u.UserGender,
'UserAccountLicense': u.UserAccountLicense,
'UserPositionStatus': u.UserPositionStatus,
'UserCreateTime': str(u.UserCreateTime) if u.UserCreateTime else '',
'UserLastLoginDate': str(u.UserLastLoginDate) if u.UserLastLoginDate else '',
'IsStaff': u.IsStaff,
'IsSuperuser': u.IsSuperuser,
})
return Response({'code': 0, 'data': records, 'total': total})
def _query_sub(self, server_name, page_index, page_size, keyword):
"""子服务器:通过 form proxy 查询"""
from gvsds.apps.msync.models import ServiceNode
from gvsds.apps.gerp.views.msync_admin import _get_sub_db_connection
node = ServiceNode.objects.filter(ServiceName=server_name).first()
if not node:
return Response({'code': 1, 'msg': f'服务不存在: {server_name}'})
conn, err = _get_sub_db_connection(node)
if err:
return Response({'code': 1, 'msg': err})
try:
conn.ensure_connection()
except Exception as e:
return Response({'code': 1, 'msg': f'数据库连接失败: {e}'})
import uuid as _uuid
try:
with conn.cursor() as cursor:
where = ''
params = []
if keyword:
where = "WHERE UserName LIKE %s OR UserEmail LIKE %s"
params = [f'%{keyword}%', f'%{keyword}%']
# 总数
cursor.execute(f"SELECT COUNT(*) FROM `User` {where}", params)
total = cursor.fetchone()[0]
# 分页
offset = (page_index - 1) * page_size
cursor.execute(
f"SELECT UserUUID, UserName, UserEmail, UserTele, UserGender, "
f"UserAccountLicense, UserPositionStatus, UserCreateTime, UserLastLoginDate, "
f"IsStaff, IsSuperuser FROM `User` {where} "
f"ORDER BY UserCreateTime DESC LIMIT %s OFFSET %s",
params + [page_size, offset]
)
records = []
for row in cursor.fetchall():
record = {}
cols = ['UserUUID', 'UserName', 'UserEmail', 'UserTele', 'UserGender',
'UserAccountLicense', 'UserPositionStatus', 'UserCreateTime',
'UserLastLoginDate', 'IsStaff', 'IsSuperuser']
for i, col in enumerate(cols):
val = row[i]
if isinstance(val, bytes) and len(val) == 16:
try:
val = str(_uuid.UUID(bytes=val))
except Exception:
val = val.hex()
elif isinstance(val, datetime.datetime):
val = str(val)
record[col] = val
records.append(record)
return Response({'code': 0, 'data': records, 'total': total})
except Exception as e:
logger.error(f'查询子服务器 {server_name} 用户列表失败: {e}')
return Response({'code': 1, 'msg': f'查询失败: {e}'})