first commit

This commit is contained in:
liu
2026-07-13 15:23:29 +08:00
commit 50885a98c8
473 changed files with 33772 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
import useAuthStore from "@/stores/user";
function useAuth() {
const access = useAuthStore(state => state.access);
const auth = (key: string) => access.includes(key);
return {auth};
}
export default useAuth;
+48
View File
@@ -0,0 +1,48 @@
import {useTranslation} from 'react-i18next';
import {useMemo} from 'react';
import dayjs from 'dayjs';
import options from '@/locales/options';
/**
* 语言切换 Hook
*/
const useLanguage = () => {
const { i18n } = useTranslation();
/**
* 切换语言
* @param lng 语言代码
*/
const changeLanguage = async (lng: string) => {
const config = getLanguageConfig(lng);
dayjs.locale(config.dayjsLocale);
await i18n.changeLanguage(lng);
localStorage.setItem('i18nextLng', lng);
};
/**
* 获取当前语言配置对象
*/
const getLanguageConfig = (lng: string) => {
return options.find(opt => opt.value === lng) || options[0];
};
/**
* Antd Locale Hook
*/
const antdLocale = useMemo(() => {
const currentLang = i18n.language;
const config = options.find(opt => opt.value === currentLang);
return config ? config.antdLocale : options[0].antdLocale;
}, [i18n.language]);
return {
antdLocale,
language: i18n.language,
changeLanguage,
getLanguageConfig,
languageOptions: options,
};
};
export default useLanguage;
+31
View File
@@ -0,0 +1,31 @@
import { useState, useEffect } from 'react';
/**
* 移动端检测Hook
* 根据屏幕宽度检测设备类型,默认768px以下为移动端
*/
const useMobile = (breakpoint: number = 768): boolean => {
const [isMobile, setIsMobile] = useState<boolean>(false);
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < breakpoint);
};
// 初始检测
checkMobile();
// 监听窗口大小变化
window.addEventListener('resize', checkMobile);
window.addEventListener('orientationchange', checkMobile);
return () => {
window.removeEventListener('resize', checkMobile);
window.removeEventListener('orientationchange', checkMobile);
};
}, [breakpoint]);
return isMobile;
};
export default useMobile;
+76
View File
@@ -0,0 +1,76 @@
import { useState, useCallback } from 'react';
import type { AxiosResponse, AxiosError } from 'axios';
interface UseRequestOptions<T> {
manual?: boolean;
onSuccess?: (data: T | undefined, response: AxiosResponse<API.ResponseStructure<T>>) => void;
onError?: (error: AxiosError) => void;
onFinally?: () => void;
}
interface UseRequestResult<T> {
data: T | undefined;
loading: boolean;
success: boolean | null;
error: AxiosError | null;
run: (...args: any[]) => Promise<AxiosResponse<API.ResponseStructure<T>> | undefined>;
}
function useRequest<T = any>(
apiFunction: (...args: any[]) => Promise<AxiosResponse<API.ResponseStructure<T>>>,
options: UseRequestOptions<T> = {}
): UseRequestResult<T> {
const { manual = false, onSuccess, onError, onFinally } = options;
const [data, setData] = useState<T>();
const [loading, setLoading] = useState(!manual);
const [success, setSuccess] = useState<boolean | null>(null);
const [error, setError] = useState<AxiosError | null>(null);
const run = useCallback(
async (...args: any[]) => {
try {
setLoading(true);
setSuccess(null);
setError(null);
const response = await apiFunction(...args);
setData(response.data.data);
setSuccess(true);
if (onSuccess) {
onSuccess(response.data.data, response);
}
return response;
} catch (err) {
const axiosError = err as AxiosError;
setError(axiosError);
setSuccess(false);
if (onError) {
onError(axiosError);
}
return undefined;
} finally {
setLoading(false);
if (onFinally) {
onFinally();
}
}
},
[apiFunction, onSuccess, onError, onFinally]
);
// 自动执行
useState(() => {
if (!manual) {
run();
}
});
return { data, loading, success, error, run };
}
export default useRequest;