1
0
forked from erp-dev/erp

feat: error_code + api doc + printing-job fields

This commit is contained in:
2026-07-06 23:13:57 +08:00
parent 740d23d04b
commit ddbf798665
21 changed files with 977 additions and 17 deletions

View File

@@ -15,44 +15,137 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.models import update_last_login
from django.core.exceptions import ObjectDoesNotExist
from django.urls import path, include
from rest_framework import status
from rest_framework.response import Response
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from sse.views import create_sse_event, push_test_event, get_sse_status, shutdown_sse
from rest_framework_simplejwt.settings import api_settings
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import (
TokenObtainPairView,
# TokenRefreshView,
)
from basic_info.models import EmployeeStatusEnum
from flower.app_version import AppVersionView
from flower.error_code import AuthErrorCode
from flower.error_code_views import ErrorCodeListView
# 自定义后台站点标题simpleui 也会读取)
admin.site.site_header = "宇问科技"
admin.site.site_title = "宇问科技"
admin.site.index_title = "管理后台"
def login_error_response(error_code: AuthErrorCode, code: str, message: str, http_status: int):
return Response(
{
'error_code': int(error_code),
'code': code,
'message': message,
'detail': message,
},
status=http_status,
)
class CustomTokenObtainPairView(TokenObtainPairView):
"""自定义登录视图"""
def post(self, request, *args, **kwargs):
data = request.data or {}
username = (data.get('username') or '').strip()
password = data.get('password')
if not username and not password:
return login_error_response(
AuthErrorCode.MISSING_CREDENTIALS,
'missing_credentials',
'请输入用户名和密码',
status.HTTP_400_BAD_REQUEST,
)
if not username:
return login_error_response(
AuthErrorCode.MISSING_USERNAME,
'missing_username',
'请输入用户名',
status.HTTP_400_BAD_REQUEST,
)
if not password:
return login_error_response(
AuthErrorCode.MISSING_PASSWORD,
'missing_password',
'请输入密码',
status.HTTP_400_BAD_REQUEST,
)
UserModel = get_user_model()
try:
resp = super().post(request, *args, **kwargs)
if resp.status_code == 200:
srz = self.get_serializer(data=request.data)
srz.is_valid()
user = srz.user
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
return login_error_response(
AuthErrorCode.USER_NOT_FOUND,
'user_not_found',
'用户不存在',
status.HTTP_401_UNAUTHORIZED,
)
if not hasattr(user, 'employee'):
# 非员工用户,直接返回登录失败
return Response({'detail': '无绑定的员工身份'}, status=401)
if not user.check_password(password):
return login_error_response(
AuthErrorCode.INVALID_PASSWORD,
'invalid_password',
'密码错误',
status.HTTP_401_UNAUTHORIZED,
)
return resp
except Exception as e:
return Response({'detail': '无法登录'}, status=400)
if not user.is_active:
return login_error_response(
AuthErrorCode.USER_INACTIVE,
'user_inactive',
'该用户已被禁用',
status.HTTP_403_FORBIDDEN,
)
try:
employee = user.employee
except ObjectDoesNotExist:
return login_error_response(
AuthErrorCode.EMPLOYEE_NOT_BOUND,
'employee_not_bound',
'该用户未绑定员工身份',
status.HTTP_403_FORBIDDEN,
)
if employee.status != EmployeeStatusEnum.ACTIVE:
return login_error_response(
AuthErrorCode.EMPLOYEE_INACTIVE,
'employee_inactive',
'该员工已离职或停用',
status.HTTP_403_FORBIDDEN,
)
refresh = TokenObtainPairSerializer.get_token(user)
if api_settings.UPDATE_LAST_LOGIN:
update_last_login(None, user)
return Response(
{
'refresh': str(refresh),
'access': str(refresh.access_token),
},
status=status.HTTP_200_OK,
)
urlpatterns = [
# JWT 登录
path('api/auth/login/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
# path('api/auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/error-codes/', ErrorCodeListView.as_view(), name='error_code_list'),
path('api/app-version/', AppVersionView.as_view(), name='app_version'),
# API 文档
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),