@4399ywkf/cli 1.0.6 → 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.
Files changed (177) hide show
  1. package/dist/templates/HarmonyOS_Sans_Bold.woff2 +0 -0
  2. package/dist/templates/HarmonyOS_Sans_Medium.woff2 +0 -0
  3. package/dist/templates/HarmonyOS_Sans_Regular.woff2 +0 -0
  4. package/dist/templates/Locale.tsx +14 -18
  5. package/dist/templates/MainContentWrap.tsx +11 -15
  6. package/dist/templates/ThemeContext.tsx +27 -24
  7. package/dist/templates/actions.ts +14 -11
  8. package/dist/templates/app/config/env/.env.public.tpl +2 -19
  9. package/dist/templates/app/config/jwt/index.ts +4 -4
  10. package/dist/templates/app/config/request/error-handler.ts +67 -0
  11. package/dist/templates/app/config/request/index.ts +127 -129
  12. package/dist/templates/app/config/request/interceptors.ts +118 -0
  13. package/dist/templates/app/config/request/token-manager.ts +23 -0
  14. package/dist/templates/app/config/request/types.ts +63 -0
  15. package/dist/templates/app/config/rspack/rspack.config.mjs +62 -61
  16. package/dist/templates/app/config/rspack/rspack.prod.mjs +41 -62
  17. package/dist/templates/app/locales/zh-CN/common.json +3 -0
  18. package/dist/templates/app/package.json.tpl +1 -10
  19. package/dist/templates/app/public/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
  20. package/dist/templates/app/public/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
  21. package/dist/templates/app/public/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
  22. package/dist/templates/app/react-app-env.d.ts +13 -8
  23. package/dist/templates/app/src/bootstrap/index.ts +34 -0
  24. package/dist/templates/app/src/config/env.ts +84 -0
  25. package/dist/templates/app/src/index.tsx +17 -54
  26. package/dist/templates/app/src/layout/Locale.tsx +14 -18
  27. package/dist/templates/app/src/layout/MainContentWrap.tsx +11 -15
  28. package/dist/templates/app/src/layout/ThemeContext.tsx +27 -24
  29. package/dist/templates/app/src/locales/default/common.ts +3 -1
  30. package/dist/templates/app/src/micro/garfish.ts +53 -0
  31. package/dist/templates/app/src/pages/base/index.tsx +189 -25
  32. package/dist/templates/app/src/routes.tsx +21 -12
  33. package/dist/templates/app/src/types/global.d.ts +19 -0
  34. package/dist/templates/app/src/utils/index.ts +3 -1
  35. package/dist/templates/app/store/middleware/createDevtools.ts +7 -7
  36. package/dist/templates/base/index.tsx +189 -25
  37. package/dist/templates/bootstrap/index.ts +34 -0
  38. package/dist/templates/common.json +3 -0
  39. package/dist/templates/common.ts +3 -1
  40. package/dist/templates/config/env/.env.public.tpl +2 -19
  41. package/dist/templates/config/env.ts +84 -0
  42. package/dist/templates/config/jwt/index.ts +4 -4
  43. package/dist/templates/config/request/error-handler.ts +67 -0
  44. package/dist/templates/config/request/index.ts +127 -129
  45. package/dist/templates/config/request/interceptors.ts +118 -0
  46. package/dist/templates/config/request/token-manager.ts +23 -0
  47. package/dist/templates/config/request/types.ts +63 -0
  48. package/dist/templates/config/rspack/rspack.config.mjs +62 -61
  49. package/dist/templates/config/rspack/rspack.prod.mjs +41 -62
  50. package/dist/templates/createDevtools.ts +7 -7
  51. package/dist/templates/default/common.ts +3 -1
  52. package/dist/templates/env/.env.public.tpl +2 -19
  53. package/dist/templates/env.ts +83 -2
  54. package/dist/templates/error-handler.ts +67 -0
  55. package/dist/templates/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
  56. package/dist/templates/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
  57. package/dist/templates/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
  58. package/dist/templates/garfish.ts +53 -0
  59. package/dist/templates/global.d.ts +19 -0
  60. package/dist/templates/index.tsx +189 -25
  61. package/dist/templates/initialState.ts +28 -10
  62. package/dist/templates/interceptors.ts +118 -0
  63. package/dist/templates/jwt/index.ts +4 -4
  64. package/dist/templates/layout/Locale.tsx +14 -18
  65. package/dist/templates/layout/MainContentWrap.tsx +11 -15
  66. package/dist/templates/layout/ThemeContext.tsx +27 -24
  67. package/dist/templates/locales/default/common.ts +3 -1
  68. package/dist/templates/locales/zh-CN/common.json +3 -0
  69. package/dist/templates/micro/garfish.ts +53 -0
  70. package/dist/templates/middleware/createDevtools.ts +7 -7
  71. package/dist/templates/package.json.tpl +1 -10
  72. package/dist/templates/page.tsx +21 -19
  73. package/dist/templates/pages/base/index.tsx +189 -25
  74. package/dist/templates/public/fonts/HarmonyOS_Sans_Bold.woff2 +0 -0
  75. package/dist/templates/public/fonts/HarmonyOS_Sans_Medium.woff2 +0 -0
  76. package/dist/templates/public/fonts/HarmonyOS_Sans_Regular.woff2 +0 -0
  77. package/dist/templates/react-app-env.d.ts +13 -8
  78. package/dist/templates/request/error-handler.ts +67 -0
  79. package/dist/templates/request/index.ts +127 -129
  80. package/dist/templates/request/interceptors.ts +118 -0
  81. package/dist/templates/request/token-manager.ts +23 -0
  82. package/dist/templates/request/types.ts +63 -0
  83. package/dist/templates/routes.tsx +21 -12
  84. package/dist/templates/rspack/rspack.config.mjs +62 -61
  85. package/dist/templates/rspack/rspack.prod.mjs +41 -62
  86. package/dist/templates/rspack.config.mjs +62 -61
  87. package/dist/templates/rspack.prod.mjs +41 -62
  88. package/dist/templates/src/bootstrap/index.ts +34 -0
  89. package/dist/templates/src/config/env.ts +84 -0
  90. package/dist/templates/src/index.tsx +17 -54
  91. package/dist/templates/src/layout/Locale.tsx +14 -18
  92. package/dist/templates/src/layout/MainContentWrap.tsx +11 -15
  93. package/dist/templates/src/layout/ThemeContext.tsx +27 -24
  94. package/dist/templates/src/locales/default/common.ts +3 -1
  95. package/dist/templates/src/micro/garfish.ts +53 -0
  96. package/dist/templates/src/pages/base/index.tsx +189 -25
  97. package/dist/templates/src/routes.tsx +21 -12
  98. package/dist/templates/src/types/global.d.ts +19 -0
  99. package/dist/templates/src/utils/index.ts +3 -1
  100. package/dist/templates/store/middleware/createDevtools.ts +7 -7
  101. package/dist/templates/token-manager.ts +23 -0
  102. package/dist/templates/types/global.d.ts +19 -0
  103. package/dist/templates/utils/index.ts +3 -1
  104. package/dist/templates/zh-CN/common.json +3 -0
  105. package/package.json +1 -1
  106. package/dist/templates/app/config/sentry/sentry.config.ts +0 -188
  107. package/dist/templates/app/src/hooks/useRouteTitle.tsx +0 -36
  108. package/dist/templates/app/src/hooks/useSentry.ts +0 -92
  109. package/dist/templates/app/src/pages/base/layout.tsx +0 -6
  110. package/dist/templates/app/src/pages/base/page.tsx +0 -25
  111. package/dist/templates/app/src/utils/env.ts +0 -3
  112. package/dist/templates/app/src/utils/format.ts +0 -21
  113. package/dist/templates/app/src/utils/getMicroApp.ts +0 -39
  114. package/dist/templates/app/src/utils/sentry.ts +0 -187
  115. package/dist/templates/app/src/utils/sentryDecorators.ts +0 -34
  116. package/dist/templates/app/src/utils/updateVersion.ts +0 -186
  117. package/dist/templates/base/layout.tsx +0 -6
  118. package/dist/templates/base/page.tsx +0 -25
  119. package/dist/templates/config/public/404.png +0 -0
  120. package/dist/templates/config/public/favicon.ico +0 -0
  121. package/dist/templates/config/public/images/banner_market_modal.webp +0 -0
  122. package/dist/templates/config/public/images/chatmode_chat_dark.webp +0 -0
  123. package/dist/templates/config/public/images/chatmode_chat_light.webp +0 -0
  124. package/dist/templates/config/public/images/chatmode_docs_dark.webp +0 -0
  125. package/dist/templates/config/public/images/chatmode_docs_light.webp +0 -0
  126. package/dist/templates/config/public/images/empty_topic_dark.webp +0 -0
  127. package/dist/templates/config/public/images/empty_topic_light.webp +0 -0
  128. package/dist/templates/config/public/images/screenshot_background.webp +0 -0
  129. package/dist/templates/config/public/images/theme_auto.webp +0 -0
  130. package/dist/templates/config/public/images/theme_dark.webp +0 -0
  131. package/dist/templates/config/public/images/theme_light.webp +0 -0
  132. package/dist/templates/config/public/index.html +0 -29
  133. package/dist/templates/config/sentry/sentry.config.ts +0 -188
  134. package/dist/templates/format.ts +0 -21
  135. package/dist/templates/getMicroApp.ts +0 -39
  136. package/dist/templates/hooks/useRouteTitle.tsx +0 -36
  137. package/dist/templates/hooks/useSentry.ts +0 -92
  138. package/dist/templates/layout.tsx +0 -6
  139. package/dist/templates/pages/base/layout.tsx +0 -6
  140. package/dist/templates/pages/base/page.tsx +0 -25
  141. package/dist/templates/sentry/sentry.config.ts +0 -188
  142. package/dist/templates/sentry.config.ts +0 -188
  143. package/dist/templates/sentry.ts +0 -187
  144. package/dist/templates/sentryDecorators.ts +0 -34
  145. package/dist/templates/src/hooks/useRouteTitle.tsx +0 -36
  146. package/dist/templates/src/hooks/useSentry.ts +0 -92
  147. package/dist/templates/src/pages/base/layout.tsx +0 -6
  148. package/dist/templates/src/pages/base/page.tsx +0 -25
  149. package/dist/templates/src/utils/env.ts +0 -3
  150. package/dist/templates/src/utils/format.ts +0 -21
  151. package/dist/templates/src/utils/getMicroApp.ts +0 -39
  152. package/dist/templates/src/utils/sentry.ts +0 -187
  153. package/dist/templates/src/utils/sentryDecorators.ts +0 -34
  154. package/dist/templates/src/utils/updateVersion.ts +0 -186
  155. package/dist/templates/updateVersion.ts +0 -186
  156. package/dist/templates/useRouteTitle.tsx +0 -36
  157. package/dist/templates/useSentry.ts +0 -92
  158. package/dist/templates/utils/env.ts +0 -3
  159. package/dist/templates/utils/format.ts +0 -21
  160. package/dist/templates/utils/getMicroApp.ts +0 -39
  161. package/dist/templates/utils/sentry.ts +0 -187
  162. package/dist/templates/utils/sentryDecorators.ts +0 -34
  163. package/dist/templates/utils/updateVersion.ts +0 -186
  164. /package/dist/templates/app/{config/public → public}/404.png +0 -0
  165. /package/dist/templates/app/{config/public → public}/favicon.ico +0 -0
  166. /package/dist/templates/app/{config/public → public}/images/banner_market_modal.webp +0 -0
  167. /package/dist/templates/app/{config/public → public}/images/chatmode_chat_dark.webp +0 -0
  168. /package/dist/templates/app/{config/public → public}/images/chatmode_chat_light.webp +0 -0
  169. /package/dist/templates/app/{config/public → public}/images/chatmode_docs_dark.webp +0 -0
  170. /package/dist/templates/app/{config/public → public}/images/chatmode_docs_light.webp +0 -0
  171. /package/dist/templates/app/{config/public → public}/images/empty_topic_dark.webp +0 -0
  172. /package/dist/templates/app/{config/public → public}/images/empty_topic_light.webp +0 -0
  173. /package/dist/templates/app/{config/public → public}/images/screenshot_background.webp +0 -0
  174. /package/dist/templates/app/{config/public → public}/images/theme_auto.webp +0 -0
  175. /package/dist/templates/app/{config/public → public}/images/theme_dark.webp +0 -0
  176. /package/dist/templates/app/{config/public → public}/images/theme_light.webp +0 -0
  177. /package/dist/templates/app/{config/public → public}/index.html +0 -0
@@ -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();
@@ -0,0 +1,53 @@
1
+ import type { Root } from "react-dom";
2
+ import { renderClient } from "@config/router";
3
+ import { createRouter } from "@/routes";
4
+
5
+ interface GarfishProvider {
6
+ render: (props: { basename: string }) => void;
7
+ destroy: () => void;
8
+ }
9
+
10
+ interface RenderContext {
11
+ basename?: string;
12
+ rootElement: HTMLElement | null;
13
+ }
14
+
15
+ /**
16
+ * Garfish 微前端生命周期适配器
17
+ */
18
+ export function createGarfishProvider(appName: string): GarfishProvider {
19
+ let root: Root | null = null;
20
+
21
+ return {
22
+ render({ basename }: { basename: string }) {
23
+ const context: RenderContext = {
24
+ basename,
25
+ rootElement: document.getElementById(appName) ?? document.body,
26
+ };
27
+
28
+ root = renderClient(context);
29
+
30
+ // 向主应用通知路由信息
31
+ if (window.Garfish?.channel) {
32
+ window.Garfish.channel.emit("router", {
33
+ name: appName,
34
+ routes: createRouter(basename),
35
+ });
36
+ }
37
+ },
38
+
39
+ destroy() {
40
+ if (root) {
41
+ root.unmount();
42
+ root = null;
43
+ }
44
+ },
45
+ };
46
+ }
47
+
48
+ /**
49
+ * 判断是否在微前端环境中运行
50
+ */
51
+ export function isMicroApp(): boolean {
52
+ return typeof window !== "undefined" && Boolean(window.__GARFISH__);
53
+ }
@@ -0,0 +1,19 @@
1
+ import type { Env } from "@/config/env";
2
+
3
+ declare global {
4
+ interface Window {
5
+ __GARFISH__?: boolean;
6
+ Garfish?: {
7
+ channel: {
8
+ emit: (event: string, data: any) => void;
9
+ on: (event: string, handler: (data: any) => void) => void;
10
+ };
11
+ };
12
+ }
13
+
14
+ namespace NodeJS {
15
+ interface ProcessEnv extends Env {}
16
+ }
17
+ }
18
+
19
+ export {};
@@ -1,32 +1,196 @@
1
- import React from 'react';
2
- import { createStyles } from "antd-style"
3
-
4
-
5
- const useStyles = createStyles(({ token, isDarkMode }) => ({
6
- button: {
7
- backgroundColor: token.colorPrimary,
8
- width: '100px',
9
- color: isDarkMode ? token.colorText : "#fff",
10
- padding: `${token.paddingXS}px ${token.paddingSM}px`,
11
- borderRadius: token.borderRadius,
12
- cursor: 'pointer',
13
- transition: 'all 0.3s ease',
14
-
15
- '&:hover': {
16
- backgroundColor: token.colorPrimaryHover,
1
+ import { useUserStore } from "@store/user";
2
+ import { Button, Card, Space, Typography, Tag, Flex } from "antd";
3
+ import {
4
+ RocketOutlined,
5
+ ThunderboltOutlined,
6
+ BulbOutlined,
7
+ GithubOutlined,
8
+ BookOutlined,
9
+ SettingOutlined,
10
+ } from "@ant-design/icons";
11
+ import React from "react";
12
+ import { createStyles } from "antd-style";
13
+
14
+ const { Title, Paragraph, Text, Link } = Typography;
15
+
16
+ const useStyles = createStyles(({ css, token }) => ({
17
+ app: css`
18
+ width: 100%;
19
+ height: 100%;
20
+ overflow: auto;
21
+ `,
22
+ }));
23
+
24
+ export default function BasePage() {
25
+ const theme = useUserStore((state) => state.themeMode);
26
+ const setTheme = useUserStore((state) => state.setThemeMode);
27
+ const { styles, cx } = useStyles();
28
+
29
+ const features = [
30
+ {
31
+ icon: <ThunderboltOutlined className="text-4xl text-blue-500" />,
32
+ title: "Rspack 构建",
33
+ description: "基于 Rspack 的极速构建体验,开发效率翻倍",
17
34
  },
18
- '&:active': {
19
- backgroundColor: token.colorPrimaryActive,
35
+ {
36
+ icon: <BulbOutlined className="text-4xl text-yellow-500" />,
37
+ title: "React 19",
38
+ description: "使用最新的 React 19 特性,享受并发渲染",
20
39
  },
21
- },
22
- }));
40
+ {
41
+ icon: <SettingOutlined className="text-4xl text-green-500" />,
42
+ title: "TypeScript",
43
+ description: "完整的 TypeScript 支持,类型安全有保障",
44
+ },
45
+ ];
46
+
47
+ const quickLinks = [
48
+ { label: "📖 文档", description: "查看完整文档" },
49
+ { label: "🎨 组件库", description: "Ant Design 组件" },
50
+ { label: "🔧 配置", description: "项目配置说明" },
51
+ { label: "🚀 部署", description: "部署指南" },
52
+ ];
23
53
 
24
- export default function Base() {
25
- const { styles } = useStyles();
26
54
  return (
27
- <div className={styles.button}>
28
- Base
29
- {/* <Button type="primary">antd按钮</Button> */}
55
+ <div
56
+ className={cx(
57
+ styles.app,
58
+ "min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-gray-900 dark:to-gray-800 p-8"
59
+ )}
60
+ >
61
+ <div className="max-w-6xl mx-auto">
62
+ <Flex vertical gap={12}>
63
+ {/* 头部欢迎区域 */}
64
+ <div className="text-center mb-12 animate-fade-in">
65
+ <div className="inline-block mb-4">
66
+ <RocketOutlined className="text-6xl text-blue-500 animate-bounce" />
67
+ </div>
68
+ <Title level={1} className="!mb-4">
69
+ 🎉 恭喜!项目创建成功
70
+ </Title>
71
+ <Paragraph className="text-lg text-gray-600 dark:text-gray-300">
72
+ 你的项目已经准备就绪,现在可以开始开发了
73
+ </Paragraph>
74
+ <Space size="middle" className="mt-4">
75
+ <Tag color="blue">React 19</Tag>
76
+ <Tag color="green">TypeScript</Tag>
77
+ <Tag color="orange">Rspack</Tag>
78
+ <Tag color="purple">Ant Design</Tag>
79
+ <Tag color="cyan">Tailwind CSS</Tag>
80
+ </Space>
81
+ </div>
82
+
83
+ {/* 特性卡片 */}
84
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
85
+ {features.map((feature, index) => (
86
+ <Card
87
+ key={index}
88
+ hoverable
89
+ className="text-center transition-all duration-300 hover:shadow-xl dark:bg-gray-800"
90
+ >
91
+ <div className="mb-4">{feature.icon}</div>
92
+ <Title level={4}>{feature.title}</Title>
93
+ <Paragraph className="text-gray-600 dark:text-gray-400">
94
+ {feature.description}
95
+ </Paragraph>
96
+ </Card>
97
+ ))}
98
+ </div>
99
+
100
+ {/* 快速开始 */}
101
+ <Card
102
+ title={
103
+ <span className="text-xl">
104
+ <BookOutlined className="mr-2" />
105
+ 快速开始
106
+ </span>
107
+ }
108
+ className="mb-8 dark:bg-gray-800"
109
+ >
110
+ <Space direction="vertical" size="large" className="w-full">
111
+ <div>
112
+ <Text strong className="text-base">
113
+ 1. 安装依赖
114
+ </Text>
115
+ <div className="mt-2 p-4 bg-gray-100 dark:bg-gray-900 rounded-lg font-mono text-sm">
116
+ <code>pnpm install</code>
117
+ </div>
118
+ </div>
119
+ <div>
120
+ <Text strong className="text-base">
121
+ 2. 启动开发服务器
122
+ </Text>
123
+ <div className="mt-2 p-4 bg-gray-100 dark:bg-gray-900 rounded-lg font-mono text-sm">
124
+ <code>pnpm dev</code>
125
+ </div>
126
+ </div>
127
+ <div>
128
+ <Text strong className="text-base">
129
+ 3. 构建生产版本
130
+ </Text>
131
+ <div className="mt-2 p-4 bg-gray-100 dark:bg-gray-900 rounded-lg font-mono text-sm">
132
+ <code>pnpm build</code>
133
+ </div>
134
+ </div>
135
+ </Space>
136
+ </Card>
137
+
138
+ {/* 快捷链接 */}
139
+ <Card
140
+ title={
141
+ <span className="text-xl">
142
+ <GithubOutlined className="mr-2" />
143
+ 快捷链接
144
+ </span>
145
+ }
146
+ className="mb-8 dark:bg-gray-800"
147
+ >
148
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
149
+ {quickLinks.map((link, index) => (
150
+ <div
151
+ key={index}
152
+ className="p-4 bg-gray-50 dark:bg-gray-900 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer transition-colors"
153
+ >
154
+ <div className="text-2xl mb-2">{link.label}</div>
155
+ <Text className="text-sm text-gray-600 dark:text-gray-400">
156
+ {link.description}
157
+ </Text>
158
+ </div>
159
+ ))}
160
+ </div>
161
+ </Card>
162
+
163
+ {/* 底部操作区 */}
164
+ <Card className="text-center dark:bg-gray-800">
165
+ <Space size="large" wrap>
166
+ <Button
167
+ type="primary"
168
+ size="large"
169
+ icon={<RocketOutlined />}
170
+ onClick={() => window.open("https://ant.design", "_blank")}
171
+ >
172
+ 查看 Ant Design 文档
173
+ </Button>
174
+ <Button
175
+ size="large"
176
+ icon={<BookOutlined />}
177
+ onClick={() => window.open("https://react.dev", "_blank")}
178
+ >
179
+ React 文档
180
+ </Button>
181
+ <Button
182
+ size="large"
183
+ onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
184
+ >
185
+ 切换主题 ({theme === "dark" ? "🌙 暗色" : "☀️ 亮色"})
186
+ </Button>
187
+ </Space>
188
+ <Paragraph className="mt-6 text-gray-500 dark:text-gray-400">
189
+ 祝你开发愉快!如有问题,请查阅文档或联系技术支持 💪
190
+ </Paragraph>
191
+ </Card>
192
+ </Flex>
193
+ </div>
30
194
  </div>
31
195
  );
32
196
  }
@@ -1,14 +1,32 @@
1
- import type { User } from '@/types/user';
1
+ export type AnimationMode = "disabled" | "agile" | "elegant";
2
+ export type ResponseAnimationStyle = "smooth" | "fadeIn" | "none";
3
+ export type ThemeMode = "auto" | "dark" | "light";
4
+ import type {
5
+ HighlighterProps,
6
+ MermaidProps,
7
+ NeutralColors,
8
+ PrimaryColors,
9
+ } from "@/styles";
2
10
 
3
- export interface UserProfileState {
4
- user?: User;
11
+ export interface UserSettingsState {
12
+ animationMode?: AnimationMode;
13
+ neutralColor?: NeutralColors;
14
+ primaryColor?: PrimaryColors;
15
+ fontSize: number;
16
+ transitionMode?: ResponseAnimationStyle;
17
+ highlighterTheme?: HighlighterProps["theme"];
18
+ mermaidTheme?: MermaidProps["theme"];
19
+
20
+ themeMode?: ThemeMode;
5
21
  }
6
22
 
7
- export const initialState: UserProfileState = {
8
- user: {
9
- id: 0,
10
- name: '',
11
- cname: '',
12
- staffId: '',
13
- },
23
+ export const initialState: UserSettingsState = {
24
+ animationMode: "agile",
25
+ neutralColor: undefined,
26
+ primaryColor: undefined,
27
+ fontSize: 14,
28
+ transitionMode: "fadeIn",
29
+ highlighterTheme: "lobe-theme",
30
+ mermaidTheme: "lobe-theme",
31
+ themeMode: "auto",
14
32
  };
@@ -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
+ }
@@ -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
  }
@@ -1,17 +1,17 @@
1
- import { ConfigProvider } from 'antd';
2
- import type { Locale as AntdLocale } from 'antd/es/locale';
3
- import dayjs from 'dayjs';
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 'react';
9
+ } from "react";
10
10
 
11
- import { isRtlLang } from 'rtl-detect';
11
+ import { isRtlLang } from "rtl-detect";
12
12
 
13
- import { createI18nNext } from '@/locales/create';
14
- import { getAntdLocale } from '@/utils/locale';
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() === 'en-us' ? 'en' : 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('dayjs/locale/en.js');
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('languageChanged', handleLang);
66
+ i18n.instance.on("languageChanged", handleLang);
69
67
  return () => {
70
- i18n.instance.off('languageChanged', handleLang);
68
+ i18n.instance.off("languageChanged", handleLang);
71
69
  };
72
70
  }, [i18n, lang]);
73
71
 
74
72
  // detect document direction
75
- const documentDir = isRtlLang(lang) ? 'rtl' : 'ltr';
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 = 'Locale';
83
+ Locale.displayName = "Locale";
88
84
 
89
85
  export default Locale;
@@ -1,19 +1,15 @@
1
- import { ConfigProvider, theme } from 'antd';
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 '@tanstack/react-query';
6
- import { Outlet } from 'react-router';
7
- import '../index.css';
8
- import { DEFAULT_LANG } from '@/const/locale';
9
- import { useRouteTitle } from '@/hooks/useRouteTitle';
10
- import { getAntdLocale } from '@/utils/locale';
11
- import queryString from 'query-string';
12
- import Locale from './Locale';
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('Failed to load locale:', error);
35
+ console.error("Failed to load locale:", error);
40
36
  // 保持默认的中文 locale
41
37
  } finally {
42
38
  setIsLocaleLoaded(true);