feat: ✨ 账号锁定功能
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from captcha.views import CaptchaStore, captcha_image
|
from captcha.views import CaptchaStore, captcha_image
|
||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
from django.contrib.auth.hashers import make_password, check_password
|
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
@@ -14,9 +12,7 @@ from rest_framework import serializers
|
|||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
||||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
from rest_framework_simplejwt.views import TokenObtainPairView
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from application import dispatch
|
from application import dispatch
|
||||||
from dvadmin.system.models import Users
|
from dvadmin.system.models import Users
|
||||||
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
|
from dvadmin.utils.json_response import ErrorResponse, DetailResponse
|
||||||
@@ -58,6 +54,7 @@ class LoginSerializer(TokenObtainPairSerializer):
|
|||||||
captcha = serializers.CharField(
|
captcha = serializers.CharField(
|
||||||
max_length=6, required=False, allow_null=True, allow_blank=True
|
max_length=6, required=False, allow_null=True, allow_blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Users
|
model = Users
|
||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
@@ -86,6 +83,11 @@ class LoginSerializer(TokenObtainPairSerializer):
|
|||||||
else:
|
else:
|
||||||
self.image_code and self.image_code.delete()
|
self.image_code and self.image_code.delete()
|
||||||
raise CustomValidationError("图片验证码错误")
|
raise CustomValidationError("图片验证码错误")
|
||||||
|
|
||||||
|
user = Users.objects.get(username=attrs['username'])
|
||||||
|
if not user.is_active:
|
||||||
|
raise CustomValidationError("账号被锁定")
|
||||||
|
|
||||||
data = super().validate(attrs)
|
data = super().validate(attrs)
|
||||||
data["name"] = self.user.name
|
data["name"] = self.user.name
|
||||||
data["userId"] = self.user.id
|
data["userId"] = self.user.id
|
||||||
@@ -107,6 +109,7 @@ class LoginSerializer(TokenObtainPairSerializer):
|
|||||||
save_login_log(request=request)
|
save_login_log(request=request)
|
||||||
return {"code": 2000, "msg": "请求成功", "data": data}
|
return {"code": 2000, "msg": "请求成功", "data": data}
|
||||||
|
|
||||||
|
|
||||||
class LoginView(TokenObtainPairView):
|
class LoginView(TokenObtainPairView):
|
||||||
"""
|
"""
|
||||||
登录接口
|
登录接口
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import * as api from './api';
|
import * as api from './api';
|
||||||
import { dict, PageQuery, AddReq, DelReq, EditReq, CrudExpose, CrudOptions, compute } from '@fast-crud/fast-crud';
|
import { dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud';
|
||||||
import { request } from '/@/utils/service';
|
import { request } from '/@/utils/service';
|
||||||
import { dictionary } from '/@/utils/dictionary';
|
import { dictionary } from '/@/utils/dictionary';
|
||||||
import { successMessage } from '/@/utils/message';
|
import { successMessage } from '/@/utils/message';
|
||||||
import { inject } from 'vue';
|
import { inject } from 'vue';
|
||||||
interface CreateCrudOptionsTypes {
|
|
||||||
crudOptions: CrudOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createCrudOptions = function ({ crudExpose }: { crudExpose: CrudExpose }): CreateCrudOptionsTypes {
|
export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const pageRequest = async (query: PageQuery) => {
|
const pageRequest = async (query: UserPageQuery) => {
|
||||||
return await api.GetList(query);
|
return await api.GetList(query);
|
||||||
};
|
};
|
||||||
const editRequest = async ({ form, row }: EditReq) => {
|
const editRequest = async ({ form, row }: EditReq) => {
|
||||||
|
|||||||
@@ -30,9 +30,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col xs="24" :sm="16" :md="18" :lg="20" :xl="20" class="p-1">
|
<el-col xs="24" :sm="16" :md="18" :lg="20" :xl="20" class="p-1">
|
||||||
<el-card :body-style="{ height: '100%' }">
|
<el-card :body-style="{ height: '100%' }">
|
||||||
|
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding"></fs-crud>
|
<fs-crud ref="crudRef" v-bind="crudBinding"></fs-crud>
|
||||||
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -47,7 +45,8 @@ import {ElTree} from 'element-plus';
|
|||||||
import { ref, onMounted, watch, toRaw, defineAsyncComponent } from 'vue';
|
import { ref, onMounted, watch, toRaw, defineAsyncComponent } from 'vue';
|
||||||
import XEUtils from 'xe-utils';
|
import XEUtils from 'xe-utils';
|
||||||
import { errorMessage, successMessage } from '../../../utils/message';
|
import { errorMessage, successMessage } from '../../../utils/message';
|
||||||
import {GetDept} from "./api";
|
import { GetDept } from './api';
|
||||||
|
import { dictionary } from '/@/utils/dictionary';
|
||||||
|
|
||||||
interface Tree {
|
interface Tree {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -70,7 +69,7 @@ const treeRef = ref<InstanceType<typeof ElTree>>();
|
|||||||
const treeProps = {
|
const treeProps = {
|
||||||
children: 'children',
|
children: 'children',
|
||||||
label: 'name',
|
label: 'name',
|
||||||
icon: 'icon'
|
icon: 'icon',
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(filterText, (val) => {
|
watch(filterText, (val) => {
|
||||||
@@ -82,7 +81,6 @@ const filterNode = (value: string, data: Tree) => {
|
|||||||
return toRaw(data).name.indexOf(value) !== -1;
|
return toRaw(data).name.indexOf(value) !== -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let data = ref([]);
|
let data = ref([]);
|
||||||
|
|
||||||
const content = `
|
const content = `
|
||||||
@@ -95,18 +93,17 @@ const getData = () => {
|
|||||||
const result = XEUtils.toArrayTree(responseData, {
|
const result = XEUtils.toArrayTree(responseData, {
|
||||||
parentKey: 'parent',
|
parentKey: 'parent',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
strict: true
|
strict: true,
|
||||||
});
|
});
|
||||||
console.log(result)
|
|
||||||
data.value = result;
|
data.value = result;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//树形点击事件
|
//树形点击事件
|
||||||
const onTreeNodeClick = (node: any) => {
|
const onTreeNodeClick = (node: any) => {
|
||||||
const {id} = node
|
const { id } = node;
|
||||||
crudExpose.doSearch({form: {dept: id}})
|
crudExpose.doSearch({ form: { dept: id } });
|
||||||
}
|
};
|
||||||
|
|
||||||
// 页面打开后获取列表数据
|
// 页面打开后获取列表数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user