@4399ywkf/cli 1.0.7 → 1.0.8
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/dist/templates/HarmonyOS_Sans_Bold.woff2 +0 -0
- package/dist/templates/HarmonyOS_Sans_Medium.woff2 +0 -0
- package/dist/templates/HarmonyOS_Sans_Regular.woff2 +0 -0
- package/dist/templates/Locale.tsx +14 -18
- package/dist/templates/MainContentWrap.tsx +11 -15
- package/dist/templates/ThemeContext.tsx +27 -24
- package/dist/templates/app/config/env/.env.public.tpl +2 -19
- package/dist/templates/app/config/jwt/index.ts +4 -4
- package/dist/templates/app/config/request/error-handler.ts +67 -0
- package/dist/templates/app/config/request/index.ts +127 -129
- package/dist/templates/app/config/request/interceptors.ts +118 -0
- package/dist/templates/app/config/request/token-manager.ts +23 -0
- package/dist/templates/app/config/request/types.ts +63 -0
- package/dist/templates/app/config/rspack/rspack.config.mjs +62 -61
- package/dist/templates/app/config/rspack/rspack.prod.mjs +41 -62
- package/dist/templates/app/locales/zh-CN/common.json +3 -0
- package/dist/templates/app/package.json.tpl +1 -10
- package/dist/templates/app/public/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
- package/dist/templates/app/public/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
- package/dist/templates/app/public/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
- package/dist/templates/app/react-app-env.d.ts +13 -8
- package/dist/templates/app/src/bootstrap/index.ts +34 -0
- package/dist/templates/app/src/config/env.ts +84 -0
- package/dist/templates/app/src/index.tsx +17 -51
- package/dist/templates/app/src/layout/Locale.tsx +14 -18
- package/dist/templates/app/src/layout/MainContentWrap.tsx +11 -15
- package/dist/templates/app/src/layout/ThemeContext.tsx +27 -24
- package/dist/templates/app/src/locales/default/common.ts +3 -1
- package/dist/templates/app/src/micro/garfish.ts +53 -0
- package/dist/templates/app/src/pages/base/index.tsx +189 -25
- package/dist/templates/app/src/routes.tsx +21 -12
- package/dist/templates/app/src/types/global.d.ts +19 -0
- package/dist/templates/app/src/utils/index.ts +3 -1
- package/dist/templates/app/store/middleware/createDevtools.ts +7 -7
- package/dist/templates/base/index.tsx +189 -25
- package/dist/templates/bootstrap/index.ts +34 -0
- package/dist/templates/common.json +3 -0
- package/dist/templates/common.ts +3 -1
- package/dist/templates/config/env/.env.public.tpl +2 -19
- package/dist/templates/config/env.ts +84 -0
- package/dist/templates/config/jwt/index.ts +4 -4
- package/dist/templates/config/request/error-handler.ts +67 -0
- package/dist/templates/config/request/index.ts +127 -129
- package/dist/templates/config/request/interceptors.ts +118 -0
- package/dist/templates/config/request/token-manager.ts +23 -0
- package/dist/templates/config/request/types.ts +63 -0
- package/dist/templates/config/rspack/rspack.config.mjs +62 -61
- package/dist/templates/config/rspack/rspack.prod.mjs +41 -62
- package/dist/templates/createDevtools.ts +7 -7
- package/dist/templates/default/common.ts +3 -1
- package/dist/templates/env/.env.public.tpl +2 -19
- package/dist/templates/env.ts +83 -2
- package/dist/templates/error-handler.ts +67 -0
- package/dist/templates/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
- package/dist/templates/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
- package/dist/templates/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
- package/dist/templates/garfish.ts +53 -0
- package/dist/templates/global.d.ts +19 -0
- package/dist/templates/index.tsx +189 -25
- package/dist/templates/interceptors.ts +118 -0
- package/dist/templates/jwt/index.ts +4 -4
- package/dist/templates/layout/Locale.tsx +14 -18
- package/dist/templates/layout/MainContentWrap.tsx +11 -15
- package/dist/templates/layout/ThemeContext.tsx +27 -24
- package/dist/templates/locales/default/common.ts +3 -1
- package/dist/templates/locales/zh-CN/common.json +3 -0
- package/dist/templates/micro/garfish.ts +53 -0
- package/dist/templates/middleware/createDevtools.ts +7 -7
- package/dist/templates/package.json.tpl +1 -10
- package/dist/templates/page.tsx +21 -19
- package/dist/templates/pages/base/index.tsx +189 -25
- package/dist/templates/public/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
- package/dist/templates/public/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
- package/dist/templates/public/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
- package/dist/templates/react-app-env.d.ts +13 -8
- package/dist/templates/request/error-handler.ts +67 -0
- package/dist/templates/request/index.ts +127 -129
- package/dist/templates/request/interceptors.ts +118 -0
- package/dist/templates/request/token-manager.ts +23 -0
- package/dist/templates/request/types.ts +63 -0
- package/dist/templates/routes.tsx +21 -12
- package/dist/templates/rspack/rspack.config.mjs +62 -61
- package/dist/templates/rspack/rspack.prod.mjs +41 -62
- package/dist/templates/rspack.config.mjs +62 -61
- package/dist/templates/rspack.prod.mjs +41 -62
- package/dist/templates/src/bootstrap/index.ts +34 -0
- package/dist/templates/src/config/env.ts +84 -0
- package/dist/templates/src/index.tsx +17 -51
- package/dist/templates/src/layout/Locale.tsx +14 -18
- package/dist/templates/src/layout/MainContentWrap.tsx +11 -15
- package/dist/templates/src/layout/ThemeContext.tsx +27 -24
- package/dist/templates/src/locales/default/common.ts +3 -1
- package/dist/templates/src/micro/garfish.ts +53 -0
- package/dist/templates/src/pages/base/index.tsx +189 -25
- package/dist/templates/src/routes.tsx +21 -12
- package/dist/templates/src/types/global.d.ts +19 -0
- package/dist/templates/src/utils/index.ts +3 -1
- package/dist/templates/store/middleware/createDevtools.ts +7 -7
- package/dist/templates/token-manager.ts +23 -0
- package/dist/templates/types/global.d.ts +19 -0
- package/dist/templates/utils/index.ts +3 -1
- package/dist/templates/zh-CN/common.json +3 -0
- package/package.json +1 -1
- package/dist/templates/app/config/sentry/sentry.config.ts +0 -188
- package/dist/templates/app/src/hooks/useRouteTitle.tsx +0 -36
- package/dist/templates/app/src/hooks/useSentry.ts +0 -92
- package/dist/templates/app/src/pages/base/layout.tsx +0 -6
- package/dist/templates/app/src/pages/base/page.tsx +0 -25
- package/dist/templates/app/src/utils/env.ts +0 -3
- package/dist/templates/app/src/utils/format.ts +0 -21
- package/dist/templates/app/src/utils/getMicroApp.ts +0 -39
- package/dist/templates/app/src/utils/sentry.ts +0 -187
- package/dist/templates/app/src/utils/sentryDecorators.ts +0 -34
- package/dist/templates/app/src/utils/updateVersion.ts +0 -186
- package/dist/templates/base/layout.tsx +0 -6
- package/dist/templates/base/page.tsx +0 -25
- package/dist/templates/config/public/404.png +0 -0
- package/dist/templates/config/public/favicon.ico +0 -0
- package/dist/templates/config/public/images/banner_market_modal.webp +0 -0
- package/dist/templates/config/public/images/chatmode_chat_dark.webp +0 -0
- package/dist/templates/config/public/images/chatmode_chat_light.webp +0 -0
- package/dist/templates/config/public/images/chatmode_docs_dark.webp +0 -0
- package/dist/templates/config/public/images/chatmode_docs_light.webp +0 -0
- package/dist/templates/config/public/images/empty_topic_dark.webp +0 -0
- package/dist/templates/config/public/images/empty_topic_light.webp +0 -0
- package/dist/templates/config/public/images/screenshot_background.webp +0 -0
- package/dist/templates/config/public/images/theme_auto.webp +0 -0
- package/dist/templates/config/public/images/theme_dark.webp +0 -0
- package/dist/templates/config/public/images/theme_light.webp +0 -0
- package/dist/templates/config/public/index.html +0 -29
- package/dist/templates/config/sentry/sentry.config.ts +0 -188
- package/dist/templates/format.ts +0 -21
- package/dist/templates/getMicroApp.ts +0 -39
- package/dist/templates/hooks/useRouteTitle.tsx +0 -36
- package/dist/templates/hooks/useSentry.ts +0 -92
- package/dist/templates/layout.tsx +0 -6
- package/dist/templates/pages/base/layout.tsx +0 -6
- package/dist/templates/pages/base/page.tsx +0 -25
- package/dist/templates/sentry/sentry.config.ts +0 -188
- package/dist/templates/sentry.config.ts +0 -188
- package/dist/templates/sentry.ts +0 -187
- package/dist/templates/sentryDecorators.ts +0 -34
- package/dist/templates/src/hooks/useRouteTitle.tsx +0 -36
- package/dist/templates/src/hooks/useSentry.ts +0 -92
- package/dist/templates/src/pages/base/layout.tsx +0 -6
- package/dist/templates/src/pages/base/page.tsx +0 -25
- package/dist/templates/src/utils/env.ts +0 -3
- package/dist/templates/src/utils/format.ts +0 -21
- package/dist/templates/src/utils/getMicroApp.ts +0 -39
- package/dist/templates/src/utils/sentry.ts +0 -187
- package/dist/templates/src/utils/sentryDecorators.ts +0 -34
- package/dist/templates/src/utils/updateVersion.ts +0 -186
- package/dist/templates/updateVersion.ts +0 -186
- package/dist/templates/useRouteTitle.tsx +0 -36
- package/dist/templates/useSentry.ts +0 -92
- package/dist/templates/utils/env.ts +0 -3
- package/dist/templates/utils/format.ts +0 -21
- package/dist/templates/utils/getMicroApp.ts +0 -39
- package/dist/templates/utils/sentry.ts +0 -187
- package/dist/templates/utils/sentryDecorators.ts +0 -34
- package/dist/templates/utils/updateVersion.ts +0 -186
- /package/dist/templates/app/{config/public → public}/404.png +0 -0
- /package/dist/templates/app/{config/public → public}/favicon.ico +0 -0
- /package/dist/templates/app/{config/public → public}/images/banner_market_modal.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/chatmode_chat_dark.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/chatmode_chat_light.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/chatmode_docs_dark.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/chatmode_docs_light.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/empty_topic_dark.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/empty_topic_light.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/screenshot_background.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/theme_auto.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/theme_dark.webp +0 -0
- /package/dist/templates/app/{config/public → public}/images/theme_light.webp +0 -0
- /package/dist/templates/app/{config/public → public}/index.html +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { ConfigProvider } from
|
|
2
|
-
import type { Locale as AntdLocale } from
|
|
3
|
-
import dayjs from
|
|
1
|
+
import { ConfigProvider } from "antd";
|
|
2
|
+
import type { Locale as AntdLocale } from "antd/es/locale";
|
|
3
|
+
import dayjs from "dayjs";
|
|
4
4
|
import React, {
|
|
5
5
|
type PropsWithChildren,
|
|
6
6
|
memo,
|
|
7
7
|
useEffect,
|
|
8
8
|
useState,
|
|
9
|
-
} from
|
|
9
|
+
} from "react";
|
|
10
10
|
|
|
11
|
-
import { isRtlLang } from
|
|
11
|
+
import { isRtlLang } from "rtl-detect";
|
|
12
12
|
|
|
13
|
-
import { createI18nNext } from
|
|
14
|
-
import { getAntdLocale } from
|
|
13
|
+
import { createI18nNext } from "@/locales/create";
|
|
14
|
+
import { getAntdLocale } from "@/utils/locale";
|
|
15
15
|
|
|
16
16
|
const updateDayjs = async (lang: string) => {
|
|
17
17
|
// load default lang
|
|
@@ -19,12 +19,12 @@ const updateDayjs = async (lang: string) => {
|
|
|
19
19
|
try {
|
|
20
20
|
// dayjs locale is using `en` instead of `en-US`
|
|
21
21
|
// refs: https://github.com/lobehub/lobe-chat/issues/3396
|
|
22
|
-
const locale = lang.toLowerCase() ===
|
|
22
|
+
const locale = lang.toLowerCase() === "en-us" ? "en" : lang.toLowerCase();
|
|
23
23
|
|
|
24
24
|
dayJSLocale = await import(`dayjs/locale/${locale}.js`);
|
|
25
25
|
} catch {
|
|
26
26
|
console.warn(`dayjs locale for ${lang} not found, fallback to en`);
|
|
27
|
-
dayJSLocale = await import(
|
|
27
|
+
dayJSLocale = await import("dayjs/locale/en.js");
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
dayjs.locale(dayJSLocale.default);
|
|
@@ -41,8 +41,6 @@ const Locale = memo<LocaleLayoutProps>(
|
|
|
41
41
|
const [lang, setLang] = useState(defaultLang);
|
|
42
42
|
const [locale, setLocale] = useState(antdLocale);
|
|
43
43
|
|
|
44
|
-
console.log(antdLocale, defaultLang);
|
|
45
|
-
|
|
46
44
|
// if on browser side, init i18n instance only once
|
|
47
45
|
if (!i18n.instance.isInitialized)
|
|
48
46
|
// console.debug('locale', lang);
|
|
@@ -65,25 +63,23 @@ const Locale = memo<LocaleLayoutProps>(
|
|
|
65
63
|
await updateDayjs(lng);
|
|
66
64
|
};
|
|
67
65
|
|
|
68
|
-
i18n.instance.on(
|
|
66
|
+
i18n.instance.on("languageChanged", handleLang);
|
|
69
67
|
return () => {
|
|
70
|
-
i18n.instance.off(
|
|
68
|
+
i18n.instance.off("languageChanged", handleLang);
|
|
71
69
|
};
|
|
72
70
|
}, [i18n, lang]);
|
|
73
71
|
|
|
74
72
|
// detect document direction
|
|
75
|
-
const documentDir = isRtlLang(lang) ?
|
|
76
|
-
|
|
77
|
-
console.log(documentDir, locale);
|
|
73
|
+
const documentDir = isRtlLang(lang) ? "rtl" : "ltr";
|
|
78
74
|
|
|
79
75
|
return (
|
|
80
76
|
<ConfigProvider direction={documentDir} locale={locale as AntdLocale}>
|
|
81
77
|
{children}
|
|
82
78
|
</ConfigProvider>
|
|
83
79
|
);
|
|
84
|
-
}
|
|
80
|
+
}
|
|
85
81
|
);
|
|
86
82
|
|
|
87
|
-
Locale.displayName =
|
|
83
|
+
Locale.displayName = "Locale";
|
|
88
84
|
|
|
89
85
|
export default Locale;
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Locale as AntdLocale } from 'antd/es/locale';
|
|
3
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
4
2
|
|
|
5
|
-
import { QueryClient, QueryClientProvider } from
|
|
6
|
-
import { Outlet } from
|
|
7
|
-
import
|
|
8
|
-
import { DEFAULT_LANG } from
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import AppTheme from './ThemeContext';
|
|
3
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
4
|
+
import { Outlet } from "react-router";
|
|
5
|
+
import "../index.css";
|
|
6
|
+
import { DEFAULT_LANG } from "@/const/locale";
|
|
7
|
+
import { getAntdLocale } from "@/utils";
|
|
8
|
+
import queryString from "query-string";
|
|
9
|
+
import Locale from "./Locale";
|
|
10
|
+
import AppTheme from "./ThemeContext";
|
|
14
11
|
|
|
15
12
|
export const MainContentWrap = () => {
|
|
16
|
-
useRouteTitle();
|
|
17
13
|
const [antdLocale, setAntdLocale] = useState<unknown>(null);
|
|
18
14
|
const [isLocaleLoaded, setIsLocaleLoaded] = useState(false);
|
|
19
15
|
|
|
@@ -32,11 +28,11 @@ export const MainContentWrap = () => {
|
|
|
32
28
|
const loadLocale = async () => {
|
|
33
29
|
try {
|
|
34
30
|
const loadedLocale = await getAntdLocale(
|
|
35
|
-
(lang as string) ?? DEFAULT_LANG
|
|
31
|
+
(lang as string) ?? DEFAULT_LANG
|
|
36
32
|
);
|
|
37
33
|
setAntdLocale(loadedLocale);
|
|
38
34
|
} catch (error) {
|
|
39
|
-
console.error(
|
|
35
|
+
console.error("Failed to load locale:", error);
|
|
40
36
|
// 保持默认的中文 locale
|
|
41
37
|
} finally {
|
|
42
38
|
setIsLocaleLoaded(true);
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import ThemeProvider from
|
|
2
|
-
import { CLOUD_THEME_APPEARANCE } from
|
|
3
|
-
import { setCookie } from
|
|
1
|
+
import ThemeProvider from "@/components/ThemeProvider";
|
|
2
|
+
import { CLOUD_THEME_APPEARANCE } from "@/const/theme";
|
|
3
|
+
import { setCookie } from "@/utils/cookie";
|
|
4
4
|
|
|
5
5
|
// import { useGlobalStore } from "@store/global";
|
|
6
|
-
import React, { memo, useEffect, type ReactNode } from
|
|
6
|
+
import React, { memo, useEffect, type ReactNode } from "react";
|
|
7
|
+
|
|
8
|
+
import { SYSTEM_PREFIX } from "@/const/system";
|
|
9
|
+
import { GlobalStyle } from "@/styles";
|
|
10
|
+
import { useUserStore } from "@store/user";
|
|
11
|
+
import { createStyles } from "antd-style";
|
|
12
|
+
import HarmonyOS_Sans_Regular from "@public/fonts/HarmonyOS_Sans_Regular.woff2";
|
|
7
13
|
|
|
8
|
-
import { SYSTEM_PREFIX } from '@/const/system';
|
|
9
|
-
import { GlobalStyle } from '@/styles';
|
|
10
|
-
import { useUserStore } from '@store/user';
|
|
11
|
-
import { createStyles } from 'antd-style';
|
|
12
14
|
const useStyles = createStyles(({ css, token }) => ({
|
|
13
15
|
app: css`
|
|
14
16
|
position: relative;
|
|
@@ -70,55 +72,56 @@ interface AppThemeProps {
|
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
const AppTheme = memo(({ children }: AppThemeProps) => {
|
|
73
|
-
const themeMode = useUserStore(s => s.themeMode);
|
|
74
|
-
const animationMode = useUserStore(s => s.animationMode);
|
|
75
|
-
const neutralColor = useUserStore(s => s.neutralColor);
|
|
76
|
-
const primaryColor = useUserStore(s => s.primaryColor);
|
|
75
|
+
const themeMode = useUserStore((s) => s.themeMode);
|
|
76
|
+
const animationMode = useUserStore((s) => s.animationMode);
|
|
77
|
+
const neutralColor = useUserStore((s) => s.neutralColor);
|
|
78
|
+
const primaryColor = useUserStore((s) => s.primaryColor);
|
|
77
79
|
const { styles, cx } = useStyles();
|
|
78
80
|
|
|
79
81
|
useEffect(() => {
|
|
80
82
|
// Update data-theme accordingly if user selects light or dark
|
|
81
|
-
if (themeMode !==
|
|
83
|
+
if (themeMode !== "auto") {
|
|
82
84
|
document.documentElement.dataset.theme = themeMode;
|
|
83
85
|
return;
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
// For auto mode, we need to watch system preferences
|
|
87
|
-
const mediaQuery = window.matchMedia(
|
|
89
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
88
90
|
|
|
89
91
|
// Set initial theme based on system preference
|
|
90
92
|
document.documentElement.dataset.theme = mediaQuery.matches
|
|
91
|
-
?
|
|
92
|
-
:
|
|
93
|
+
? "dark"
|
|
94
|
+
: "light";
|
|
93
95
|
|
|
94
96
|
// Update theme when system preference changes
|
|
95
97
|
function handleChange(e) {
|
|
96
|
-
document.documentElement.dataset.theme = e.matches ?
|
|
98
|
+
document.documentElement.dataset.theme = e.matches ? "dark" : "light";
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
mediaQuery.addEventListener(
|
|
100
|
-
return () => mediaQuery.removeEventListener(
|
|
101
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
102
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
101
103
|
}, [themeMode]);
|
|
102
104
|
|
|
103
105
|
return (
|
|
104
106
|
<ThemeProvider
|
|
105
107
|
prefixCls={SYSTEM_PREFIX}
|
|
106
|
-
appearance={themeMode !==
|
|
108
|
+
appearance={themeMode !== "auto" ? themeMode : undefined}
|
|
107
109
|
className={cx(styles.app, styles.scrollbar, styles.scrollbarPolyfill)}
|
|
108
110
|
customTheme={{
|
|
109
111
|
neutralColor: neutralColor,
|
|
110
112
|
primaryColor: primaryColor,
|
|
111
113
|
}}
|
|
114
|
+
customFonts={[HarmonyOS_Sans_Regular]}
|
|
112
115
|
theme={{
|
|
113
116
|
cssVar: true,
|
|
114
117
|
token: {
|
|
115
|
-
motion: animationMode !==
|
|
116
|
-
motionUnit: animationMode ===
|
|
118
|
+
motion: animationMode !== "disabled",
|
|
119
|
+
motionUnit: animationMode === "agile" ? 0.05 : 0.1,
|
|
117
120
|
},
|
|
118
121
|
}}
|
|
119
122
|
themeMode={themeMode}
|
|
120
|
-
onAppearanceChange={appearance => {
|
|
121
|
-
if (themeMode !==
|
|
123
|
+
onAppearanceChange={(appearance) => {
|
|
124
|
+
if (themeMode !== "auto") return;
|
|
122
125
|
|
|
123
126
|
setCookie(CLOUD_THEME_APPEARANCE, appearance);
|
|
124
127
|
}}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
API_PREFIX="/api"
|
|
2
|
-
API_TIMEOUT=
|
|
2
|
+
API_TIMEOUT=60000
|
|
3
3
|
|
|
4
4
|
COOKIE_NAME='ywkf_jwt'
|
|
5
5
|
|
|
@@ -9,23 +9,6 @@ OUTPUT_PATH='dist'
|
|
|
9
9
|
BASENAME='/'
|
|
10
10
|
|
|
11
11
|
PUBLIC_PATH='/s{{{ name }}}/'
|
|
12
|
-
VERSION_NOTIFY_TIME=30000
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# Sentry 配置 - (官网)
|
|
16
|
-
# REACT_APP_SENTRY_DSN="https://95add4dc797c22aa2224494e4abd4d71@o4509466151878656.ingest.us.sentry.io/4509466153058304"
|
|
17
|
-
# SENTRY_PROJECT="javascript-react"
|
|
18
|
-
# SENTRY_ORG="test-x6m"
|
|
19
|
-
# SENTRY_AUTH_TOKEN="d477b94cfe375f5b4e4e88ac4fc15a8be8557652cea424710b6f7f19be4f0b3d"
|
|
20
|
-
# SENTRY_URL="https://test-x6m.sentry.io/"
|
|
21
12
|
|
|
22
13
|
# 帮助中心
|
|
23
|
-
HELP_CENTER_URL="https://im-support.gz4399.com/"
|
|
24
|
-
|
|
25
|
-
# 是否开启Sentry
|
|
26
|
-
SENTRY_ENABLED='{{SENTRY_ENABLED}}'
|
|
27
|
-
REACT_APP_SENTRY_DSN='{{SENTRY_DSN}}'
|
|
28
|
-
SENTRY_PROJECT='{{{ name }}}'
|
|
29
|
-
SENTRY_ORG="sentry"
|
|
30
|
-
SENTRY_AUTH_TOKEN="f13c66cd7a3629c8324cceb62fdb65aae1f337abbec4ebbadbe0a22447708994"
|
|
31
|
-
SENTRY_URL="https://sentry.gz4399.com/"
|
|
14
|
+
HELP_CENTER_URL="https://im-support.gz4399.com/"
|
|
@@ -20,12 +20,12 @@ export default class jwt {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// 获取访问令牌
|
|
23
|
-
static getAccessToken(accessTokenKey
|
|
24
|
-
return Cookies.get(accessTokenKey);
|
|
23
|
+
static getAccessToken(accessTokenKey?: string) {
|
|
24
|
+
return Cookies.get(accessTokenKey ?? this.key);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// 清空访问令牌
|
|
28
|
-
static clearAccessToken(accessTokenKey
|
|
29
|
-
Cookies.remove(accessTokenKey);
|
|
28
|
+
static clearAccessToken(accessTokenKey?: string) {
|
|
29
|
+
Cookies.remove(accessTokenKey ?? this.key);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { message as antdMessage } from "antd";
|
|
2
|
+
import type { AxiosError } from "axios";
|
|
3
|
+
import type { RequestConfig, ApiResponse } from "./types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 错误处理器
|
|
7
|
+
*/
|
|
8
|
+
export class ErrorHandler {
|
|
9
|
+
/**
|
|
10
|
+
* 处理请求错误
|
|
11
|
+
*/
|
|
12
|
+
handle(error: any, config?: RequestConfig): void {
|
|
13
|
+
const messageConfig = config?.message;
|
|
14
|
+
|
|
15
|
+
// 如果明确禁用错误提示
|
|
16
|
+
if (messageConfig?.showError === false) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const axiosError = error as AxiosError<ApiResponse>;
|
|
21
|
+
let errorMessage = messageConfig?.errorMessage;
|
|
22
|
+
|
|
23
|
+
// 如果没有自定义错误消息,使用默认逻辑
|
|
24
|
+
if (!errorMessage) {
|
|
25
|
+
if (axiosError.response) {
|
|
26
|
+
const { status, data } = axiosError.response;
|
|
27
|
+
|
|
28
|
+
// 优先使用后端返回的消息
|
|
29
|
+
errorMessage = data?.message;
|
|
30
|
+
|
|
31
|
+
// 如果后端没有返回消息,使用默认消息
|
|
32
|
+
if (!errorMessage) {
|
|
33
|
+
errorMessage = this.getDefaultErrorMessage(status);
|
|
34
|
+
}
|
|
35
|
+
} else if (axiosError.request) {
|
|
36
|
+
errorMessage = "网络错误,请检查您的网络连接";
|
|
37
|
+
} else {
|
|
38
|
+
errorMessage = axiosError.message || "请求失败";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 显示错误提示
|
|
43
|
+
antdMessage.error(errorMessage);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 获取默认错误消息
|
|
48
|
+
*/
|
|
49
|
+
private getDefaultErrorMessage(status: number): string {
|
|
50
|
+
const errorMessages: Record<number, string> = {
|
|
51
|
+
400: "请求参数错误",
|
|
52
|
+
401: "未授权,请重新登录",
|
|
53
|
+
403: "拒绝访问",
|
|
54
|
+
404: "请求的资源不存在",
|
|
55
|
+
405: "请求方法不允许",
|
|
56
|
+
408: "请求超时",
|
|
57
|
+
500: "服务器内部错误",
|
|
58
|
+
502: "网关错误",
|
|
59
|
+
503: "服务暂时不可用",
|
|
60
|
+
504: "网关超时",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return errorMessages[status] || `请求失败 (${status})`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const errorHandler = new ErrorHandler();
|
|
@@ -1,174 +1,172 @@
|
|
|
1
|
-
import
|
|
2
|
-
import axios, {
|
|
3
|
-
type AxiosInstance,
|
|
4
|
-
type AxiosRequestConfig,
|
|
5
|
-
type AxiosResponse,
|
|
6
|
-
} from "axios";
|
|
1
|
+
import axios, { type AxiosInstance } from "axios";
|
|
7
2
|
import qs from "qs";
|
|
8
|
-
|
|
9
|
-
type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
subSequest = [];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function getRefreshToken(token: string) {
|
|
35
|
-
return fetch(`${baseURL}/dns/auth/login/token/refresh`, {
|
|
36
|
-
headers: {
|
|
37
|
-
authorization: token,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function redirectToLogin() {
|
|
43
|
-
// 记录当前的url,并且实现跳转
|
|
44
|
-
if (window.location.pathname === "/login") {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
jwt.clearAccessToken(accessTokenKey as string);
|
|
48
|
-
jwt.clearAccessToken("refresh_token");
|
|
49
|
-
const href = encodeURIComponent(window.location.href);
|
|
50
|
-
window.location.href = `${window.location.origin}/login?redirect=${href}`;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// 刷新token
|
|
54
|
-
function refreshToken() {
|
|
55
|
-
if (!flag) {
|
|
56
|
-
flag = true;
|
|
57
|
-
// 获取刷新token
|
|
58
|
-
const r_tk = jwt.getAccessToken("refresh_token");
|
|
59
|
-
if (r_tk) {
|
|
60
|
-
// 判断刷新token是否过期
|
|
61
|
-
getRefreshToken(r_tk)
|
|
62
|
-
.then((v) => v.json())
|
|
63
|
-
.then((v) => {
|
|
64
|
-
flag = false;
|
|
65
|
-
if (!v?.data?.accessToken) {
|
|
66
|
-
redirectToLogin();
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
jwt.setAccessToken({
|
|
70
|
-
token_type: v.data?.tokenType ?? "JWT",
|
|
71
|
-
access_token: v.data?.accessToken,
|
|
72
|
-
expires_at: v.data?.expires_at * 1000,
|
|
73
|
-
});
|
|
74
|
-
// 重新发送请求
|
|
75
|
-
retryRequest();
|
|
76
|
-
})
|
|
77
|
-
.catch(() => {
|
|
78
|
-
redirectToLogin();
|
|
79
|
-
});
|
|
80
|
-
} else {
|
|
81
|
-
redirectToLogin();
|
|
3
|
+
import { env } from "@/config/env";
|
|
4
|
+
import type { RequestConfig, ApiResponse, TokenManager } from "./types";
|
|
5
|
+
import { tokenManager as defaultTokenManager } from "./token-manager";
|
|
6
|
+
import {
|
|
7
|
+
errorHandler as defaultErrorHandler,
|
|
8
|
+
type ErrorHandler,
|
|
9
|
+
} from "./error-handler";
|
|
10
|
+
import {
|
|
11
|
+
setupRequestInterceptor,
|
|
12
|
+
setupResponseInterceptor,
|
|
13
|
+
} from "./interceptors";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 参数序列化器
|
|
17
|
+
*/
|
|
18
|
+
export function paramsSerializer(params: Record<string, any>): string {
|
|
19
|
+
const result: Record<string, any> = {};
|
|
20
|
+
|
|
21
|
+
Object.keys(params).forEach((key) => {
|
|
22
|
+
const value = params[key];
|
|
23
|
+
if (value === null || value === undefined) {
|
|
24
|
+
// 跳过 null 和 undefined
|
|
25
|
+
return;
|
|
82
26
|
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function paramsSerializer(params) {
|
|
87
|
-
const result = {};
|
|
88
|
-
Object.keys(params).forEach((p) => {
|
|
89
|
-
const value = params[p];
|
|
90
27
|
if (Array.isArray(value)) {
|
|
91
|
-
result[
|
|
92
|
-
} else if (value === null || value === undefined) {
|
|
93
|
-
result[p] = value;
|
|
28
|
+
result[key] = value;
|
|
94
29
|
} else if (typeof value === "object") {
|
|
95
|
-
result[
|
|
30
|
+
result[key] = JSON.stringify(value);
|
|
96
31
|
} else {
|
|
97
|
-
result[
|
|
32
|
+
result[key] = value;
|
|
98
33
|
}
|
|
99
34
|
});
|
|
35
|
+
|
|
100
36
|
return qs.stringify(result, { arrayFormat: "repeat", skipNulls: true });
|
|
101
37
|
}
|
|
102
38
|
|
|
103
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Request 配置选项
|
|
41
|
+
*/
|
|
42
|
+
export interface RequestOptions {
|
|
43
|
+
baseURL?: string;
|
|
44
|
+
timeout?: number;
|
|
45
|
+
tokenManager?: TokenManager;
|
|
46
|
+
errorHandler?: ErrorHandler;
|
|
47
|
+
onUnauthorized?: () => void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* HTTP 请求类
|
|
52
|
+
*/
|
|
104
53
|
export class Request {
|
|
105
|
-
// axios 实例
|
|
106
54
|
private instance: AxiosInstance;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
55
|
+
public tokenManager: TokenManager;
|
|
56
|
+
public errorHandler: ErrorHandler;
|
|
57
|
+
|
|
58
|
+
constructor(options: RequestOptions = {}) {
|
|
59
|
+
const {
|
|
60
|
+
baseURL = env.API_PREFIX,
|
|
61
|
+
timeout = env.API_TIMEOUT,
|
|
62
|
+
tokenManager = defaultTokenManager,
|
|
63
|
+
errorHandler = defaultErrorHandler,
|
|
64
|
+
onUnauthorized,
|
|
65
|
+
} = options;
|
|
66
|
+
|
|
67
|
+
this.tokenManager = tokenManager;
|
|
68
|
+
this.errorHandler = errorHandler;
|
|
69
|
+
|
|
70
|
+
// 创建 axios 实例
|
|
71
|
+
this.instance = axios.create({
|
|
72
|
+
baseURL,
|
|
73
|
+
timeout,
|
|
74
|
+
withCredentials: true,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 设置拦截器
|
|
78
|
+
setupRequestInterceptor(this.instance, tokenManager);
|
|
79
|
+
setupResponseInterceptor(
|
|
80
|
+
this.instance,
|
|
81
|
+
tokenManager,
|
|
82
|
+
errorHandler,
|
|
83
|
+
onUnauthorized
|
|
129
84
|
);
|
|
130
85
|
}
|
|
131
86
|
|
|
132
|
-
|
|
133
|
-
|
|
87
|
+
/**
|
|
88
|
+
* 通用请求方法
|
|
89
|
+
*/
|
|
90
|
+
public request<T = any>(config: RequestConfig): Promise<ApiResponse<T>> {
|
|
134
91
|
return this.instance.request(config);
|
|
135
92
|
}
|
|
136
93
|
|
|
94
|
+
/**
|
|
95
|
+
* GET 请求
|
|
96
|
+
*/
|
|
137
97
|
public get<T = any>(
|
|
138
98
|
url: string,
|
|
139
99
|
params?: any,
|
|
140
|
-
config?:
|
|
141
|
-
): Promise<
|
|
100
|
+
config?: RequestConfig
|
|
101
|
+
): Promise<ApiResponse<T>> {
|
|
142
102
|
return this.instance.get(url, {
|
|
143
103
|
...config,
|
|
144
|
-
params
|
|
104
|
+
params,
|
|
145
105
|
paramsSerializer,
|
|
146
106
|
});
|
|
147
107
|
}
|
|
148
108
|
|
|
109
|
+
/**
|
|
110
|
+
* POST 请求
|
|
111
|
+
*/
|
|
149
112
|
public post<T = any>(
|
|
150
113
|
url: string,
|
|
151
114
|
data?: any,
|
|
152
|
-
config?:
|
|
153
|
-
): Promise<
|
|
115
|
+
config?: RequestConfig
|
|
116
|
+
): Promise<ApiResponse<T>> {
|
|
154
117
|
return this.instance.post(url, data, config);
|
|
155
118
|
}
|
|
156
119
|
|
|
120
|
+
/**
|
|
121
|
+
* PUT 请求
|
|
122
|
+
*/
|
|
157
123
|
public put<T = any>(
|
|
158
124
|
url: string,
|
|
159
125
|
data?: any,
|
|
160
|
-
config?:
|
|
161
|
-
): Promise<
|
|
126
|
+
config?: RequestConfig
|
|
127
|
+
): Promise<ApiResponse<T>> {
|
|
162
128
|
return this.instance.put(url, data, config);
|
|
163
129
|
}
|
|
164
130
|
|
|
131
|
+
/**
|
|
132
|
+
* DELETE 请求
|
|
133
|
+
*/
|
|
165
134
|
public delete<T = any>(
|
|
166
135
|
url: string,
|
|
167
|
-
config?:
|
|
168
|
-
): Promise<
|
|
136
|
+
config?: RequestConfig
|
|
137
|
+
): Promise<ApiResponse<T>> {
|
|
169
138
|
return this.instance.delete(url, config);
|
|
170
139
|
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* PATCH 请求
|
|
143
|
+
*/
|
|
144
|
+
public patch<T = any>(
|
|
145
|
+
url: string,
|
|
146
|
+
data?: any,
|
|
147
|
+
config?: RequestConfig
|
|
148
|
+
): Promise<ApiResponse<T>> {
|
|
149
|
+
return this.instance.patch(url, data, config);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 获取 axios 实例(用于高级用法)
|
|
154
|
+
*/
|
|
155
|
+
public getAxiosInstance(): AxiosInstance {
|
|
156
|
+
return this.instance;
|
|
157
|
+
}
|
|
171
158
|
}
|
|
172
159
|
|
|
173
|
-
//
|
|
174
|
-
export
|
|
160
|
+
// 导出默认实例
|
|
161
|
+
export const request = new Request();
|
|
162
|
+
|
|
163
|
+
// 导出类型
|
|
164
|
+
export type {
|
|
165
|
+
RequestConfig,
|
|
166
|
+
ApiResponse,
|
|
167
|
+
MessageConfig,
|
|
168
|
+
TokenManager,
|
|
169
|
+
} from "./types";
|
|
170
|
+
|
|
171
|
+
// 默认导出
|
|
172
|
+
export default request;
|