@4399ywkf/cli 1.0.7 → 1.0.9

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.
Files changed (254) hide show
  1. package/dist/templates/AntdStaticMethods/index.tsx +20 -0
  2. package/dist/templates/AppTheme.tsx +136 -0
  3. package/dist/templates/DIRECTORY_STRUCTURE.md +141 -0
  4. package/dist/templates/GlobalProvider/AppTheme.tsx +136 -0
  5. package/dist/templates/GlobalProvider/Locale.tsx +84 -0
  6. package/dist/templates/GlobalProvider/Query.tsx +12 -0
  7. package/dist/templates/GlobalProvider/StyleRegistry.tsx +9 -0
  8. package/dist/templates/GlobalProvider/index.tsx +23 -0
  9. package/dist/templates/HarmonyOS_Sans_Bold.woff2 +0 -0
  10. package/dist/templates/HarmonyOS_Sans_Medium.woff2 +0 -0
  11. package/dist/templates/HarmonyOS_Sans_Regular.woff2 +0 -0
  12. package/dist/templates/Locale.tsx +49 -54
  13. package/dist/templates/MainContentWrap.tsx +11 -15
  14. package/dist/templates/Query.tsx +12 -0
  15. package/dist/templates/StyleRegistry.tsx +9 -0
  16. package/dist/templates/ThemeContext.tsx +27 -24
  17. package/dist/templates/analyzeUnusedKeys.ts +506 -0
  18. package/dist/templates/app/.i18nrc.js +57 -0
  19. package/dist/templates/app/config/env/.env.public.tpl +2 -19
  20. package/dist/templates/app/config/jwt/index.ts +4 -4
  21. package/dist/templates/app/config/request/error-handler.ts +67 -0
  22. package/dist/templates/app/config/request/index.ts +127 -129
  23. package/dist/templates/app/config/request/interceptors.ts +118 -0
  24. package/dist/templates/app/config/request/token-manager.ts +23 -0
  25. package/dist/templates/app/config/request/types.ts +63 -0
  26. package/dist/templates/app/config/rspack/rspack.config.mjs +62 -61
  27. package/dist/templates/app/config/rspack/rspack.prod.mjs +41 -62
  28. package/dist/templates/app/docs/DIRECTORY_STRUCTURE.md +141 -0
  29. package/dist/templates/app/docs/glossary.md +11 -0
  30. package/dist/templates/app/locales/zh-CN/common.json +3 -0
  31. package/dist/templates/app/package.json.tpl +8 -25
  32. package/dist/templates/app/public/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
  33. package/dist/templates/app/public/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
  34. package/dist/templates/app/public/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
  35. package/dist/templates/app/react-app-env.d.ts +13 -8
  36. package/dist/templates/app/scripts/i18nWorkflow/analyzeUnusedKeys.ts +506 -0
  37. package/dist/templates/app/scripts/i18nWorkflow/cleanUnusedKeys.ts +344 -0
  38. package/dist/templates/app/scripts/i18nWorkflow/const.ts +18 -0
  39. package/dist/templates/app/scripts/i18nWorkflow/flattenLocaleKeys.ts +139 -0
  40. package/dist/templates/app/scripts/i18nWorkflow/genDefaultLocale.ts +19 -0
  41. package/dist/templates/app/scripts/i18nWorkflow/genDiff.ts +49 -0
  42. package/dist/templates/app/scripts/i18nWorkflow/i18nConfig.ts +7 -0
  43. package/dist/templates/app/scripts/i18nWorkflow/index.ts +11 -0
  44. package/dist/templates/app/scripts/i18nWorkflow/protectedPatterns.ts +91 -0
  45. package/dist/templates/app/scripts/i18nWorkflow/utils.ts +76 -0
  46. package/dist/templates/app/src/bootstrap/index.ts +34 -0
  47. package/dist/templates/app/src/components/AntdStaticMethods/index.tsx +20 -0
  48. package/dist/templates/app/src/config/env.ts +84 -0
  49. package/dist/templates/app/src/index.tsx +13 -51
  50. package/dist/templates/app/src/layout/GlobalProvider/AppTheme.tsx +136 -0
  51. package/dist/templates/app/src/layout/GlobalProvider/Locale.tsx +84 -0
  52. package/dist/templates/app/src/layout/GlobalProvider/Query.tsx +12 -0
  53. package/dist/templates/app/src/layout/GlobalProvider/StyleRegistry.tsx +9 -0
  54. package/dist/templates/app/src/layout/GlobalProvider/index.tsx +23 -0
  55. package/dist/templates/app/src/layout/Locale.tsx +14 -18
  56. package/dist/templates/app/src/layout/MainContentWrap.tsx +11 -15
  57. package/dist/templates/app/src/layout/ThemeContext.tsx +27 -24
  58. package/dist/templates/app/src/locales/default/common.ts +3 -1
  59. package/dist/templates/app/src/locales/utils.ts +23 -0
  60. package/dist/templates/app/src/micro/garfish.ts +53 -0
  61. package/dist/templates/app/src/pages/base/index.tsx +280 -25
  62. package/dist/templates/app/src/routes.tsx +21 -12
  63. package/dist/templates/app/src/types/global.d.ts +19 -0
  64. package/dist/templates/app/src/utils/index.ts +3 -1
  65. package/dist/templates/app/store/middleware/createDevtools.ts +7 -7
  66. package/dist/templates/app/tsconfig.json +19 -3
  67. package/dist/templates/base/index.tsx +280 -25
  68. package/dist/templates/bootstrap/index.ts +34 -0
  69. package/dist/templates/cleanUnusedKeys.ts +344 -0
  70. package/dist/templates/common.json +3 -0
  71. package/dist/templates/common.ts +3 -1
  72. package/dist/templates/components/AntdStaticMethods/index.tsx +20 -0
  73. package/dist/templates/config/env/.env.public.tpl +2 -19
  74. package/dist/templates/config/env.ts +84 -0
  75. package/dist/templates/config/jwt/index.ts +4 -4
  76. package/dist/templates/config/request/error-handler.ts +67 -0
  77. package/dist/templates/config/request/index.ts +127 -129
  78. package/dist/templates/config/request/interceptors.ts +118 -0
  79. package/dist/templates/config/request/token-manager.ts +23 -0
  80. package/dist/templates/config/request/types.ts +63 -0
  81. package/dist/templates/config/rspack/rspack.config.mjs +62 -61
  82. package/dist/templates/config/rspack/rspack.prod.mjs +41 -62
  83. package/dist/templates/const.ts +18 -0
  84. package/dist/templates/createDevtools.ts +7 -7
  85. package/dist/templates/default/common.ts +3 -1
  86. package/dist/templates/docs/DIRECTORY_STRUCTURE.md +141 -0
  87. package/dist/templates/docs/glossary.md +11 -0
  88. package/dist/templates/env/.env.public.tpl +2 -19
  89. package/dist/templates/env.ts +83 -2
  90. package/dist/templates/error-handler.ts +67 -0
  91. package/dist/templates/flattenLocaleKeys.ts +139 -0
  92. package/dist/templates/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
  93. package/dist/templates/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
  94. package/dist/templates/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
  95. package/dist/templates/garfish.ts +53 -0
  96. package/dist/templates/genDefaultLocale.ts +19 -0
  97. package/dist/templates/genDiff.ts +49 -0
  98. package/dist/templates/global.d.ts +19 -0
  99. package/dist/templates/glossary.md +11 -0
  100. package/dist/templates/i18nConfig.ts +7 -0
  101. package/dist/templates/i18nWorkflow/analyzeUnusedKeys.ts +506 -0
  102. package/dist/templates/i18nWorkflow/cleanUnusedKeys.ts +344 -0
  103. package/dist/templates/i18nWorkflow/const.ts +18 -0
  104. package/dist/templates/i18nWorkflow/flattenLocaleKeys.ts +139 -0
  105. package/dist/templates/i18nWorkflow/genDefaultLocale.ts +19 -0
  106. package/dist/templates/i18nWorkflow/genDiff.ts +49 -0
  107. package/dist/templates/i18nWorkflow/i18nConfig.ts +7 -0
  108. package/dist/templates/i18nWorkflow/index.ts +11 -0
  109. package/dist/templates/i18nWorkflow/protectedPatterns.ts +91 -0
  110. package/dist/templates/i18nWorkflow/utils.ts +76 -0
  111. package/dist/templates/index.tsx +280 -25
  112. package/dist/templates/interceptors.ts +118 -0
  113. package/dist/templates/jwt/index.ts +4 -4
  114. package/dist/templates/layout/GlobalProvider/AppTheme.tsx +136 -0
  115. package/dist/templates/layout/GlobalProvider/Locale.tsx +84 -0
  116. package/dist/templates/layout/GlobalProvider/Query.tsx +12 -0
  117. package/dist/templates/layout/GlobalProvider/StyleRegistry.tsx +9 -0
  118. package/dist/templates/layout/GlobalProvider/index.tsx +23 -0
  119. package/dist/templates/layout/Locale.tsx +14 -18
  120. package/dist/templates/layout/MainContentWrap.tsx +11 -15
  121. package/dist/templates/layout/ThemeContext.tsx +27 -24
  122. package/dist/templates/locales/default/common.ts +3 -1
  123. package/dist/templates/locales/utils.ts +23 -0
  124. package/dist/templates/locales/zh-CN/common.json +3 -0
  125. package/dist/templates/micro/garfish.ts +53 -0
  126. package/dist/templates/middleware/createDevtools.ts +7 -7
  127. package/dist/templates/package.json.tpl +8 -25
  128. package/dist/templates/page.tsx +21 -19
  129. package/dist/templates/pages/base/index.tsx +280 -25
  130. package/dist/templates/protectedPatterns.ts +91 -0
  131. package/dist/templates/public/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
  132. package/dist/templates/public/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
  133. package/dist/templates/public/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
  134. package/dist/templates/react-app-env.d.ts +13 -8
  135. package/dist/templates/request/error-handler.ts +67 -0
  136. package/dist/templates/request/index.ts +127 -129
  137. package/dist/templates/request/interceptors.ts +118 -0
  138. package/dist/templates/request/token-manager.ts +23 -0
  139. package/dist/templates/request/types.ts +63 -0
  140. package/dist/templates/routes.tsx +21 -12
  141. package/dist/templates/rspack/rspack.config.mjs +62 -61
  142. package/dist/templates/rspack/rspack.prod.mjs +41 -62
  143. package/dist/templates/rspack.config.mjs +62 -61
  144. package/dist/templates/rspack.prod.mjs +41 -62
  145. package/dist/templates/scripts/i18nWorkflow/analyzeUnusedKeys.ts +506 -0
  146. package/dist/templates/scripts/i18nWorkflow/cleanUnusedKeys.ts +344 -0
  147. package/dist/templates/scripts/i18nWorkflow/const.ts +18 -0
  148. package/dist/templates/scripts/i18nWorkflow/flattenLocaleKeys.ts +139 -0
  149. package/dist/templates/scripts/i18nWorkflow/genDefaultLocale.ts +19 -0
  150. package/dist/templates/scripts/i18nWorkflow/genDiff.ts +49 -0
  151. package/dist/templates/scripts/i18nWorkflow/i18nConfig.ts +7 -0
  152. package/dist/templates/scripts/i18nWorkflow/index.ts +11 -0
  153. package/dist/templates/scripts/i18nWorkflow/protectedPatterns.ts +91 -0
  154. package/dist/templates/scripts/i18nWorkflow/utils.ts +76 -0
  155. package/dist/templates/src/bootstrap/index.ts +34 -0
  156. package/dist/templates/src/components/AntdStaticMethods/index.tsx +20 -0
  157. package/dist/templates/src/config/env.ts +84 -0
  158. package/dist/templates/src/index.tsx +13 -51
  159. package/dist/templates/src/layout/GlobalProvider/AppTheme.tsx +136 -0
  160. package/dist/templates/src/layout/GlobalProvider/Locale.tsx +84 -0
  161. package/dist/templates/src/layout/GlobalProvider/Query.tsx +12 -0
  162. package/dist/templates/src/layout/GlobalProvider/StyleRegistry.tsx +9 -0
  163. package/dist/templates/src/layout/GlobalProvider/index.tsx +23 -0
  164. package/dist/templates/src/layout/Locale.tsx +14 -18
  165. package/dist/templates/src/layout/MainContentWrap.tsx +11 -15
  166. package/dist/templates/src/layout/ThemeContext.tsx +27 -24
  167. package/dist/templates/src/locales/default/common.ts +3 -1
  168. package/dist/templates/src/locales/utils.ts +23 -0
  169. package/dist/templates/src/micro/garfish.ts +53 -0
  170. package/dist/templates/src/pages/base/index.tsx +280 -25
  171. package/dist/templates/src/routes.tsx +21 -12
  172. package/dist/templates/src/types/global.d.ts +19 -0
  173. package/dist/templates/src/utils/index.ts +3 -1
  174. package/dist/templates/store/middleware/createDevtools.ts +7 -7
  175. package/dist/templates/token-manager.ts +23 -0
  176. package/dist/templates/tsconfig.json +19 -3
  177. package/dist/templates/type.ts +23 -24
  178. package/dist/templates/types/global.d.ts +19 -0
  179. package/dist/templates/utils/index.ts +3 -1
  180. package/dist/templates/utils.ts +23 -0
  181. package/dist/templates/zh-CN/common.json +3 -0
  182. package/package.json +19 -21
  183. package/dist/templates/app/config/sentry/sentry.config.ts +0 -188
  184. package/dist/templates/app/src/hooks/useRouteTitle.tsx +0 -36
  185. package/dist/templates/app/src/hooks/useSentry.ts +0 -92
  186. package/dist/templates/app/src/pages/base/layout.tsx +0 -6
  187. package/dist/templates/app/src/pages/base/page.tsx +0 -25
  188. package/dist/templates/app/src/utils/env.ts +0 -3
  189. package/dist/templates/app/src/utils/format.ts +0 -21
  190. package/dist/templates/app/src/utils/getMicroApp.ts +0 -39
  191. package/dist/templates/app/src/utils/sentry.ts +0 -187
  192. package/dist/templates/app/src/utils/sentryDecorators.ts +0 -34
  193. package/dist/templates/app/src/utils/updateVersion.ts +0 -186
  194. package/dist/templates/base/layout.tsx +0 -6
  195. package/dist/templates/base/page.tsx +0 -25
  196. package/dist/templates/config/public/404.png +0 -0
  197. package/dist/templates/config/public/favicon.ico +0 -0
  198. package/dist/templates/config/public/images/banner_market_modal.webp +0 -0
  199. package/dist/templates/config/public/images/chatmode_chat_dark.webp +0 -0
  200. package/dist/templates/config/public/images/chatmode_chat_light.webp +0 -0
  201. package/dist/templates/config/public/images/chatmode_docs_dark.webp +0 -0
  202. package/dist/templates/config/public/images/chatmode_docs_light.webp +0 -0
  203. package/dist/templates/config/public/images/empty_topic_dark.webp +0 -0
  204. package/dist/templates/config/public/images/empty_topic_light.webp +0 -0
  205. package/dist/templates/config/public/images/screenshot_background.webp +0 -0
  206. package/dist/templates/config/public/images/theme_auto.webp +0 -0
  207. package/dist/templates/config/public/images/theme_dark.webp +0 -0
  208. package/dist/templates/config/public/images/theme_light.webp +0 -0
  209. package/dist/templates/config/public/index.html +0 -29
  210. package/dist/templates/config/sentry/sentry.config.ts +0 -188
  211. package/dist/templates/format.ts +0 -21
  212. package/dist/templates/getMicroApp.ts +0 -39
  213. package/dist/templates/hooks/useRouteTitle.tsx +0 -36
  214. package/dist/templates/hooks/useSentry.ts +0 -92
  215. package/dist/templates/layout.tsx +0 -6
  216. package/dist/templates/pages/base/layout.tsx +0 -6
  217. package/dist/templates/pages/base/page.tsx +0 -25
  218. package/dist/templates/sentry/sentry.config.ts +0 -188
  219. package/dist/templates/sentry.config.ts +0 -188
  220. package/dist/templates/sentry.ts +0 -187
  221. package/dist/templates/sentryDecorators.ts +0 -34
  222. package/dist/templates/src/hooks/useRouteTitle.tsx +0 -36
  223. package/dist/templates/src/hooks/useSentry.ts +0 -92
  224. package/dist/templates/src/pages/base/layout.tsx +0 -6
  225. package/dist/templates/src/pages/base/page.tsx +0 -25
  226. package/dist/templates/src/utils/env.ts +0 -3
  227. package/dist/templates/src/utils/format.ts +0 -21
  228. package/dist/templates/src/utils/getMicroApp.ts +0 -39
  229. package/dist/templates/src/utils/sentry.ts +0 -187
  230. package/dist/templates/src/utils/sentryDecorators.ts +0 -34
  231. package/dist/templates/src/utils/updateVersion.ts +0 -186
  232. package/dist/templates/updateVersion.ts +0 -186
  233. package/dist/templates/useRouteTitle.tsx +0 -36
  234. package/dist/templates/useSentry.ts +0 -92
  235. package/dist/templates/utils/env.ts +0 -3
  236. package/dist/templates/utils/format.ts +0 -21
  237. package/dist/templates/utils/getMicroApp.ts +0 -39
  238. package/dist/templates/utils/sentry.ts +0 -187
  239. package/dist/templates/utils/sentryDecorators.ts +0 -34
  240. package/dist/templates/utils/updateVersion.ts +0 -186
  241. /package/dist/templates/app/{config/public → public}/404.png +0 -0
  242. /package/dist/templates/app/{config/public → public}/favicon.ico +0 -0
  243. /package/dist/templates/app/{config/public → public}/images/banner_market_modal.webp +0 -0
  244. /package/dist/templates/app/{config/public → public}/images/chatmode_chat_dark.webp +0 -0
  245. /package/dist/templates/app/{config/public → public}/images/chatmode_chat_light.webp +0 -0
  246. /package/dist/templates/app/{config/public → public}/images/chatmode_docs_dark.webp +0 -0
  247. /package/dist/templates/app/{config/public → public}/images/chatmode_docs_light.webp +0 -0
  248. /package/dist/templates/app/{config/public → public}/images/empty_topic_dark.webp +0 -0
  249. /package/dist/templates/app/{config/public → public}/images/empty_topic_light.webp +0 -0
  250. /package/dist/templates/app/{config/public → public}/images/screenshot_background.webp +0 -0
  251. /package/dist/templates/app/{config/public → public}/images/theme_auto.webp +0 -0
  252. /package/dist/templates/app/{config/public → public}/images/theme_dark.webp +0 -0
  253. /package/dist/templates/app/{config/public → public}/images/theme_light.webp +0 -0
  254. /package/dist/templates/app/{config/public → public}/index.html +0 -0
@@ -0,0 +1,20 @@
1
+ // Entry component
2
+ import { App } from 'antd';
3
+ import type { MessageInstance } from 'antd/es/message/interface';
4
+ import type { ModalStaticFunctions } from 'antd/es/modal/confirm';
5
+ import type { NotificationInstance } from 'antd/es/notification/interface';
6
+ import { memo } from 'react';
7
+
8
+ let message: MessageInstance;
9
+ let notification: NotificationInstance;
10
+ let modal: Omit<ModalStaticFunctions, 'warn'>;
11
+
12
+ export default memo(() => {
13
+ const staticFunction = App.useApp();
14
+ message = staticFunction.message;
15
+ modal = staticFunction.modal;
16
+ notification = staticFunction.notification;
17
+ return null;
18
+ });
19
+
20
+ export { message, modal, notification };
@@ -1,5 +1,5 @@
1
1
  API_PREFIX="/api"
2
- API_TIMEOUT=60 * 1000
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/"
@@ -0,0 +1,84 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * 环境变量 Schema 定义
5
+ */
6
+ const envSchema = z.object({
7
+ // Node 环境
8
+ NODE_ENV: z
9
+ .enum(["development", "test", "testDevelopment", "production"])
10
+ .default("development"),
11
+
12
+ // 应用配置
13
+ APP_NAME: z.string().min(1, "应用名称不能为空").default("app"),
14
+ APP_CNAME: z.string().default("应用"),
15
+ BASENAME: z.string().optional(),
16
+
17
+ // API 配置
18
+ API_PREFIX: z.string().default("/api"),
19
+ API_TIMEOUT: z
20
+ .string()
21
+ .transform(Number)
22
+ .pipe(z.number().positive())
23
+ .default(30000),
24
+
25
+ // Cookie 配置
26
+ COOKIE_NAME: z.string().default("access_token"),
27
+
28
+ // 其他配置
29
+ HELP_CENTER_URL: z.string().url().optional(),
30
+ OUTPUT_PATH: z.string().default("dist"),
31
+ PUBLIC_PATH: z.string().default("/"),
32
+ });
33
+
34
+ /**
35
+ * 安全解析环境变量(开发模式下使用默认值)
36
+ */
37
+ function safeParseEnv() {
38
+ const result = envSchema.safeParse(process.env);
39
+
40
+ if (!result.success) {
41
+ if (process.env.NODE_ENV === "production") {
42
+ // 生产环境严格校验
43
+ console.error("❌ 环境变量验证失败:");
44
+ result.error.issues.forEach((err) => {
45
+ console.error(` - ${err.path.join(".")}: ${err.message}`);
46
+ });
47
+ throw new Error("环境变量配置错误");
48
+ } else {
49
+ // 开发环境警告但不中断
50
+ console.warn("⚠️ 环境变量验证警告:");
51
+ result.error.issues.forEach((err) => {
52
+ console.warn(` - ${err.path.join(".")}: ${err.message}`);
53
+ });
54
+ }
55
+ }
56
+
57
+ return result.success ? result.data : envSchema.parse({});
58
+ }
59
+
60
+ /**
61
+ * 导出类型安全的环境变量
62
+ */
63
+ export const env = safeParseEnv();
64
+
65
+ /**
66
+ * 环境变量类型
67
+ */
68
+ export type Env = z.infer<typeof envSchema>;
69
+
70
+ /**
71
+ * 工具函数:判断是否为开发环境
72
+ */
73
+ export const isDev = env.NODE_ENV === "development";
74
+
75
+ /**
76
+ * 工具函数:判断是否为生产环境
77
+ */
78
+ export const isProd = env.NODE_ENV === "production";
79
+
80
+ /**
81
+ * 工具函数:判断是否为测试环境
82
+ */
83
+ export const isTest =
84
+ env.NODE_ENV === "test" || env.NODE_ENV === "testDevelopment";
@@ -20,12 +20,12 @@ export default class jwt {
20
20
  }
21
21
 
22
22
  // 获取访问令牌
23
- static getAccessToken(accessTokenKey: string) {
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: string) {
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 jwt from "@config/jwt";
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 Result<T> = {
10
- code: number;
11
- message: string;
12
- data: T;
13
- suppressErrorNotification?: boolean;
14
- };
15
-
16
- const baseURL = process.env.API_PREFIX;
17
- const timeout = process.env.API_TIMEOUT;
18
- const accessTokenKey = process.env.COOKIE_NAME;
19
-
20
- let flag = false; // 设置开关,保证一次只能请求一次刷新token,防止客户端多次操作,多次请求
21
- let subSequest: any[] = [];
22
-
23
- // 把过期请求添加在数组中
24
- function addRequest(request: () => any) {
25
- subSequest.push(request);
26
- }
27
-
28
- // 重新调用过期请求列表
29
- function retryRequest() {
30
- subSequest.forEach((request) => request());
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[p] = value;
92
- } else if (value === null || value === undefined) {
93
- result[p] = value;
28
+ result[key] = value;
94
29
  } else if (typeof value === "object") {
95
- result[p] = JSON.stringify(value);
30
+ result[key] = JSON.stringify(value);
96
31
  } else {
97
- result[p] = value;
32
+ result[key] = value;
98
33
  }
99
34
  });
35
+
100
36
  return qs.stringify(result, { arrayFormat: "repeat", skipNulls: true });
101
37
  }
102
38
 
103
- // 导出Request类,可以用来自定义传递配置来创建实例
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
- // 基础配置,url和超时时间
108
- private baseConfig: AxiosRequestConfig = {
109
- baseURL: baseURL,
110
- timeout: Number(timeout),
111
- withCredentials: true,
112
- };
113
-
114
- constructor(config: AxiosRequestConfig) {
115
- // 使用axios.create创建axios实例
116
- this.instance = axios.create(Object.assign(this.baseConfig, config));
117
-
118
- this.instance.interceptors.request.use(
119
- (config: any) => {
120
- // 一般会请求拦截里面加token,用于后端的验证
121
- config.headers = config.headers || {};
122
- config.headers.Authorization =
123
- jwt.getAccessToken(accessTokenKey as string) || "";
124
- return config;
125
- },
126
- (err: any) => {
127
- return Promise.reject(err);
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
- public request(config: AxiosRequestConfig): Promise<AxiosResponse> {
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?: AxiosRequestConfig & { suppressErrorNotification?: boolean }
141
- ): Promise<Result<T>> {
100
+ config?: RequestConfig
101
+ ): Promise<ApiResponse<T>> {
142
102
  return this.instance.get(url, {
143
103
  ...config,
144
- params: 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?: AxiosRequestConfig & { suppressErrorNotification?: boolean }
153
- ): Promise<Result<T>> {
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?: AxiosRequestConfig & { suppressErrorNotification?: boolean }
161
- ): Promise<Result<T>> {
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?: AxiosRequestConfig & { suppressErrorNotification?: boolean }
168
- ): Promise<Result<T>> {
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
- // 默认导出Request实例
174
- export default new Request({});
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;
@@ -0,0 +1,118 @@
1
+ import type {
2
+ AxiosInstance,
3
+ InternalAxiosRequestConfig,
4
+ AxiosResponse,
5
+ } from "axios";
6
+ import { message as antdMessage } from "antd";
7
+ import type { TokenManager, RequestConfig, ApiResponse } from "./types";
8
+ import type { ErrorHandler } from "./error-handler";
9
+
10
+ /**
11
+ * 设置请求拦截器
12
+ */
13
+ export function setupRequestInterceptor(
14
+ instance: AxiosInstance,
15
+ tokenManager: TokenManager
16
+ ): void {
17
+ instance.interceptors.request.use(
18
+ (config: InternalAxiosRequestConfig) => {
19
+ const requestConfig = config as RequestConfig;
20
+
21
+ // 添加 Token(如果需要认证,默认为 true)
22
+ if (requestConfig.requireAuth !== false) {
23
+ const token = tokenManager.getToken();
24
+ if (token && config.headers) {
25
+ config.headers.Authorization = token;
26
+ }
27
+ }
28
+
29
+ // 添加自定义 Headers
30
+ if (requestConfig.customHeaders && config.headers) {
31
+ Object.entries(requestConfig.customHeaders).forEach(([key, value]) => {
32
+ config.headers[key] = value;
33
+ });
34
+ }
35
+
36
+ return config;
37
+ },
38
+ (error) => {
39
+ return Promise.reject(error);
40
+ }
41
+ );
42
+ }
43
+
44
+ /**
45
+ * 设置响应拦截器
46
+ */
47
+ export function setupResponseInterceptor(
48
+ instance: AxiosInstance,
49
+ tokenManager: TokenManager,
50
+ errorHandler: ErrorHandler,
51
+ onUnauthorized?: () => void
52
+ ): void {
53
+ instance.interceptors.response.use(
54
+ (response: AxiosResponse<ApiResponse>) => {
55
+ const config = response.config as RequestConfig;
56
+ const messageConfig = config.message;
57
+
58
+ const { code, message: msg, data } = response.data;
59
+
60
+ // 业务成功(根据实际后端约定调整)
61
+ if (code === 0 || code === 200) {
62
+ // 显示成功消息
63
+ if (messageConfig?.showSuccess) {
64
+ const successMsg = messageConfig.successMessage || msg || "操作成功";
65
+ antdMessage.success(successMsg);
66
+ }
67
+
68
+ // 直接返回 data,简化调用
69
+ return response.data;
70
+ }
71
+
72
+ // 业务失败
73
+ const errorMsg = messageConfig?.errorMessage || msg || "操作失败";
74
+
75
+ if (messageConfig?.showError !== false) {
76
+ antdMessage.error(errorMsg);
77
+ }
78
+
79
+ return Promise.reject(new Error(errorMsg));
80
+ },
81
+ async (error) => {
82
+ const config = error.config as RequestConfig;
83
+
84
+ // 401 未授权
85
+ if (error.response?.status === 401) {
86
+ tokenManager.clearToken();
87
+
88
+ // 执行自定义的未授权回调
89
+ if (onUnauthorized) {
90
+ onUnauthorized();
91
+ } else {
92
+ // 默认跳转到登录页
93
+ redirectToLogin();
94
+ }
95
+
96
+ return Promise.reject(error);
97
+ }
98
+
99
+ // 其他错误统一处理
100
+ errorHandler.handle(error, config);
101
+
102
+ return Promise.reject(error);
103
+ }
104
+ );
105
+ }
106
+
107
+ /**
108
+ * 重定向到登录页
109
+ */
110
+ function redirectToLogin(): void {
111
+ if (typeof window === "undefined") return;
112
+
113
+ const currentPath = window.location.pathname;
114
+ if (currentPath === "/login") return;
115
+
116
+ const redirectUrl = encodeURIComponent(window.location.href);
117
+ window.location.href = `${window.location.origin}/login?redirect=${redirectUrl}`;
118
+ }
@@ -0,0 +1,23 @@
1
+ import jwt from "@config/jwt";
2
+ import type { TokenManager as TokenManagerType } from "./types";
3
+ /**
4
+ * Token 刷新管理器
5
+ * 使用 Promise 避免并发刷新问题
6
+ */
7
+ export class TokenManager implements TokenManagerType {
8
+ getToken(token?: string): string | undefined {
9
+ return jwt.getAccessToken(token);
10
+ }
11
+ setToken(token: {
12
+ token_type: any;
13
+ access_token: any;
14
+ expires_at: number;
15
+ }): void {
16
+ jwt.setAccessToken(token);
17
+ }
18
+ clearToken(token?: string): void {
19
+ jwt.clearAccessToken(token);
20
+ }
21
+ }
22
+
23
+ export const tokenManager = new TokenManager();