Compare commits

..

No commits in common. "47bc37ac2ce9724f45af65ac23272d50224ca3ed" and "bc75c7885cb49cda4c42c6be7733987f0b67fd68" have entirely different histories.

8 changed files with 92 additions and 133 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "neer-app-h5", "name": "neer-app-h5",
"private": true, "private": true,
"version": "1.0.1", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@ -1,10 +1,8 @@
import axios, { AxiosRequestConfig, AxiosRequestHeaders } from "axios"; import axios, { AxiosRequestConfig, AxiosRequestHeaders } from 'axios';
//基础URLaxios将会自动拼接在url前 //基础URLaxios将会自动拼接在url前
//process.env.NODE_ENV 判断是否为开发环境 根据不同环境使用不同的baseURL 方便调试 //process.env.NODE_ENV 判断是否为开发环境 根据不同环境使用不同的baseURL 方便调试
const baseURL = import.meta.env.DEV const baseURL = import.meta.env.DEV ? import.meta.env.VITE_API_URL : import.meta.env.VITE_API_URL;
? import.meta.env.VITE_API_URL
: import.meta.env.VITE_API_URL;
//默认请求超时时间 //默认请求超时时间
const timeout = 30000; const timeout = 30000;
@ -13,37 +11,34 @@ const service = axios.create({
timeout, timeout,
baseURL, baseURL,
//如需要携带cookie 该值需设为true //如需要携带cookie 该值需设为true
withCredentials: true, withCredentials: true
}); });
// 统一请求拦截,可配置自定义 headers 例如 language、token 等 // 统一请求拦截,可配置自定义 headers 例如 language、token 等
service.interceptors.request.use( service.interceptors.request.use(
(config: any): any => { (config: any): any => {
// 确保 headers 对象存在 // 确保 headers 对象存在
if (!config.headers) { if (!config.headers) {
config.headers = {}; config.headers = {};
} }
// 配置自定义请求头 // 配置自定义请求头
const customHeaders: Partial<AxiosRequestHeaders> = { const customHeaders: Partial<AxiosRequestHeaders> = {
// language: "zh-cn", language: 'zh-cn',
// 这里可以添加其他自定义头信息,例如 token // 这里可以添加其他自定义头信息,例如 token
}; };
// 合并自定义头信息到 config.headers 中 // 合并自定义头信息到 config.headers 中
config.headers = { config.headers = { ...config.headers, ...customHeaders } as AxiosRequestHeaders;
...config.headers,
...customHeaders,
} as AxiosRequestHeaders;
return config; return config;
}, },
(error) => { error => {
console.log(error); console.log(error);
return Promise.reject(error); return Promise.reject(error);
} }
); );
//axios返回格式 //axios返回格式
interface axiosTypes<T> { interface axiosTypes<T>{
data: T; data: T;
status: number; status: number;
statusText: string; statusText: string;
@ -52,75 +47,66 @@ interface axiosTypes<T> {
//后台响应数据格式 //后台响应数据格式
//###该接口用于规定后台返回的数据格式意为必须携带code、msg以及result //###该接口用于规定后台返回的数据格式意为必须携带code、msg以及result
//###而result的数据格式 由外部提供。如此即可根据不同需求,定制不同的数据格式 //###而result的数据格式 由外部提供。如此即可根据不同需求,定制不同的数据格式
interface responseTypes<T> { interface responseTypes<T>{
code: number; code: number,
msg: string; msg: string,
result: T; result: T
} }
//核心处理代码 将返回一个promise 调用then将可获取响应的业务数据 //核心处理代码 将返回一个promise 调用then将可获取响应的业务数据
const requestHandler = <T>( const requestHandler = <T>(method: 'get' | 'post' | 'put' | 'delete', url: string, params: object = {}, config: AxiosRequestConfig = {}): Promise<T> => {
method: "get" | "post" | "put" | "delete",
url: string,
params: object = {},
config: AxiosRequestConfig = {}
): Promise<T> => {
let response: Promise<axiosTypes<responseTypes<T>>>; let response: Promise<axiosTypes<responseTypes<T>>>;
switch (method) { switch(method){
case "get": case 'get':
response = service.get(url, { params: { ...params }, ...config }); response = service.get(url, {params: { ...params }, ...config});
break; break;
case "post": case 'post':
response = service.post(url, { ...params }, { ...config }); response = service.post(url, {...params}, {...config});
break; break;
case "put": case 'put':
response = service.put(url, { ...params }, { ...config }); response = service.put(url, {...params}, {...config});
break; break;
case "delete": case 'delete':
response = service.delete(url, { params: { ...params }, ...config }); response = service.delete(url, {params: { ...params }, ...config});
break; break;
} }
return new Promise<T>((resolve, reject) => { return new Promise<T>((resolve, reject) => {
response response.then(res => {
.then((res) => { //业务代码 可根据需求自行处理
//业务代码 可根据需求自行处理
const data = res.data; const data = res.data;
if (data.code !== 200 && data.code !== 0) { if(data.code !== 200 && data.code !== 0){
//特定状态码 处理特定的需求
if (data.code == 401) { //特定状态码 处理特定的需求
console.log("登录异常,执行登出..."); if(data.code == 401){
} console.log('登录异常,执行登出...');
const e = JSON.stringify(data);
console.log(`请求错误:${e}`);
//数据请求错误 使用reject将错误返回
reject(data);
} else {
//数据请求正确 使用resolve将结果返回
resolve(res as T);
} }
})
.catch((error) => { const e = JSON.stringify(data);
const e = JSON.stringify(error); console.log(`请求错误:${e}`)
console.log(`网络错误:${e}`); //数据请求错误 使用reject将错误返回
reject(error); reject(data);
}); }else{
}); //数据请求正确 使用resolve将结果返回
}; resolve(res as T);
}
}).catch(error => {
const e = JSON.stringify(error);
console.log(`网络错误:${e}`)
reject(error);
})
})
}
// 使用 request 统一调用包括封装的get、post、put、delete等方法 // 使用 request 统一调用包括封装的get、post、put、delete等方法
const request = { const request = {
get: <T>(url: string, params?: object, config?: AxiosRequestConfig) => get: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('get', url, params, config),
requestHandler<T>("get", url, params, config), post: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('post', url, params, config),
post: <T>(url: string, params?: object, config?: AxiosRequestConfig) => put: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('put', url, params, config),
requestHandler<T>("post", url, params, config), delete: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('delete', url, params, config)
put: <T>(url: string, params?: object, config?: AxiosRequestConfig) =>
requestHandler<T>("put", url, params, config),
delete: <T>(url: string, params?: object, config?: AxiosRequestConfig) =>
requestHandler<T>("delete", url, params, config),
}; };
// 导出至外层,方便统一使用 // 导出至外层,方便统一使用
export { request }; export { request };

View File

@ -10,7 +10,6 @@ import { Toast } from "antd-mobile";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { Md5 } from "ts-md5"; import { Md5 } from "ts-md5";
import { FormInstance } from "antd-mobile/es/components/form"; import { FormInstance } from "antd-mobile/es/components/form";
import useUserStore from "../store/user";
function EmailForm() { function EmailForm() {
const formRef = useRef<FormInstance>(null); const formRef = useRef<FormInstance>(null);
@ -21,11 +20,10 @@ function EmailForm() {
const [authCode, setAuthCode] = useState(""); const [authCode, setAuthCode] = useState("");
const [shareCode, setShareCode] = useState(""); const [shareCode, setShareCode] = useState("");
const [remainingTime, setRemainingTime] = useState(0); const [remainingTime, setRemainingTime] = useState(0);
const { Lang } = useUserStore();
const config = { const config = {
headers: { headers: {
"Accept-Language": Lang, "Accept-Language": navigator.language,
}, },
}; };
const sendVerificationCode = async () => { const sendVerificationCode = async () => {

View File

@ -20,7 +20,6 @@ function PhoneForm() {
CurrentPhoneNumber, CurrentPhoneNumber,
UpdateCurrentPhoneNumber, UpdateCurrentPhoneNumber,
UpdatePreviousPathName, UpdatePreviousPathName,
Lang,
} = useUserStore(); } = useUserStore();
const getShareCode = (url: string) => { const getShareCode = (url: string) => {
@ -52,7 +51,7 @@ function PhoneForm() {
}; };
const config = { const config = {
headers: { headers: {
"Accept-Language": Lang, "Accept-Language": navigator.language,
}, },
}; };
const sendVerificationCode = async () => { const sendVerificationCode = async () => {
@ -154,7 +153,6 @@ function PhoneForm() {
console.warn(error); console.warn(error);
} }
}; };
return ( return (
<Form <Form
name="form" name="form"
@ -179,14 +177,6 @@ function PhoneForm() {
name="account" name="account"
rules={[ rules={[
{ required: true, message: t("Please enter your phone number") }, { required: true, message: t("Please enter your phone number") },
{
validator: (_, v) => {
if (v != "" && !/^\d+$/.test(v)) {
return Promise.reject(new Error(t("Invalid phone number")));
}
return Promise.resolve();
},
},
]} ]}
> >
<div className="phone-box"> <div className="phone-box">

View File

@ -19,6 +19,5 @@
"Official Website": "官方網站", "Official Website": "官方網站",
"Download": "下載", "Download": "下載",
"send successfully": "發送成功", "send successfully": "發送成功",
"Send failure": "發送失敗", "Send failure": "發送失敗"
"Invalid phone number": "無效手機號碼" }
}

View File

@ -1,24 +1,23 @@
{ {
"E-mail": "E-mail", "E-mail": "E-mail",
"phone": "phone", "phone":"phone",
"Please enter your email address": "Please enter your email address", "Please enter your email address":"Please enter your email address",
"Please enter the email verification code": "Please enter the email verification code", "Please enter the email verification code":"Please enter the email verification code",
"Please enter your phone number": "Please enter your phone number", "Please enter your phone number":"Please enter your phone number",
"Please enter SMS verification code": "Please enter SMS verification code", "Please enter SMS verification code":"Please enter SMS verification code",
"Send verification code": "Send verification code", "Send verification code":"Send verification code",
"Please enter the invitation code (optional)": "Please enter the invitation code (optional)", "Please enter the invitation code (optional)":"Please enter the invitation code (optional)",
"register": "Register", "register":"Register",
"If you already have an account": "If you already have an account", "If you already have an account":"If you already have an account",
"download the APP directly": "download the APP directly", "download the APP directly":"download the APP directly",
"Continuing to represent you in agreeing to our": "Continuing to represent you in agreeing to our", "Continuing to represent you in agreeing to our":"Continuing to represent you in agreeing to our",
"Terms of Service": "Terms of Service", "Terms of Service":"Terms of Service",
"and": "and", "and":"and",
"Privacy Policy": "Privacy Policy", "Privacy Policy":"Privacy Policy",
"Select country/region": "Select country/region", "Select country/region":"Select country/region",
"seconds": "s", "seconds": "s",
"Official Website": "Official Website", "Official Website":"Official Website",
"Download": "Download", "Download":"Download",
"send successfully": "send successfully", "send successfully":"send successfully",
"Send failure": "Send failure", "Send failure":"Send failure"
"Invalid phone number": "Invalid phone number"
} }

View File

@ -20,7 +20,6 @@ function SignIn() {
const [selectIndex, setSelectIndex] = useState<number>(0); const [selectIndex, setSelectIndex] = useState<number>(0);
const { previousPathName, UpdatePreviousPathName } = useUserStore(); const { previousPathName, UpdatePreviousPathName } = useUserStore();
const navigate = useNavigate(); const navigate = useNavigate();
const { UpdateLang } = useUserStore();
const handleTabs = (num: number) => { const handleTabs = (num: number) => {
return () => { return () => {
UpdatePreviousPathName("/"); UpdatePreviousPathName("/");
@ -71,7 +70,6 @@ function SignIn() {
onClick={() => { onClick={() => {
i18n.changeLanguage("cn"); i18n.changeLanguage("cn");
setVisible(false); setVisible(false);
UpdateLang("zh-TW");
}} }}
> >
@ -82,7 +80,6 @@ function SignIn() {
onClick={() => { onClick={() => {
i18n.changeLanguage("en"); i18n.changeLanguage("en");
setVisible(false); setVisible(false);
UpdateLang("en-US");
}} }}
> >
English English

View File

@ -1,25 +1,21 @@
/* /*
* @LastEditors: John * @LastEditors: John
* @Date: 2024-01-19 11:31:12 * @Date: 2024-01-19 11:31:12
* @LastEditTime: 2024-06-03 14:52:45 * @LastEditTime: 2024-01-25 15:42:25
* @Author: John * @Author: John
*/ */
import { create } from "zustand"; import { create } from "zustand";
import { CountryItem } from "../type/SelectCountry"; import { CountryItem } from "../type/SelectCountry";
export type LanguageCode = "en-US" | "zh-CN" | "zh-TW" | "ko-KR";
// 状态管理器 // 状态管理器
export interface UserState { export interface UserState {
SelectCountry: CountryItem | null; SelectCountry: CountryItem | null;
UpdateSelectCountry: (item: CountryItem) => void; UpdateSelectCountry: (item: CountryItem) => void
Token: string; Token: string;
UpdateToken: (token: string) => void; UpdateToken: (token: string) => void;
CurrentPhoneNumber: string; CurrentPhoneNumber:string;
UpdateCurrentPhoneNumber: (number: string) => void; UpdateCurrentPhoneNumber: (number: string) => void;
previousPathName: string; previousPathName:string;
UpdatePreviousPathName: (number: string) => void; UpdatePreviousPathName:(number: string) => void;
Lang: LanguageCode;
UpdateLang: (lan: LanguageCode) => void;
} }
const useUserStore = create<UserState>()((set) => ({ const useUserStore = create<UserState>()((set) => ({
@ -34,22 +30,16 @@ const useUserStore = create<UserState>()((set) => ({
set((state) => { set((state) => {
return { ...state, Token: token }; return { ...state, Token: token };
}), }),
CurrentPhoneNumber: "", CurrentPhoneNumber:'',
UpdateCurrentPhoneNumber: (val) => UpdateCurrentPhoneNumber: (val) =>
set((state) => { set((state) => {
return { ...state, CurrentPhoneNumber: val }; return { ...state, CurrentPhoneNumber: val };
}), }),
previousPathName: "/", previousPathName:'/',
UpdatePreviousPathName: (url) => UpdatePreviousPathName:(url) =>
set((state) => { set((state)=>{
return { ...state, previousPathName: url }; return {...state,previousPathName:url}
}), })
Lang: "en-US",
UpdateLang: (Lang) => {
set((state) => {
return { ...state, Lang };
});
},
})); }));
export default useUserStore; export default useUserStore;