finstep-template-cli 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/cli.js +117 -0
- package/package.json +39 -0
- package/template/.env.development +3 -0
- package/template/.env.production +3 -0
- package/template/.env.staging +3 -0
- package/template/.env.test +3 -0
- package/template/.eslintrc.cjs +21 -0
- package/template/README.md +69 -0
- package/template/auto-imports.d.ts +47 -0
- package/template/eslint.config.js +26 -0
- package/template/index.html +16 -0
- package/template/package.json +46 -0
- package/template/postcss.config.js +5 -0
- package/template/public/logo.svg +85 -0
- package/template/public/vite.svg +1 -0
- package/template/src/App.css +42 -0
- package/template/src/App.tsx +25 -0
- package/template/src/api/home/index.ts +56 -0
- package/template/src/api/home/typings.d.ts +8 -0
- package/template/src/assets/logo.svg +85 -0
- package/template/src/assets/react.svg +1 -0
- package/template/src/components/admin-layout.tsx +211 -0
- package/template/src/components/f-b-footer.tsx +46 -0
- package/template/src/components/f-b-header.tsx +894 -0
- package/template/src/components/global-loading.tsx +143 -0
- package/template/src/components/hero-section.tsx +371 -0
- package/template/src/components/products-preview.tsx +175 -0
- package/template/src/components/stats-section.tsx +85 -0
- package/template/src/components/trusted-by.tsx +53 -0
- package/template/src/hooks/useGlobalLoading.ts +57 -0
- package/template/src/index.css +341 -0
- package/template/src/main.tsx +30 -0
- package/template/src/pages/admin/index.tsx +361 -0
- package/template/src/pages/admin/pages/applications/index.tsx +558 -0
- package/template/src/pages/home/index.tsx +129 -0
- package/template/src/router/index.tsx +9 -0
- package/template/src/router/routes.tsx +30 -0
- package/template/src/stores/loading.store.ts +46 -0
- package/template/src/stores/root.store.ts +22 -0
- package/template/src/stores/store-context.tsx +43 -0
- package/template/src/stores/user.store.ts +46 -0
- package/template/src/utils/index.ts +14 -0
- package/template/src/utils/request.ts +116 -0
- package/template/src/utils/tokenManager.ts +168 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tailwind.config.js +19 -0
- package/template/tsconfig.app.json +29 -0
- package/template/tsconfig.json +7 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vite.config.ts +36 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
import { lazy } from "react";
|
2
|
+
import type { RouteObject } from "react-router-dom";
|
3
|
+
const Home = lazy(() => import("@/pages/home/index"));
|
4
|
+
const Admin = lazy(() => import("@/pages/admin/index"));
|
5
|
+
const Applications = lazy(() => import("@/pages/admin/pages/applications"));
|
6
|
+
const routes: RouteObject[] = [
|
7
|
+
{
|
8
|
+
path: "/",
|
9
|
+
children: [
|
10
|
+
{
|
11
|
+
index: true,
|
12
|
+
element: <Home />,
|
13
|
+
},
|
14
|
+
{
|
15
|
+
path: "/home",
|
16
|
+
element: <Home />,
|
17
|
+
},
|
18
|
+
{
|
19
|
+
path: "/admin",
|
20
|
+
element: <Admin />,
|
21
|
+
},
|
22
|
+
{
|
23
|
+
path: "/admin/applications",
|
24
|
+
element: <Applications />,
|
25
|
+
},
|
26
|
+
],
|
27
|
+
},
|
28
|
+
];
|
29
|
+
|
30
|
+
export default routes;
|
@@ -0,0 +1,46 @@
|
|
1
|
+
// AI生成的代码 - 全局Loading状态管理
|
2
|
+
import { makeAutoObservable } from "mobx";
|
3
|
+
import type { RootStore } from "./root.store";
|
4
|
+
|
5
|
+
export default class LoadingStore {
|
6
|
+
private rootStore: RootStore;
|
7
|
+
// AI生成的代码 - loading状态管理
|
8
|
+
isLoading = false;
|
9
|
+
loadingText = "加载中...";
|
10
|
+
loadingCount = 0; // 用于管理多个并发loading请求
|
11
|
+
|
12
|
+
constructor(rootStore: RootStore) {
|
13
|
+
makeAutoObservable(this);
|
14
|
+
this.rootStore = rootStore;
|
15
|
+
}
|
16
|
+
|
17
|
+
// AI生成的代码 - 显示loading
|
18
|
+
showLoading = (text?: string) => {
|
19
|
+
this.loadingCount++;
|
20
|
+
this.isLoading = true;
|
21
|
+
if (text) {
|
22
|
+
this.loadingText = text;
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
// AI生成的代码 - 隐藏loading
|
27
|
+
hideLoading = () => {
|
28
|
+
this.loadingCount = Math.max(0, this.loadingCount - 1);
|
29
|
+
if (this.loadingCount === 0) {
|
30
|
+
this.isLoading = false;
|
31
|
+
this.loadingText = "加载中...";
|
32
|
+
}
|
33
|
+
};
|
34
|
+
|
35
|
+
// AI生成的代码 - 强制隐藏loading(清除所有loading状态)
|
36
|
+
forceHideLoading = () => {
|
37
|
+
this.loadingCount = 0;
|
38
|
+
this.isLoading = false;
|
39
|
+
this.loadingText = "加载中...";
|
40
|
+
};
|
41
|
+
|
42
|
+
// AI生成的代码 - 设置loading文本
|
43
|
+
setLoadingText = (text: string) => {
|
44
|
+
this.loadingText = text;
|
45
|
+
};
|
46
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { makeAutoObservable } from "mobx";
|
2
|
+
import { makePersistable } from "mobx-persist-store";
|
3
|
+
import UserStore from "./user.store";
|
4
|
+
import LoadingStore from "./loading.store";
|
5
|
+
export class RootStore {
|
6
|
+
userStore: UserStore;
|
7
|
+
loadingStore: LoadingStore;
|
8
|
+
constructor() {
|
9
|
+
makeAutoObservable(this);
|
10
|
+
this.userStore = new UserStore(this);
|
11
|
+
this.loadingStore = new LoadingStore(this);
|
12
|
+
makePersistable(this.userStore, {
|
13
|
+
name: "UserStore",
|
14
|
+
properties: ["userInfo"],
|
15
|
+
storage: window.localStorage,
|
16
|
+
});
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
// 创建RootStore实例
|
21
|
+
export const rootStore = new RootStore();
|
22
|
+
export const getRootStore = () => rootStore;
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import React, { createContext, useContext, ReactNode } from "react";
|
2
|
+
import type { RootStore } from "./root.store";
|
3
|
+
import { rootStore } from "./root.store";
|
4
|
+
|
5
|
+
const StoreContext = createContext<RootStore | null>(null);
|
6
|
+
|
7
|
+
interface StoreProviderProps {
|
8
|
+
children: ReactNode;
|
9
|
+
}
|
10
|
+
|
11
|
+
export const StoreProvider: React.FC<StoreProviderProps> = ({
|
12
|
+
children,
|
13
|
+
}: {
|
14
|
+
children: ReactNode;
|
15
|
+
}) => {
|
16
|
+
return (
|
17
|
+
<StoreContext.Provider value={rootStore}>{children}</StoreContext.Provider>
|
18
|
+
);
|
19
|
+
};
|
20
|
+
|
21
|
+
let globalStore: RootStore | null = null;
|
22
|
+
|
23
|
+
export const setGlobalStore = (store: RootStore) => {
|
24
|
+
globalStore = store;
|
25
|
+
};
|
26
|
+
|
27
|
+
export const getStore = () => {
|
28
|
+
if (!globalStore) {
|
29
|
+
throw new Error("Store not initialized");
|
30
|
+
}
|
31
|
+
return globalStore;
|
32
|
+
};
|
33
|
+
|
34
|
+
export const useStore = () => {
|
35
|
+
const store = useContext(StoreContext);
|
36
|
+
if (!store) {
|
37
|
+
throw new Error("useStore must be used within a StoreProvider");
|
38
|
+
}
|
39
|
+
if (!globalStore) {
|
40
|
+
setGlobalStore(store);
|
41
|
+
}
|
42
|
+
return store;
|
43
|
+
};
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { makeAutoObservable, runInAction } from "mobx";
|
2
|
+
import type { RootStore } from "./root.store";
|
3
|
+
interface userInfoType {
|
4
|
+
userId: number | string;
|
5
|
+
login: boolean;
|
6
|
+
phone?: string;
|
7
|
+
avatar?: string; // AI生成的代码 - 用户头像
|
8
|
+
username?: string; // AI生成的代码 - 用户名
|
9
|
+
accessToken?: string;
|
10
|
+
refreshToken?: string;
|
11
|
+
}
|
12
|
+
export default class User {
|
13
|
+
userInfo: userInfoType;
|
14
|
+
// @ts-expect-error RootStore circular dependency with User store
|
15
|
+
constructor(private rootStore: RootStore) {
|
16
|
+
this.rootStore = rootStore;
|
17
|
+
this.userInfo = {
|
18
|
+
userId: "",
|
19
|
+
login: false,
|
20
|
+
phone: "",
|
21
|
+
avatar: "", // AI生成的代码 - 默认头像
|
22
|
+
username: "", // AI生成的代码 - 默认用户名
|
23
|
+
accessToken: "",
|
24
|
+
refreshToken: "",
|
25
|
+
};
|
26
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
27
|
+
}
|
28
|
+
setUserInfo(userInfo: userInfoType) {
|
29
|
+
runInAction(() => {
|
30
|
+
this.userInfo = userInfo;
|
31
|
+
});
|
32
|
+
}
|
33
|
+
|
34
|
+
// AI生成:退出登录方法
|
35
|
+
logout() {
|
36
|
+
runInAction(() => {
|
37
|
+
this.userInfo = {
|
38
|
+
userId: "",
|
39
|
+
login: false,
|
40
|
+
phone: "",
|
41
|
+
avatar: "",
|
42
|
+
username: "",
|
43
|
+
};
|
44
|
+
});
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
export const getQueryParams = () => {
|
2
|
+
const url = window.location.href;
|
3
|
+
let queryString = "";
|
4
|
+
|
5
|
+
if (url.includes("#")) {
|
6
|
+
// Hash 路由
|
7
|
+
queryString = url.split("#")[1].split("?")[1];
|
8
|
+
} else {
|
9
|
+
// History 路由
|
10
|
+
queryString = window.location.search.substring(1);
|
11
|
+
}
|
12
|
+
const urlParams = new URLSearchParams(queryString);
|
13
|
+
return Object.fromEntries(urlParams.entries());
|
14
|
+
};
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import axios from "axios";
|
2
|
+
import { showError } from "finstep-b-components";
|
3
|
+
import type {
|
4
|
+
AxiosResponse,
|
5
|
+
AxiosError,
|
6
|
+
InternalAxiosRequestConfig,
|
7
|
+
} from "axios";
|
8
|
+
import { tokenManager } from "./tokenManager";
|
9
|
+
// AI生成的代码 - 自定义请求配置接口,支持登录接口标识
|
10
|
+
export interface CustomAxiosRequestConfig {
|
11
|
+
url?: string;
|
12
|
+
method?: string;
|
13
|
+
data?: unknown;
|
14
|
+
params?: unknown;
|
15
|
+
headers?: Record<string, string>;
|
16
|
+
timeout?: number;
|
17
|
+
isLoginApi?: boolean; // AI生成的代码 - 标识是否为登录接口
|
18
|
+
[key: string]: unknown;
|
19
|
+
}
|
20
|
+
|
21
|
+
export const baseURL = import.meta.env.VITE_API_URL;
|
22
|
+
export const baseHeader = {
|
23
|
+
"Content-Type": "application/json",
|
24
|
+
};
|
25
|
+
const request = axios.create({
|
26
|
+
baseURL,
|
27
|
+
timeout: 10000,
|
28
|
+
headers: {
|
29
|
+
...baseHeader,
|
30
|
+
},
|
31
|
+
});
|
32
|
+
|
33
|
+
// AI生成的代码 - 为 request 函数添加类型重载,支持自定义配置
|
34
|
+
interface RequestFunction {
|
35
|
+
<T = unknown>(config: CustomAxiosRequestConfig): Promise<T>;
|
36
|
+
<T = unknown>(url: string, config?: CustomAxiosRequestConfig): Promise<T>;
|
37
|
+
}
|
38
|
+
|
39
|
+
// AI生成的代码 - 创建类型安全的 request 函数
|
40
|
+
const typedRequest = request as RequestFunction;
|
41
|
+
|
42
|
+
// AI生成的代码 - 请求拦截器,处理登录接口的特殊认证
|
43
|
+
request.interceptors.request.use(
|
44
|
+
(config: InternalAxiosRequestConfig & { isLoginApi?: boolean }) => {
|
45
|
+
if (config.isLoginApi) {
|
46
|
+
if (!config.headers) {
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
48
|
+
config.headers = {} as any;
|
49
|
+
}
|
50
|
+
config.headers["authorization"] = "Basic Y2FpeXVlOmNhaXl1ZQ==";
|
51
|
+
}
|
52
|
+
return config;
|
53
|
+
},
|
54
|
+
(error: AxiosError) => {
|
55
|
+
return Promise.reject(error);
|
56
|
+
}
|
57
|
+
);
|
58
|
+
|
59
|
+
// AI生成的代码 - 响应拦截器,处理 401 错误和 token 刷新
|
60
|
+
request.interceptors.response.use(
|
61
|
+
(response: AxiosResponse) => {
|
62
|
+
if (response.data.code !== 0) {
|
63
|
+
if (response.data.msg) {
|
64
|
+
showError(response.data.msg);
|
65
|
+
return Promise.reject(response.data);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
return response.data.data;
|
69
|
+
},
|
70
|
+
async (error: AxiosError) => {
|
71
|
+
if (error.response) {
|
72
|
+
switch (error.response.status) {
|
73
|
+
case 400:
|
74
|
+
console.error(error.response?.data);
|
75
|
+
break;
|
76
|
+
case 401: {
|
77
|
+
console.error("未授权,请重新登录");
|
78
|
+
const { config: axiosConfig } = error;
|
79
|
+
if (!axiosConfig) return Promise.reject(error);
|
80
|
+
try {
|
81
|
+
// 使用 TokenManager 处理 401 错误
|
82
|
+
await tokenManager.handle401Error(axiosConfig);
|
83
|
+
return await request(axiosConfig);
|
84
|
+
} catch (refreshError) {
|
85
|
+
// 刷新失败,跳转到登录页
|
86
|
+
window.location.href = "/login";
|
87
|
+
return Promise.reject(
|
88
|
+
refreshError instanceof Error
|
89
|
+
? refreshError
|
90
|
+
: new Error(String(refreshError))
|
91
|
+
);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
case 403:
|
95
|
+
console.error("拒绝访问");
|
96
|
+
break;
|
97
|
+
case 404:
|
98
|
+
console.error("请求的资源不存在");
|
99
|
+
break;
|
100
|
+
case 500:
|
101
|
+
showError("服务异常,请稍后再试");
|
102
|
+
break;
|
103
|
+
default:
|
104
|
+
console.error("发生错误:", error.message);
|
105
|
+
}
|
106
|
+
} else if (error.request) {
|
107
|
+
console.error("网络错误,请检查您的网络连接");
|
108
|
+
} else {
|
109
|
+
console.error("请求配置错误:", (error as Error).message);
|
110
|
+
}
|
111
|
+
return Promise.reject(error);
|
112
|
+
}
|
113
|
+
);
|
114
|
+
|
115
|
+
// AI生成的代码 - 导出类型安全的 request 函数
|
116
|
+
export default typedRequest;
|
@@ -0,0 +1,168 @@
|
|
1
|
+
// AI生成的代码 - Token 管理器,处理 token 刷新和请求队列
|
2
|
+
import { refreshToken } from "@/api/home";
|
3
|
+
import type { AxiosRequestConfig } from "axios";
|
4
|
+
import { getRootStore } from "@/stores/root.store";
|
5
|
+
// AI生成的代码 - 请求队列项接口
|
6
|
+
interface QueueItem {
|
7
|
+
config: AxiosRequestConfig;
|
8
|
+
resolve: (value: AxiosRequestConfig) => void;
|
9
|
+
reject: (reason?: Error) => void;
|
10
|
+
}
|
11
|
+
|
12
|
+
// AI生成的代码 - Token 管理器类
|
13
|
+
class TokenManager {
|
14
|
+
private isRefreshing = false; // 是否正在刷新 token
|
15
|
+
private requestQueue: QueueItem[] = []; // 请求队列
|
16
|
+
private refreshDebounceTimer: number | null = null; // 防抖定时器
|
17
|
+
private readonly DEBOUNCE_DELAY = 100; // 防抖延迟时间(毫秒)
|
18
|
+
|
19
|
+
/**
|
20
|
+
* AI生成的代码 - 判断是否为登录相关接口
|
21
|
+
* @param config 请求配置
|
22
|
+
* @returns 是否为登录接口
|
23
|
+
*/
|
24
|
+
private isLoginApi(
|
25
|
+
config: AxiosRequestConfig & { isLoginApi?: boolean }
|
26
|
+
): boolean {
|
27
|
+
// 检查自定义标识
|
28
|
+
if (config.isLoginApi) {
|
29
|
+
return true;
|
30
|
+
}
|
31
|
+
|
32
|
+
// 检查 URL 路径
|
33
|
+
const loginPaths = ["/auth/oauth2/token"];
|
34
|
+
|
35
|
+
const url = config.url || "";
|
36
|
+
return loginPaths.some((path) => url.includes(path));
|
37
|
+
}
|
38
|
+
|
39
|
+
/**
|
40
|
+
* AI生成的代码 - 获取存储的 refresh token
|
41
|
+
* @returns refresh token 或 null
|
42
|
+
*/
|
43
|
+
private getRefreshToken(): string | null {
|
44
|
+
return getRootStore().userStore.userInfo.refreshToken || "";
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* AI生成的代码 - 保存新的 token 信息
|
49
|
+
* @param tokenData token 数据
|
50
|
+
*/
|
51
|
+
private saveTokens(tokenData: {
|
52
|
+
access_token?: string;
|
53
|
+
refresh_token?: string;
|
54
|
+
}): void {
|
55
|
+
getRootStore().userStore.setUserInfo({
|
56
|
+
...getRootStore().userStore.userInfo,
|
57
|
+
accessToken: tokenData.access_token || "",
|
58
|
+
refreshToken: tokenData.refresh_token || "",
|
59
|
+
});
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* AI生成的代码 - 清除所有 token
|
64
|
+
*/
|
65
|
+
private clearTokens(): void {
|
66
|
+
getRootStore().userStore.setUserInfo({
|
67
|
+
userId: "",
|
68
|
+
login: false,
|
69
|
+
phone: "",
|
70
|
+
avatar: "", // AI生成的代码 - 默认头像
|
71
|
+
username: "", // AI生成的代码 - 默认用户名
|
72
|
+
accessToken: "",
|
73
|
+
refreshToken: "",
|
74
|
+
});
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* AI生成的代码 - 处理队列中的请求
|
79
|
+
* @param error 错误信息(如果刷新失败)
|
80
|
+
*/
|
81
|
+
private processQueue(error?: Error): void {
|
82
|
+
this.requestQueue.forEach(({ resolve, reject, config }) => {
|
83
|
+
if (error) {
|
84
|
+
reject(error);
|
85
|
+
} else {
|
86
|
+
resolve(config);
|
87
|
+
}
|
88
|
+
});
|
89
|
+
this.requestQueue = [];
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* AI生成的代码 - 刷新 token
|
94
|
+
* @returns Promise<void>
|
95
|
+
*/
|
96
|
+
async refreshToken(): Promise<void> {
|
97
|
+
const refreshTokenValue = this.getRefreshToken();
|
98
|
+
|
99
|
+
if (!refreshTokenValue) {
|
100
|
+
this.clearTokens();
|
101
|
+
throw new Error("No refresh token available");
|
102
|
+
}
|
103
|
+
|
104
|
+
try {
|
105
|
+
const response = await refreshToken({
|
106
|
+
refresh_token: refreshTokenValue,
|
107
|
+
});
|
108
|
+
|
109
|
+
this.saveTokens(response);
|
110
|
+
this.processQueue(); // 处理队列中的请求
|
111
|
+
} catch (error) {
|
112
|
+
this.clearTokens();
|
113
|
+
this.processQueue(
|
114
|
+
error instanceof Error ? error : new Error(String(error))
|
115
|
+
); // 确保传递Error类型的错误给队列中的请求
|
116
|
+
throw error;
|
117
|
+
} finally {
|
118
|
+
this.isRefreshing = false;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* AI生成的代码 - 处理 401 错误,支持请求队列和防抖
|
124
|
+
* @param config 原始请求配置
|
125
|
+
* @returns Promise<any>
|
126
|
+
*/
|
127
|
+
async handle401Error(
|
128
|
+
config: AxiosRequestConfig & { isLoginApi?: boolean }
|
129
|
+
): Promise<AxiosRequestConfig> {
|
130
|
+
// 如果是登录接口,直接拒绝
|
131
|
+
if (this.isLoginApi(config)) {
|
132
|
+
return Promise.reject(new Error("Login API returned 401"));
|
133
|
+
}
|
134
|
+
|
135
|
+
return new Promise((resolve, reject) => {
|
136
|
+
// 将请求添加到队列
|
137
|
+
this.requestQueue.push({ config, resolve, reject });
|
138
|
+
|
139
|
+
// 如果已经在刷新中,直接返回
|
140
|
+
if (this.isRefreshing) {
|
141
|
+
return;
|
142
|
+
}
|
143
|
+
|
144
|
+
// 清除之前的防抖定时器
|
145
|
+
if (this.refreshDebounceTimer) {
|
146
|
+
clearTimeout(this.refreshDebounceTimer);
|
147
|
+
}
|
148
|
+
|
149
|
+
// 设置防抖定时器
|
150
|
+
this.refreshDebounceTimer = setTimeout(async () => {
|
151
|
+
this.isRefreshing = true;
|
152
|
+
|
153
|
+
try {
|
154
|
+
await this.refreshToken();
|
155
|
+
} catch (error) {
|
156
|
+
// 刷新失败,清除队列
|
157
|
+
this.processQueue(
|
158
|
+
error instanceof Error ? error : new Error(String(error))
|
159
|
+
);
|
160
|
+
}
|
161
|
+
}, this.DEBOUNCE_DELAY);
|
162
|
+
});
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
// AI生成的代码 - 导出单例实例
|
167
|
+
export const tokenManager = new TokenManager();
|
168
|
+
export default TokenManager;
|
@@ -0,0 +1 @@
|
|
1
|
+
/// <reference types="vite/client" />
|
@@ -0,0 +1,19 @@
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
2
|
+
// AI生成的代码 - Tailwind CSS配置文件
|
3
|
+
export default {
|
4
|
+
content: [
|
5
|
+
"./index.html",
|
6
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
7
|
+
],
|
8
|
+
theme: {
|
9
|
+
extend: {
|
10
|
+
fontFamily: {
|
11
|
+
'pacifico': ['Pacifico', 'cursive'],
|
12
|
+
'inter': ['Inter', 'sans-serif'],
|
13
|
+
'jetbrains': ['JetBrains Mono', 'monospace'],
|
14
|
+
},
|
15
|
+
},
|
16
|
+
},
|
17
|
+
plugins: [],
|
18
|
+
}
|
19
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
4
|
+
"target": "ES2020",
|
5
|
+
"useDefineForClassFields": true,
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
7
|
+
"module": "ESNext",
|
8
|
+
"skipLibCheck": true,
|
9
|
+
|
10
|
+
/* Bundler mode */
|
11
|
+
"moduleResolution": "bundler",
|
12
|
+
"allowImportingTsExtensions": true,
|
13
|
+
"isolatedModules": true,
|
14
|
+
"moduleDetection": "force",
|
15
|
+
"noEmit": true,
|
16
|
+
"jsx": "react-jsx",
|
17
|
+
"baseUrl": ".",
|
18
|
+
"paths": {
|
19
|
+
"@/*": ["src/*"]
|
20
|
+
},
|
21
|
+
/* Linting */
|
22
|
+
"strict": true,
|
23
|
+
"noUnusedLocals": true,
|
24
|
+
"noUnusedParameters": true,
|
25
|
+
"noFallthroughCasesInSwitch": true,
|
26
|
+
"noUncheckedSideEffectImports": true
|
27
|
+
},
|
28
|
+
"include": ["src", "./auto-imports.d.ts"]
|
29
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
4
|
+
"target": "ES2023",
|
5
|
+
"lib": ["ES2023"],
|
6
|
+
"module": "ESNext",
|
7
|
+
"skipLibCheck": true,
|
8
|
+
"types": ["node"],
|
9
|
+
|
10
|
+
/* Bundler mode */
|
11
|
+
"moduleResolution": "bundler",
|
12
|
+
"allowImportingTsExtensions": true,
|
13
|
+
"verbatimModuleSyntax": true,
|
14
|
+
"moduleDetection": "force",
|
15
|
+
"noEmit": true,
|
16
|
+
|
17
|
+
/* Linting */
|
18
|
+
"strict": true,
|
19
|
+
"noUnusedLocals": true,
|
20
|
+
"noUnusedParameters": true,
|
21
|
+
"erasableSyntaxOnly": true,
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
23
|
+
"noUncheckedSideEffectImports": true
|
24
|
+
},
|
25
|
+
"include": ["vite.config.ts"]
|
26
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { defineConfig } from "vite";
|
2
|
+
import react from "@vitejs/plugin-react";
|
3
|
+
import AutoImport from "unplugin-auto-import/vite";
|
4
|
+
import { resolve } from "path";
|
5
|
+
// https://vite.dev/config/
|
6
|
+
export default defineConfig({
|
7
|
+
plugins: [
|
8
|
+
react(),
|
9
|
+
AutoImport({
|
10
|
+
// 这里可以配置自动导入的库,例如 vue、react 等
|
11
|
+
imports: ["react", "react-router-dom", "react-router"], // 根据需要选择要自动导入的库
|
12
|
+
// 其他配置项
|
13
|
+
dts: "auto-imports.d.ts", // 可以生成 TypeScript 声明文件
|
14
|
+
}),
|
15
|
+
],
|
16
|
+
resolve: {
|
17
|
+
alias: {
|
18
|
+
"@": resolve(__dirname, "./src"),
|
19
|
+
},
|
20
|
+
},
|
21
|
+
server: {
|
22
|
+
port: 80,
|
23
|
+
host: "0.0.0.0",
|
24
|
+
// AI生成的代码 - 添加允许的主机列表以解决被阻止的请求问题
|
25
|
+
// allowedHosts: ["sso-login.finstep.cn"],
|
26
|
+
proxy: {
|
27
|
+
"/api": {
|
28
|
+
// 免费的在线REST API
|
29
|
+
// target: "http://10.159.0.130:9527",
|
30
|
+
target: "http://product-test.finstep.cn",
|
31
|
+
changeOrigin: true,
|
32
|
+
rewrite: (path) => path.replace(/^\/api/, ""),
|
33
|
+
},
|
34
|
+
},
|
35
|
+
},
|
36
|
+
});
|