Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions backend/app/core/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ async def get_current_user(
# 获取用户信息
user = await UserCRUD(auth).get_by_username_crud(username=username)
if not user:
raise CustomException(msg="用户不存在", status_code=403)
raise CustomException(msg="用户不存在", status_code=401)
if not user.status:
raise CustomException(msg="用户已被停用", status_code=403)
raise CustomException(msg="用户已被停用", status_code=401)

# 设置请求上下文
request.scope["user_id"] = user.id
Expand Down Expand Up @@ -156,11 +156,11 @@ async def __call__(
# 严格模式:要求所有权限都满足
if not all(perm in user_permissions for perm in self.permissions):
logger.error(f"用户缺少所需的权限: {self.permissions}")
raise CustomException(msg="无权限操作")
raise CustomException(msg="无权限操作", status_code=403)
else:
# 非严格模式:满足任一权限即可
if not any(perm in user_permissions for perm in self.permissions):
logger.error(f"用户缺少任何所需的权限: {self.permissions}")
raise CustomException(msg="无权限操作")
raise CustomException(msg="无权限操作", status_code=403)

return auth
10 changes: 5 additions & 5 deletions backend/app/core/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def create_access_token(payload: JWTPayloadSchema) -> str:
def decode_access_token(token: str) -> JWTPayloadSchema:
"""解析JWT访问令牌"""
if not token:
raise CustomException(msg="认证不存在,请重新登录", status_code=403)
raise CustomException(msg="认证不存在,请重新登录", status_code=401)

try:
payload = jwt.decode(
Expand All @@ -99,15 +99,15 @@ def decode_access_token(token: str) -> JWTPayloadSchema:

online_user_info = payload.get("sub")
if not online_user_info:
raise CustomException(msg="无效认证,请重新登录", status_code=403)
raise CustomException(msg="无效认证,请重新登录", status_code=401)

return JWTPayloadSchema(**payload)

except (jwt.InvalidSignatureError, jwt.DecodeError):
raise CustomException(msg="无效认证,请重新登录", status_code=403)
raise CustomException(msg="无效认证,请重新登录", status_code=401)

except jwt.ExpiredSignatureError:
raise CustomException(msg="认证已过期,请重新登录", status_code=403)
raise CustomException(msg="认证已过期,请重新登录", status_code=401)

except jwt.InvalidTokenError:
raise CustomException(msg="token已失效,请重新登录", status_code=403)
raise CustomException(msg="token已失效,请重新登录", status_code=401)
974 changes: 294 additions & 680 deletions backend/sql/fastapi_vue_admin.sql

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions frontend/src/api/system/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const UserAPI = {
},

updateCurrentUserInfo(body: InfoFormState) {
return request<ApiResponse>({
return request<ApiResponse<UserInfo>>({
url: `/system/user/current/info/update`,
method: "put",
data: body,
Expand Down Expand Up @@ -229,9 +229,9 @@ export interface InfoFormState {
}

export interface PasswordFormState {
oldPassword: string;
newPassword: string;
confirmPassword: string;
old_password: string;
new_password: string;
confirm_password: string;
}

export interface ResetPasswordForm {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/enums/api/result.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export const enum ResultEnum {
/**
* 访问令牌无效或过期
*/
ACCESS_TOKEN_INVALID = 403,
ACCESS_TOKEN_INVALID = 401,

}
5 changes: 5 additions & 0 deletions frontend/src/store/modules/user.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export const useUserStore = defineStore("user", {
this.basicInfo = { ...this.basicInfo, ...response.data.data };
},

// 设置用户信息
setUserInfo(info: UserInfo) {
this.basicInfo = info;
},

setRoute(routers: any) {
this.routeList = routers;
this.hasGetRoute = true;
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/utils/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ httpRequest.interceptors.response.use((response: AxiosResponse<ApiResponse>) =>

const data = response.data;

// 请求成功
if (data.code != ResultEnum.SUCCESS) {
// 检查请求是否失败
if (data.code !== ResultEnum.SUCCESS) {
ElMessage.error(data.msg);
return Promise.reject(response);
}
}

// 如果请求不是 GET 请求,请求成功时显示成功提示
if (response.config.method?.toUpperCase() !== 'GET') {
ElMessage.success(data.msg);
}

return response;
}, async (error: AxiosError<ApiResponse>) => {
const data = error.response?.data;
Expand Down
75 changes: 56 additions & 19 deletions frontend/src/views/current/profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,15 @@
<el-form ref="ruleFormRef" :model="infoFormState" :rules="rules" :inline="true" label-suffix=":">

<el-form-item label="姓名" name="name">
<el-input v-model:value="infoFormState.name" placeholder="请输入姓名" prefix-icon="User" clearable />
<el-input v-model="infoFormState.name" placeholder="请输入姓名" prefix-icon="User" clearable />
</el-form-item>

<el-form-item label="手机号" name="mobile">
<el-input v-model:value="infoFormState.mobile" placeholder="请输入手机号码" prefix-icon="Phone" clearable />
<el-input v-model="infoFormState.mobile" placeholder="请输入手机号码" prefix-icon="Phone" clearable />
</el-form-item>

<el-form-item label="邮箱" name="email">
<el-input v-model:value="infoFormState.email" placeholder="请输入邮箱" prefix-icon="Message" clearable />
<el-input v-model="infoFormState.email" placeholder="请输入邮箱" prefix-icon="Message" clearable />
</el-form-item>

<el-form-item label="性别" name="gender">
Expand All @@ -159,32 +159,32 @@
</template>
<div>
<el-form ref="ruleFormRef" :model="passwordFormState" :rules="resetPasswordRules" label-suffix=":">
<el-form-item label="当前密码" name="oldPassword">
<el-input v-model.trim="passwordFormState.oldPassword" :placeholder="t('login.password')" type="password" show-password clearable>
<el-form-item label="当前密码" name="old_password">
<el-input v-model.trim="passwordFormState.old_password" :placeholder="t('login.password')" type="password" show-password clearable>
<template #prefix>
<Lock />
</template>
</el-input>
</el-form-item>

<el-form-item label="新密码" name="newPassword">
<el-input v-model.trim="passwordFormState.newPassword" type="password" :placeholder="t('login.newPassword')" show-password clearable>
<el-form-item label="新密码" name="new_password">
<el-input v-model.trim="passwordFormState.new_password" type="password" :placeholder="t('login.newPassword')" show-password clearable>
<template #prefix>
<Key />
</template>
</el-input>
</el-form-item>

<el-form-item label="确认新密码" name="confirmPassword">
<el-input v-model.trim="passwordFormState.confirmPassword" type="password" :placeholder="t('login.message.password.confirm')" show-password clearable>
<el-form-item label="确认新密码" name="confirm_password">
<el-input v-model.trim="passwordFormState.confirm_password" type="password" :placeholder="t('login.message.password.confirm')" show-password clearable>
<template #prefix>
<Check />
</template>
</el-input>
</el-form-item>

<el-form-item>
<el-button type="primary" :loading="passwordChanging" icon="edit">更新密码</el-button>
<el-button type="primary" :loading="passwordChanging" icon="edit" @click="handlePasswordChange">更新密码</el-button>
</el-form-item>
</el-form>
</div>
Expand All @@ -200,8 +200,10 @@
import type { FormInstance } from 'element-plus'
import UserAPI, { type InfoFormState, type PasswordFormState } from '@/api/system/user';
import { useUserStore, useDictStore } from "@/store";
import { useUserStoreHook } from "@/store/modules/user.store";
import { Camera } from '@element-plus/icons-vue';
import { useI18n } from "vue-i18n";
import router from "@/router";

const { t } = useI18n();
const userStore = useUserStore();
Expand Down Expand Up @@ -236,9 +238,9 @@ const infoFormState = reactive<InfoFormState>({

// 修改密码表单
const passwordFormState = reactive<PasswordFormState>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
old_password: '',
new_password: '',
confirm_password: ''
});

// 头像上传处理优化
Expand Down Expand Up @@ -324,7 +326,7 @@ const resetPasswordRules = {
},
{
validator: (_: any, value: string) => {
return value === passwordFormState.newPassword;
return value === passwordFormState.new_password;
},
trigger: "blur",
message: t("login.message.password.inconformity"),
Expand All @@ -348,20 +350,55 @@ const initPasswordForm = () => {
};

// 基本信息表单提交
const handleSave = async (values: any) => {
const handleSave = async () => {
try {
infoSubmitting.value = true;
values.avatar = infoFormState.avatar;
await UserAPI.updateCurrentUserInfo(values);
await userStore.getUserInfo;
infoFormState.avatar = infoFormState.avatar;
const response = await UserAPI.updateCurrentUserInfo(infoFormState);
await userStore.setUserInfo(response.data.data);
} catch (error) {
console.error(error);

} finally {
infoSubmitting.value = false;
}
};

// 修改密码
const handlePasswordChange = async () => {
try {
passwordChanging.value = true;
const response = await UserAPI.changeCurrentUserPassword(passwordFormState);
initPasswordForm();
await redirectToLogin(response.data.msg);
} catch (error) {
console.error(error);
} finally {
passwordChanging.value = false;
}
};

/**
* 重定向到登录页面
*/
async function redirectToLogin(message: string = "请重新登录"): Promise<void> {
try {
ElNotification({
title: "提示",
message,
type: "warning",
duration: 3000,
});

await useUserStoreHook().resetAllState();

// 跳转到登录页,保留当前路由用于登录后跳转
const currentPath = router.currentRoute.value.fullPath;
await router.push(`/login?redirect=${encodeURIComponent(currentPath)}`);
} catch (error: any) {
ElMessage.error(error.message);
}
}

onMounted(async () => {
await getOptions();
initInfoForm();
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/config/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/dept/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/dict/components/DataDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/dict/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/log/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/menu/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/notice/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/position/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/system/role/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down
6 changes: 3 additions & 3 deletions frontend/src/views/system/user/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ const formData = reactive<UserForm>({
gender: undefined,
email: undefined,
mobile: undefined,
is_superuser: undefined,
is_superuser: false, //默认不是超管
status: true,
description: undefined,
})
Expand Down Expand Up @@ -551,7 +551,7 @@ async function handleSubmit() {
handleCloseDialog();
handleResetQuery();
} catch (error: any) {
ElMessage.error(error.message);
console.log(error.message);
} finally {
loading.value = false;
}
Expand Down Expand Up @@ -650,7 +650,7 @@ async function handleDelete(ids: number[]) {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消删除');
ElMessageBox.close();
});
}

Expand Down