feat: 新增文件上传下载功能并优化用户认证流程

- 新增文件上传下载服务及API接口
- 重构用户认证模块,支持验证码登录
- 优化.env配置文件结构
- 更新前端API请求工具和类型定义
- 添加工作台菜单项
- 修复用户登出逻辑
- 统一API响应数据结构
This commit is contained in:
zhangtao
2025-08-11 23:52:29 +08:00
parent 130038cb11
commit c760a53f34
34 changed files with 677 additions and 429 deletions
+87 -70
View File
@@ -1,60 +1,58 @@
import request, { publicRequest } from "@/utils/request";
const AUTH_BASE_URL = "/api/v1/auth";
export interface LoginData {
username: string;
password: string;
}
export interface WxLoginData {
code: string;
encryptedData?: string;
iv?: string;
phoneCode?: string;
}
export interface LoginResult {
accessToken: string;
refreshToken?: string;
tokenType: string;
expiresIn: number;
isNewUser?: boolean;
isProfileComplete?: boolean;
}
const AUTH_BASE_URL = "/api/v1/system/auth";
const AuthAPI = {
/**
* 账号密码登录
* @param data 登录表单数据
* 登录
* @param body 登录表单数据
* @returns 登录结果
*/
login(data: LoginData): Promise<LoginResult> {
const formData = {
username: data.username,
password: data.password,
};
return publicRequest<LoginResult>({
login(body: LoginFormData): Promise<LoginResult> {
return request<LoginResult>({
url: `${AUTH_BASE_URL}/login`,
method: "POST",
data: formData,
header: {
"Content-Type": "application/x-www-form-urlencoded",
headers: {
"Content-Type": "multipart/form-data",
},
data: body,
});
},
/**
* 微信小程序授权登录 (仅使用code获取OpenID)
* @param code 微信登录凭证
* @returns 登录结果
* 刷新令牌
* @param body 刷新令牌请求体
* @returns 新的访问令牌
*/
loginByWxMiniAppCode(code: string): Promise<LoginResult> {
return publicRequest<LoginResult>({
url: `${AUTH_BASE_URL}/wx/miniapp/code-login`,
refreshToken(body: RefreshToekenBody): Promise<any> {
return request<LoginResult>({
url: `${AUTH_BASE_URL}/token/refresh`,
method: "POST",
data: { code },
data: body,
});
},
/**
* 获取验证码
* @returns 验证码信息
*/
getCaptcha(): Promise<any> {
return request<CaptchaInfo>({
url: `${AUTH_BASE_URL}/captcha/get`,
method: "GET",
});
},
/**
* 登出
* @param body 登出请求体
* @returns 登出结果
*/
logout(body: LogoutBody): Promise<any> {
return request<ApiResponse>({
url: `${AUTH_BASE_URL}/logout`,
method: "POST",
data: body,
});
},
@@ -72,39 +70,58 @@ const AuthAPI = {
},
/**
* 检查会话有效性
* @returns 会话是否有效
* 微信小程序授权登录 (仅使用code获取OpenID)
* @param code 微信登录凭证
* @returns 登录结果
*/
checkSession(): Promise<{ valid: boolean }> {
return request<{ valid: boolean }>({
url: `${AUTH_BASE_URL}/check-session`,
method: "GET",
});
},
/**
* 登出
* @returns 登出结果
*/
logout(): Promise<any> {
return request<any>({
url: `${AUTH_BASE_URL}/logout`,
loginByWxMiniAppCode(code: string): Promise<LoginResult> {
return publicRequest<LoginResult>({
url: `${AUTH_BASE_URL}/wx/miniapp/code-login`,
method: "POST",
});
},
/**
* 刷新令牌
* @param refreshToken 刷新令牌
* @returns 新的访问令牌
*/
refreshToken(refreshToken: string): Promise<{ accessToken: string; expiresIn: number }> {
return publicRequest<{ accessToken: string; expiresIn: number }>({
url: `${AUTH_BASE_URL}/refresh-token`,
method: "POST",
data: { refreshToken },
data: { code },
});
},
};
export default AuthAPI;
export interface WxLoginData {
code: string;
encryptedData?: string;
iv?: string;
phoneCode?: string;
}
/** 登录表单数据 */
export interface LoginFormData {
username: string;
password: string;
captcha_key: string;
captcha: string;
remember: boolean;
}
// 刷新令牌
export interface RefreshToekenBody {
refresh_token: string;
}
/** 登录响应 */
export interface LoginResult {
access_token: string;
refresh_token: string;
token_type: string;
expires_in: number;
}
/** 验证码信息 */
export interface CaptchaInfo {
enable: boolean;
key: string;
img_base: string;
}
/** 退出登录操作 */
export interface LogoutBody {
token: string;
}
+5 -15
View File
@@ -1,8 +1,8 @@
import { getToken } from "@/utils/storage";
import { ApiCode } from "@/enums/api-code.enum";
// H5 使用 VITE_APP_BASE_API 作为代理路径,其他平台使用 VITE_APP_API_URL 作为请求路径
let baseApi = import.meta.env.VITE_APP_API_URL;
// H5 使用 VITE_APP_BASE_API 作为代理路径,其他平台使用 VITE_API_BASE_URL 作为请求路径
let baseApi = import.meta.env.VITE_API_BASE_URL;
// #ifdef H5
baseApi = import.meta.env.VITE_APP_BASE_API;
// #endif
@@ -11,14 +11,14 @@ const FileAPI = {
/**
* 文件上传地址
*/
uploadUrl: baseApi + "/api/v1/files",
uploadUrl: baseApi + "/api/v1/files/upload",
/**
* 上传文件
*
* @param filePath
*/
upload(filePath: string): Promise<FileInfo> {
upload(filePath: string): Promise<UploadFilePath> {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: this.uploadUrl,
@@ -29,7 +29,7 @@ const FileAPI = {
},
formData: {},
success: (response) => {
const resData = JSON.parse(response.data) as ResponseData<FileInfo>;
const resData = JSON.parse(response.data) as ApiResponse<UploadFilePath>;
// 业务状态码 00000 表示成功
if (resData.code === ApiCode.SUCCESS) {
resolve(resData.data);
@@ -63,13 +63,3 @@ const FileAPI = {
};
export default FileAPI;
/**
* 文件API类型声明
*/
export interface FileInfo {
/** 文件名 */
name: string;
/** 文件路径 */
url: string;
}
+250 -244
View File
@@ -1,44 +1,103 @@
import request from "@/utils/request";
const USER_BASE_URL = "/api/v1/users";
const USER_BASE_URL = "/api/v1/system/user";
const UserAPI = {
/**
* 获取当前登录用户信息
* 个人中心用户信息
*
* @returns 登录用户昵称、头像信息,包括角色和权限
*/
getUserInfo(): Promise<UserInfo> {
getCurrentUserInfo(): Promise<UserInfo> {
return request<UserInfo>({
url: `${USER_BASE_URL}/me`,
url: `${USER_BASE_URL}/current/info`,
method: "GET",
});
},
/**
* 当前用户头像上传
*
* @param body
* @returns 上传后的文件路径
*/
uploadCurrentUserAvatar(body: any): Promise<UploadFilePath> {
return request<UploadFilePath>({
url: `${USER_BASE_URL}/current/avatar/upload`,
method: "POST",
data: body,
headers: { "Content-Type": "multipart/form-data" },
});
},
/**
* 修改个人中心用户信息
*
* @param body
* @returns 修改后的用户信息
*/
updateCurrentUserInfo(body: UserProfileForm): Promise<UserInfo> {
return request<UserInfo>({
url: `${USER_BASE_URL}/current/info/update`,
method: "PUT",
data: body,
});
},
/**
* 修改个人中心用户密码
*
* @param body
* @returns 修改后的用户信息
*/
changeCurrentUserPassword(body: PasswordChangeForm): Promise<ApiResponse> {
return request<ApiResponse>({
url: `${USER_BASE_URL}/current/password/change`,
method: "PUT",
data: body,
});
},
/**
* 注册用户
*
* @param body
* @returns 忘记密码结果
*/
registerUser(body: RegisterForm): Promise<ApiResponse> {
return request<ApiResponse>({
url: `${USER_BASE_URL}/register`,
method: "POST",
data: body,
});
},
/**
* 忘记密码
*
* @param body
* @returns 忘记密码结果
*/
forgetPassword(body: ForgetPasswordForm): Promise<ApiResponse> {
return request<ApiResponse>({
url: `${USER_BASE_URL}/forget/password`,
method: "POST",
data: body,
});
},
/**
* 获取用户分页列表
*
*POST
* @param queryParams 查询参数
*/
getPage(queryParams: UserPageQuery) {
return request<PageResult<UserPageVO[]>>({
url: `${USER_BASE_URL}/page`,
getUserPage(queryParams: UserPageQuery): Promise<PageResult<UserInfo[]>> {
return request<PageResult<UserInfo[]>>({
url: `${USER_BASE_URL}/list`,
method: "GET",
data: queryParams,
});
},
/**
* 添加用户
*
* @param data 用户表单数据
*/
add(data: UserForm) {
return request({
url: `${USER_BASE_URL}`,
method: "POST",
data: data,
});
},
/**
* 获取用户表单详情
@@ -46,245 +105,216 @@ const UserAPI = {
* @param userId 用户ID
* @returns 用户表单详情
*/
getFormData(userId: number) {
getUserDetail(userId: number): Promise<UserForm> {
return request<UserForm>({
url: `${USER_BASE_URL}/${userId}/form`,
url: `${USER_BASE_URL}/detail/${userId}`,
method: "GET",
});
},
/**
* 添加用户
*
* @param body 用户表单数据
*/
addUser(body: UserForm): Promise<ApiResponse> {
return request<ApiResponse>({
url: `${USER_BASE_URL}/create`,
method: "POST",
data: body,
});
},
/**
* 修改用户
*
* @param id 用户ID
* @param data 用户表单数据
* @param body 用户表单数据
*/
update(id: number, data: UserForm) {
updateUser(body: UserForm): Promise<ApiResponse> {
return request({
url: `${USER_BASE_URL}/${id}`,
url: `${USER_BASE_URL}/update`,
method: "PUT",
data: data,
});
},
/** 获取个人中心用户信息 */
getProfile() {
return request<UserProfileVO>({
url: `${USER_BASE_URL}/profile`,
method: "GET",
});
},
/** 修改个人中心用户信息 */
updateProfile(data: UserProfileForm) {
return request({
url: `${USER_BASE_URL}/profile`,
method: "PUT",
data: data,
});
},
/** 修改个人中心用户密码 */
changePassword(data: PasswordChangeForm) {
return request({
url: `${USER_BASE_URL}/password`,
method: "PUT",
data: data,
data: body,
});
},
/**
* 发送手机/邮箱验证码
* 删除用户
*
* @param contact 联系方式 手机号/邮箱
* @param contactType 联系方式类型 MOBILE:手机;EMAIL:邮箱
* @param ids 用户ID数组
*/
sendVerificationCode(contact: string, contactType: string) {
return request({
url: `${USER_BASE_URL}/send-verification-code?contact=${contact}&contactType=${contactType}`,
method: "POST",
});
},
/** 绑定个人中心用户手机 */
bindMobile(data: MobileBindingForm) {
return request({
url: `${USER_BASE_URL}/mobile`,
method: "PUT",
data: data,
});
},
/** 绑定个人中心用户邮箱 */
bindEmail(data: EmailBindingForm) {
return request({
url: `${USER_BASE_URL}/email`,
method: "PUT",
data: data,
});
},
/**
* 批量删除用户,多个以英文逗号(,)分割
*
* @param ids 用户ID字符串,多个以英文逗号(,)分割
*/
deleteByIds(ids: string) {
return request({
url: `${USER_BASE_URL}/${ids}`,
deleteUser(ids: number[]): Promise<ApiResponse> {
return request<ApiResponse>({
url: `/system/user/delete`,
method: "DELETE",
});
},
/** 获取微信手机号 */
getPhoneNumber(data: WechatPhoneData): Promise<PhoneNumberResult> {
return request<PhoneNumberResult>({
url: `${USER_BASE_URL}/wechat-phone`,
method: "POST",
data: data,
data: ids,
});
},
};
export default UserAPI;
/** 登录用户信息 */
export interface UserInfo {
/** 用户ID */
userId?: number;
/** 用户名 */
username?: string;
/** 昵称 */
nickname?: string;
/** 头像URL */
avatar?: string;
/** 角色 */
roles?: string[];
/** 权限 */
perms?: string[];
/* 忘记密码表单 */
export interface ForgetPasswordForm {
username: string;
new_password: string;
confirmPassword: string;
}
/**
* 用户分页查询对象
*/
/* 注册表单 */
export interface RegisterForm {
username: string;
password: string;
confirmPassword: string;
}
/* 分页查询表单 */
export interface UserPageQuery extends PageQuery {
/** 搜索关键字 */
keywords?: string;
/** 用户状态 */
status?: number;
/** 部门ID */
deptId?: number;
/** 开始时间 */
createTime?: [string, string] | string;
/** 排序字段 */
field?: string;
/** 排序方式(asc:正序,desc:倒序) */
direction?: string;
}
/** 用户分页对象 */
export interface UserPageVO {
/** 用户头像URL */
avatar?: string;
/** 创建时间 */
createTime?: string;
/** 部门名称 */
deptName?: string;
/** 用户邮箱 */
email?: string;
/** 性别 */
gender?: number;
/** 用户ID */
id: number;
/** 手机号 */
mobile?: string;
/** 用户昵称 */
nickname?: string;
/** 角色名称,多个使用英文逗号(,)分割 */
roleNames?: string;
/** 用户状态(1:启用;0:禁用) */
status?: number;
/** 用户名 */
username?: string;
name?: string;
status?: boolean;
dept_id?: number;
start_time?: string;
end_time?: string;
}
/** 个人中心用户信息 */
export interface UserProfileVO {
/** 用户ID */
/* 搜索选择器数据类型 */
export interface searchSelectDataType {
name?: string;
status?: string;
}
/* 用户表单 */
export interface UserForm {
id?: number;
/** 用户名 */
username?: string;
/** 昵称 */
nickname?: string;
/** 头像URL */
avatar?: string;
/** 性别 */
name?: string;
dept_id?: number;
dept_name?: string;
role_ids?: number[];
roleNames?: string[];
position_ids?: number[];
positionNames?: string[];
password?: string;
gender?: number;
/** 手机号 */
mobile?: string;
/** 邮箱 */
email?: string;
/** 部门名称 */
deptName?: string;
/** 角色名称,多个使用英文逗号(,)分割 */
roleNames?: string;
/** 创建时间 */
createTime?: string;
mobile?: string;
is_superuser?: boolean;
status?: boolean;
description?: string;
}
/** 个人中心用户信息表单 */
/* 登录用户信息 */
export interface UserInfo {
index?: number;
id?: number;
username?: string;
name?: string;
avatar?: string;
email?: string;
mobile?: string;
gender?: string;
password?: string;
menus?: MenuTable[];
dept?: deptTreeType;
dept_id?: deptTreeType["id"];
dept_name?: deptTreeType["name"];
roles?: roleSelectorType[];
roleNames?: roleSelectorType["name"][];
role_ids?: roleSelectorType["id"][];
positions?: positionSelectorType[];
positionNames?: positionSelectorType["name"][];
position_ids?: positionSelectorType["id"][];
is_superuser?: boolean;
status?: boolean;
description?: string;
last_login?: string;
created_at?: string;
updated_at?: string;
creator?: creatorType;
}
/* 菜单表 */
export interface MenuTable {
index?: number;
id?: number;
name?: string;
type?: number;
icon?: string;
order?: number;
permission?: string;
route_name?: string;
route_path?: string;
component_path?: string;
redirect?: string;
parent_id?: number;
parent_name?: string;
keep_alive?: boolean;
hidden?: boolean;
always_show?: boolean;
title?: string;
params?: { key: string; value: string }[];
affix?: boolean;
status?: boolean;
description?: string;
created_at?: string;
updated_at?: string;
children?: MenuTable[];
}
/* 部门树 */
export interface deptTreeType {
id?: number;
name?: string;
parent_id?: number;
children?: deptTreeType[];
}
/* 角色选择器 */
export interface roleSelectorType {
id?: number;
name?: string;
status?: boolean;
description?: string;
}
/* 职位选择器 */
export interface positionSelectorType {
id?: number;
name?: string;
status?: boolean;
description?: string;
}
/* 个人中心用户信息表单 */
export interface UserProfileForm {
/** 用户ID */
id?: number;
/** 用户名 */
username?: string;
/** 昵称 */
nickname?: string;
/** 头像URL */
avatar?: string;
/** 性别 */
gender?: number;
/** 手机号 */
mobile?: string;
/** 邮箱 */
email?: string;
name: string;
gender: number;
mobile: string;
email: string;
username: string;
dept_name: string;
positions: positionSelectorType[];
roles: roleSelectorType[];
avatar: string;
created_at: string;
}
/** 修改密码表单 */
/* 修改密码表单 */
export interface PasswordChangeForm {
/** 原密码 */
oldPassword?: string;
/** 新密码 */
newPassword?: string;
/** 确认新密码 */
confirmPassword?: string;
old_password: string;
new_password: string;
confirm_password: string;
}
/** 修改手机表单 */
/* 重置密码表单 */
export interface ResetPasswordForm {
id: number;
password: string;
}
/* 修改手机表单 */
export interface MobileBindingForm {
/** 手机号 */
mobile?: string;
@@ -292,7 +322,7 @@ export interface MobileBindingForm {
code?: string;
}
/** 修改邮箱表单 */
/* 修改邮箱表单 */
export interface EmailBindingForm {
/** 邮箱 */
email?: string;
@@ -300,31 +330,7 @@ export interface EmailBindingForm {
code?: string;
}
/** 用户表单 */
export interface UserForm {
/** 用户头像 */
avatar?: string;
/** 部门ID */
deptId?: number;
/** 用户邮箱 */
email?: string;
/** 性别 */
gender?: number;
/** 用户ID */
id?: number;
/** 手机号 */
mobile?: string;
/** 昵称 */
nickname?: string;
/** 角色ID集合 */
roleIds: number[];
/** 用户状态(1:正常;0:禁用) */
status?: number;
/** 用户名 */
username?: string;
}
/** 微信手机号授权数据 */
/* 微信手机号授权数据 */
export interface WechatPhoneData {
/** 微信授权码 */
code: string;
@@ -334,7 +340,7 @@ export interface WechatPhoneData {
iv?: string;
}
/** 手机号获取结果 */
/* 手机号获取结果 */
export interface PhoneNumberResult {
/** 手机号 */
phoneNumber: string;
+1
View File
@@ -8,6 +8,7 @@ export interface TabbarItem {
const tabbarItems = ref<TabbarItem[]>([
{ name: "home", value: null, active: true, title: "首页", icon: "home" },
{ name: "work", value: null, active: true, title: "工作台", icon: "work" },
{ name: "mine", value: null, active: false, title: "我的", icon: "user" },
]);
+10 -15
View File
@@ -5,45 +5,40 @@ export const enum ApiCode {
/**
* 成功
*/
SUCCESS = "00000",
SUCCESS = 0,
/**
* 通用错误
*/
ERROR = "B0001",
ERROR = 1,
/**
* 令牌无效或过期
* 异常
*/
TOKEN_INVALID = "A0230",
/**
* 令牌已过期
*/
TOKEN_EXPIRED = "A0231",
EXCEPTION = -1,
/**
* 未授权访问
*/
UNAUTHORIZED = "A0232",
UNAUTHORIZED = 401,
/**
* 禁止访问
* 令牌已过期
*/
FORBIDDEN = "A0233",
TOKEN_EXPIRED = 403,
/**
* 参数校验失败
*/
PARAM_INVALID = "A0400",
PARAM_INVALID = 400,
/**
* 资源不存在
*/
NOT_FOUND = "A0404",
NOT_FOUND = 404,
/**
* 服务器内部错误
*/
INTERNAL_ERROR = "B0500",
INTERNAL_ERROR = 500,
}
+2
View File
@@ -1,4 +1,6 @@
<script lang="ts" setup>
import { useTheme } from "@/composables/useTheme";
const { theme, themeVars } = useTheme();
</script>
+44 -2
View File
@@ -50,6 +50,25 @@
@click="showPassword = !showPassword"
/>
</view>
<!-- 验证码输入框 -->
<view class="form-item">
<wd-icon
name="lock-on"
size="22"
:color="isDarkMode ? '#7AC5FF' : '#333'"
class="input-icon"
/>
<input
v-model="loginFormData.captcha"
class="form-input input-transparent"
type="text"
placeholder="请输入验证码"
placeholder-class="input-placeholder"
/>
<view class="captcha-img">
<image :src="captchaImg" class="captcha-img" />
</view>
</view>
<view class="divider"></view>
<!-- 登录按钮 -->
@@ -122,12 +141,12 @@
<script lang="ts" setup>
import { onLoad } from "@dcloudio/uni-app";
import { type LoginData } from "@/api/auth";
import { useUserStore } from "@/store/modules/user.store";
import { useToast } from "wot-design-uni";
import { useWechat } from "@/composables/useWechat";
import { useTheme } from "@/composables/useTheme";
import { computed, onMounted } from "vue";
import AuthAPI, { type LoginFormData } from "@/api/auth";
const loginFormRef = ref();
const toast = useToast();
@@ -138,13 +157,18 @@ const loginType = ref<"account" | "phone">("account");
const { authState, getLoginCode, getPhoneNumber } = useWechat();
const { theme } = useTheme();
const captchaImg = ref("");
// 是否暗黑模式
const isDarkMode = computed(() => theme.value === "dark");
// 登录表单数据
const loginFormData = ref<LoginData>({
const loginFormData = ref<LoginFormData>({
username: "admin",
password: "123456",
captcha_key: "",
captcha: "",
remember: true,
});
// 获取重定向参数
@@ -155,6 +179,17 @@ onLoad((options) => {
}
});
// 获取验证码
const getLoginCaptcha = async () => {
try {
const result = await AuthAPI.getCaptcha();
captchaImg.value = result.captcha_key;
toast.success("验证码发送成功");
} catch (error: any) {
toast.error(error?.message || "验证码发送失败");
}
};
// 强制清除输入框背景色
onMounted(() => {
setTimeout(() => {
@@ -164,6 +199,8 @@ onMounted(() => {
input.style.boxShadow = "none";
});
}, 100);
getLoginCaptcha();
});
// 账号密码登录处理
@@ -179,6 +216,11 @@ const handleAccountLogin = () => {
toast.error("请输入密码");
return;
}
if (loginFormData.value.captcha_key && !loginFormData.value.captcha) {
toast.error("请输入验证码");
return;
}
loading.value = true;
+17 -26
View File
@@ -1,5 +1,10 @@
import { defineStore } from "pinia";
import AuthAPI, { type LoginData, type WxLoginData } from "@/api/auth";
import AuthAPI, {
type LoginFormData,
type WxLoginData,
type LoginResult,
type LogoutBody,
} from "@/api/auth";
import UserAPI, { type UserInfo } from "@/api/user";
import { setAccessToken, clearTokens } from "@/utils/auth";
import { getUserInfo, setUserInfo } from "@/utils/storage";
@@ -10,11 +15,11 @@ export const useUserStore = defineStore("user", () => {
const userInfo = ref<UserInfo | undefined>(getUserInfo());
// 账号密码登录
const login = (data: LoginData) => {
const login = (data: LoginFormData) => {
return new Promise((resolve, reject) => {
AuthAPI.login(data)
.then((data) => {
setAccessToken(data.accessToken);
.then((data: LoginResult) => {
setAccessToken(data.access_token);
resolve(data);
})
.catch((error) => {
@@ -28,8 +33,8 @@ export const useUserStore = defineStore("user", () => {
const loginWithWxCode = (code: string) => {
return new Promise((resolve, reject) => {
AuthAPI.loginByWxMiniAppCode(code)
.then((data) => {
setAccessToken(data.accessToken);
.then((data: LoginResult) => {
setAccessToken(data.access_token);
resolve(data);
})
.catch((error: any) => {
@@ -43,8 +48,8 @@ export const useUserStore = defineStore("user", () => {
const loginWithWxPhone = (data: WxLoginData): Promise<any> => {
return new Promise((resolve, reject) => {
AuthAPI.loginByWxMiniAppPhone(data)
.then((result: any) => {
setAccessToken(result.accessToken);
.then((result: LoginResult) => {
setAccessToken(result.access_token);
resolve(result);
})
.catch((error: any) => {
@@ -54,23 +59,10 @@ export const useUserStore = defineStore("user", () => {
});
};
// 检查会话状态
const checkSession = (): Promise<boolean> => {
return new Promise((resolve) => {
AuthAPI.checkSession()
.then((result) => {
resolve(result.valid);
})
.catch(() => {
resolve(false);
});
});
};
// 获取用户信息
const getInfo = () => {
return new Promise((resolve, reject) => {
UserAPI.getUserInfo()
UserAPI.getCurrentUserInfo()
.then((data) => {
setUserInfo(data);
userInfo.value = data;
@@ -84,9 +76,9 @@ export const useUserStore = defineStore("user", () => {
};
// 登出
const logout = async () => {
const logout = async (data: LogoutBody) => {
try {
await AuthAPI.logout(); // 调用后台注销接口
await AuthAPI.logout(data); // 调用后台注销接口
} catch (error) {
console.error("登出失败", error);
} finally {
@@ -105,7 +97,7 @@ export const useUserStore = defineStore("user", () => {
const isUserInfoComplete = (): boolean => {
if (!userInfo.value) return false;
return !!(userInfo.value.nickname && userInfo.value.avatar);
return !!(userInfo.value.username && userInfo.value.avatar);
};
return {
@@ -115,7 +107,6 @@ export const useUserStore = defineStore("user", () => {
loginWithWxPhone,
logout,
getInfo,
checkSession,
isUserInfoComplete,
};
});
+9 -6
View File
@@ -6,15 +6,18 @@ interface ImportMetaEnv {
/**
* 应用端口
*/
VITE_APP_PORT: number;
readonly VITE_APP_PORT: number;
/** 超时时间 */
readonly VITE_TIMEOUT: number;
/** API基础路径 */
readonly VITE_APP_BASE_API: string;
/** API服务器URL */
readonly VITE_APP_API_URL: string;
/**
* WebSocket 端点
*/
readonly VITE_API_BASE_URL: string;
/** 环境 */
readonly VITE_APP_ENV: string;
/** 项目名称 */
readonly VITE_APP_TITLE: string;
/** WebSocket 端点 */
readonly VITE_APP_WS_ENDPOINT?: string;
}
+34 -9
View File
@@ -1,10 +1,22 @@
declare global {
/**
* 响应数据
*/
interface ApiResponse<T = any> {
code: number;
data: T;
msg: string;
status_code: number;
}
/**
* 分页查询参数
*/
interface PageQuery {
pageNum: number;
pageSize: number;
/** 当前页码 */
page_no: number;
/** 每页条数 */
page_size: number;
}
/**
@@ -12,13 +24,16 @@ declare global {
*/
interface PageResult<T> {
/** 数据列表 */
list: T;
items: T;
/** 总数 */
total: number;
page_no: number;
page_size: number;
has_next: boolean;
}
/**
* 组件数据源
* 下拉选项数据类型
*/
interface OptionType {
/** 值 */
@@ -30,12 +45,22 @@ declare global {
}
/**
* 响应数据
* 创建人
*/
interface ResponseData<T = any> {
code: string;
data: T;
msg: string;
interface creatorType {
id?: number;
name?: string;
username?: string;
}
/**
* 上传文件返回
*/
interface UploadFilePath {
file_path: string;
file_name: string;
origin_name: string;
file_url: string;
}
}
export {};
+1 -1
View File
@@ -132,7 +132,7 @@ export function requireLogin(): void {
if (!accessToken || !userStore.userInfo) {
// 清除可能存在的无效状态
clearTokens();
userStore.logout();
userStore.logout({ token: accessToken || "" });
// 跳转到登录页
uni.reLaunch({
+1 -1
View File
@@ -5,7 +5,7 @@
* @returns
*/
const debounce = <T extends (...args: any[]) => any>(fn: T, delay: number) => {
let timer: number | null = null;
let timer: ReturnType<typeof setTimeout> | null = null;
return function (this: any, ...args: Parameters<T>) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
+17 -10
View File
@@ -5,23 +5,25 @@ interface RequestOptions<T = any> {
url: string;
method: "GET" | "POST" | "PUT" | "DELETE";
data?: T;
header?: Record<string, string>;
headers?: Record<string, string>;
timeout?: number;
responseType?: "text" | "arraybuffer";
responseType?: "text" | "arraybuffer" | "blob" | "json";
skipAuth?: boolean; // 标记是否跳过认证
}
// 请求函数
/**
* 请求拦截器 - 添加 Authorization 头
*/
function request<T = any>(options: RequestOptions): Promise<T> {
return new Promise<T>((resolve, reject) => {
// 构建请求头
const header = Object.assign({}, options.header || {});
const header = Object.assign({}, options.headers || {});
// 检查是否需要添加认证令牌
if (!options.skipAuth) {
const token = getAccessToken();
if (token) {
header["Authorization"] = `Bearer ${token}`;
const accessToken = getAccessToken();
if (accessToken) {
header["Authorization"] = `Bearer ${accessToken}`;
} else {
// 需要认证但没有令牌,跳转到登录页
uni.navigateTo({
@@ -35,7 +37,7 @@ function request<T = any>(options: RequestOptions): Promise<T> {
let requestUrl = options.url;
// #ifdef MP-WEIXIN
// 微信小程序环境,使用完整URL
requestUrl = `${import.meta.env.VITE_APP_API_URL}${options.url}`;
requestUrl = `${import.meta.env.VITE_API_BASE_URL}${options.url}`;
// #endif
// #ifndef MP-WEIXIN
@@ -43,13 +45,18 @@ function request<T = any>(options: RequestOptions): Promise<T> {
requestUrl = `${import.meta.env.VITE_APP_BASE_API}${options.url}`;
// #endif
let timeout = Number(import.meta.env.VITE_TIMEOUT);
if (options.timeout) {
timeout = options.timeout;
}
// 统一处理请求
uni.request({
url: requestUrl,
method: options.method,
data: options.data,
header,
timeout: options.timeout || 30000,
header: header,
timeout: timeout,
responseType: options.responseType,
success: (res: any) => {
// 请求成功