新增 VITE_API_BASE_URL2 環境變數,更新請求模組以移除 token2 支持,並在登錄頁面中整合新的 token 登錄功能,調整狀態管理以支持多個 token 的存儲。

This commit is contained in:
超级老白兔
2025-08-16 16:31:02 +08:00
parent 85f4ca9744
commit 7dd20b0a9b
7 changed files with 157 additions and 62 deletions

View File

@@ -1,4 +1,5 @@
# 基础环境变量示例
VITE_API_BASE_URL=http://www.yishi.com
VITE_API_BASE_URL2=https://kf.quwanzhi.com:9991
# VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
VITE_APP_TITLE=存客宝

View File

@@ -1,4 +1,5 @@
# 基础环境变量示例
VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
VITE_API_BASE_URL2=https://kf.quwanzhi.com:9991
# VITE_API_BASE_URL=http://www.yishi.com
VITE_APP_TITLE=存客宝

View File

@@ -6,7 +6,7 @@ import axios, {
} from "axios";
import { Toast } from "antd-mobile";
import { useUserStore } from "@/store/module/user";
const { token, token2 } = useUserStore.getState();
const { token } = useUserStore.getState();
const DEFAULT_DEBOUNCE_GAP = 1000;
const debounceMap = new Map<string, number>();
@@ -19,13 +19,7 @@ const instance: AxiosInstance = axios.create({
});
instance.interceptors.request.use((config: any) => {
// 从配置中获取是否使用token2
const useToken2 = config.useToken2;
if (useToken2 && token2) {
config.headers = config.headers || {};
config.headers["Authorization"] = `Bearer ${token2}`;
} else if (token) {
if (token) {
config.headers = config.headers || {};
config.headers["Authorization"] = `Bearer ${token}`;
}
@@ -62,7 +56,6 @@ export function request(
method: Method = "GET",
config?: AxiosRequestConfig,
debounceGap?: number,
isToken2?: boolean,
): Promise<any> {
const gap =
typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP;
@@ -79,10 +72,7 @@ export function request(
url,
method,
...config,
} as any;
// 添加自定义属性
(axiosConfig as any).useToken2 = isToken2;
};
// 如果是FormData不设置Content-Type让浏览器自动设置
if (data instanceof FormData) {

View File

@@ -0,0 +1,79 @@
import axios, {
AxiosInstance,
AxiosRequestConfig,
Method,
AxiosResponse,
} from "axios";
import { Toast } from "antd-mobile";
import { useUserStore } from "@/store/module/user";
const { token2 } = useUserStore.getState();
const DEFAULT_DEBOUNCE_GAP = 1000;
const debounceMap = new Map<string, number>();
interface RequestConfig extends AxiosRequestConfig {
headers: {
Client?: string;
"Content-Type"?: string;
};
}
const instance: AxiosInstance = axios.create({
baseURL: (import.meta as any).env?.VITE_API_BASE_URL2 || "/api",
timeout: 20000,
headers: {
"Content-Type": "application/json",
Client: "kefu-client",
},
});
instance.interceptors.request.use((config: any) => {
if (token2) {
config.headers = config.headers || {};
config.headers["Authorization"] = `Bearer ${token2}`;
}
return config;
});
instance.interceptors.response.use(
(res: AxiosResponse) => {
return res.data;
},
err => {
Toast.show({ content: err.message || "网络异常", position: "top" });
return Promise.reject(err);
},
);
export function request(
url: string,
data?: any,
method: Method = "GET",
config?: RequestConfig,
debounceGap?: number,
): Promise<any> {
const gap =
typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP;
const key = `${method}_${url}_${JSON.stringify(data)}`;
const now = Date.now();
const last = debounceMap.get(key) || 0;
if (gap > 0 && now - last < gap) {
// Toast.show({ content: '请求过于频繁,请稍后再试', position: 'top' });
return Promise.reject("请求过于频繁,请稍后再试");
}
debounceMap.set(key, now);
const axiosConfig: RequestConfig = {
url,
method,
...config,
};
if (method.toUpperCase() === "GET") {
axiosConfig.params = data;
} else {
axiosConfig.data = data;
}
return instance(axiosConfig);
}
export default request;

View File

@@ -7,7 +7,12 @@ import {
UserOutline,
} from "antd-mobile-icons";
import { useUserStore } from "@/store/module/user";
import { loginWithPassword, loginWithCode, sendVerificationCode } from "./api";
import {
loginWithPassword,
loginWithCode,
sendVerificationCode,
loginWithToken,
} from "./api";
import style from "./login.module.scss";
const Login: React.FC = () => {
@@ -18,7 +23,7 @@ const Login: React.FC = () => {
const [showPassword, setShowPassword] = useState(false);
const [agreeToTerms, setAgreeToTerms] = useState(false);
const { login } = useUserStore();
const { login, login2 } = useUserStore();
// 倒计时效果
useEffect(() => {
@@ -66,32 +71,59 @@ const Login: React.FC = () => {
Toast.show({ content: "请同意用户协议和隐私政策", position: "top" });
return;
}
setLoading(true);
try {
getToken(values)
.then(() => {
getToken2();
})
.finally(() => {
setLoading(false);
});
};
const getToken = (values: any) => {
return new Promise((resolve, reject) => {
// 添加typeId参数
const loginParams = {
...values,
typeId: activeTab as number,
};
let response;
if (activeTab === 1) {
response = await loginWithPassword(loginParams);
} else {
response = await loginWithCode(loginParams);
}
const response =
activeTab === 1
? loginWithPassword(loginParams)
: loginWithCode(loginParams);
// 获取设备总数
const deviceTotal = response.deviceTotal || 0;
response
.then(res => {
// 获取设备总数
const deviceTotal = res.deviceTotal || 0;
// 更新状态管理token会自动存储到localStorage用户信息存储在状态管理中
login(response.token, response.member, deviceTotal);
} catch (error: any) {
// 错误已在request中处理这里不需要额外处理
} finally {
setLoading(false);
}
// 更新状态管理token会自动存储到localStorage用户信息存储在状态管理中
login(res.token, res.member, deviceTotal);
resolve(res);
})
.catch(err => {
reject(err);
});
});
};
const getToken2 = () => {
return new Promise((resolve, reject) => {
const params = {
grant_type: "password",
password: "kr123456",
username: "kr_xf3",
};
const response = loginWithToken(params);
response.then(res => {
login2(res.access_token);
resolve(res);
});
response.catch(err => {
reject(err);
});
});
};
// 第三方登录处理

View File

@@ -1,33 +1,5 @@
import request from "@/api/request";
export interface LoginParams {
phone: string;
password?: string;
verificationCode?: string;
}
export interface LoginResponse {
code: number;
msg: string;
data: {
token: string;
token_expired: string;
deviceTotal: number; // 设备总数
member: {
id: string;
name: string;
phone: string;
s2_accountId: string;
avatar?: string;
email?: string;
};
};
}
export interface SendCodeResponse {
code: number;
msg: string;
}
import request2 from "@/api/request2";
// 密码登录
export function loginWithPassword(params: any) {
return request("/v1/auth/login", params, "POST");
@@ -52,3 +24,17 @@ export function logout() {
export function getUserInfo() {
return request("/v1/auth/user-info", {}, "GET");
}
//触客宝登陆
export function loginWithToken(params: any) {
return request2(
"/token",
params,
"POST",
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
1000,
);
}

View File

@@ -29,6 +29,7 @@ interface UserState {
setToken2: (token2: string) => void;
clearUser: () => void;
login: (token: string, userInfo: User, deviceTotal: number) => void;
login2: (token2: string) => void;
logout: () => void;
}
@@ -41,7 +42,8 @@ export const useUserStore = createPersistStore<UserState>(
setUser: user => set({ user, isLoggedIn: true }),
setToken: token => set({ token }),
setToken2: token2 => set({ token2 }),
clearUser: () => set({ user: null, token: null, token2: null, isLoggedIn: false }),
clearUser: () =>
set({ user: null, token: null, token2: null, isLoggedIn: false }),
login: (token, userInfo, deviceTotal) => {
// 只将token存储到localStorage
localStorage.setItem("token", token);
@@ -76,6 +78,10 @@ export const useUserStore = createPersistStore<UserState>(
window.location.href = "/guide";
}
},
login2: token2 => {
localStorage.setItem("token2", token2);
set({ token2, isLoggedIn: true });
},
logout: () => {
// 清除localStorage中的token
localStorage.removeItem("token");