@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.
- 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/actions.ts +14 -11
- 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 -54
- 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/initialState.ts +28 -10
- 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 -54
- 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
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import * as Sentry from '@sentry/react';
|
|
2
|
-
|
|
3
|
-
// Sentry 配置接口
|
|
4
|
-
export interface SentryConfig {
|
|
5
|
-
dsn: string;
|
|
6
|
-
environment: string;
|
|
7
|
-
release?: string;
|
|
8
|
-
sampleRate: number;
|
|
9
|
-
tracesSampleRate: number;
|
|
10
|
-
enabled: boolean;
|
|
11
|
-
sessionSampleRate: number;
|
|
12
|
-
beforeSend?: (event: Sentry.ErrorEvent, hint: Sentry.EventHint) => Sentry.ErrorEvent | null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// 开发环境配置
|
|
16
|
-
const developmentConfig: Partial<SentryConfig> = {
|
|
17
|
-
enabled: true, // 开发环境可以选择关闭
|
|
18
|
-
sampleRate: 1.0,
|
|
19
|
-
tracesSampleRate: 1.0,
|
|
20
|
-
sessionSampleRate: 1.0, // 开发环境记录所有会话
|
|
21
|
-
beforeSend: (event, hint) => {
|
|
22
|
-
console.group('🐛 Sentry Event (Development)');
|
|
23
|
-
console.log('Event:', event);
|
|
24
|
-
console.log('Hint:', hint);
|
|
25
|
-
console.log('Event:', event);
|
|
26
|
-
console.groupEnd();
|
|
27
|
-
|
|
28
|
-
return event;
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// 生产环境配置
|
|
33
|
-
const productionConfig: Partial<SentryConfig> = {
|
|
34
|
-
enabled: true,
|
|
35
|
-
sampleRate: 1.0, // 临时设置为100%以排查问题,后续可调整
|
|
36
|
-
tracesSampleRate: 0.1, // 提高到10%性能采样
|
|
37
|
-
sessionSampleRate: 1.0, // 记录所有会话以获得准确的健康度数据
|
|
38
|
-
beforeSend: (event, hint) => {
|
|
39
|
-
// 生产环境也打印日志以便调试
|
|
40
|
-
console.log('🐛 Sentry Event (Production):', event);
|
|
41
|
-
|
|
42
|
-
// 过滤敏感信息
|
|
43
|
-
if (event.exception) {
|
|
44
|
-
const error = event.exception.values?.[0];
|
|
45
|
-
if (error?.value?.includes('密码') || error?.value?.includes('token')) {
|
|
46
|
-
return null; // 不发送包含敏感信息的错误
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return event;
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// 获取环境配置
|
|
54
|
-
const getEnvironmentConfig = (): Partial<SentryConfig> => {
|
|
55
|
-
const env = process.env.NODE_ENV || 'development';
|
|
56
|
-
console.log(env, 'env');
|
|
57
|
-
switch (env) {
|
|
58
|
-
case 'development':
|
|
59
|
-
return developmentConfig;
|
|
60
|
-
case 'production':
|
|
61
|
-
return productionConfig;
|
|
62
|
-
default:
|
|
63
|
-
return developmentConfig;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// 基础配置
|
|
68
|
-
const baseConfig: SentryConfig = {
|
|
69
|
-
dsn: process.env.REACT_APP_SENTRY_DSN || '',
|
|
70
|
-
environment: process.env.SENTRY_ENV || 'development',
|
|
71
|
-
enabled: true,
|
|
72
|
-
sampleRate: 1.0,
|
|
73
|
-
tracesSampleRate: 1.0,
|
|
74
|
-
sessionSampleRate: 1.0, // 默认记录所有会话
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// 合并配置
|
|
78
|
-
export const sentryConfig: SentryConfig = {
|
|
79
|
-
...baseConfig,
|
|
80
|
-
...getEnvironmentConfig(),
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// 安全的会话重放集成初始化
|
|
84
|
-
const getSafeReplayIntegration = () => {
|
|
85
|
-
try {
|
|
86
|
-
return Sentry.replayIntegration({
|
|
87
|
-
maskAllText: false,
|
|
88
|
-
maskAllInputs: false,
|
|
89
|
-
blockAllMedia: true,
|
|
90
|
-
networkDetailAllowUrls: [window.location.origin],
|
|
91
|
-
}) as any; // 添加类型断言
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.warn('会话重放初始化失败:', error);
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// 初始化 Sentry
|
|
99
|
-
export const initSentry = () => {
|
|
100
|
-
// 修复 fetch 上下文问题
|
|
101
|
-
if (typeof window !== 'undefined' && window.fetch) {
|
|
102
|
-
window.fetch = window.fetch.bind(window);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (!sentryConfig.enabled || !sentryConfig.dsn) {
|
|
106
|
-
console.warn('❌ Sentry not enabled or DSN not provided');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const integrations = [Sentry.browserTracingIntegration()];
|
|
111
|
-
|
|
112
|
-
// 安全地添加会话重放集成
|
|
113
|
-
const replayIntegration = getSafeReplayIntegration();
|
|
114
|
-
if (replayIntegration && !window.__GARFISH__) {
|
|
115
|
-
// 目前微服务无法使用会话重放
|
|
116
|
-
integrations.push(replayIntegration);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
Sentry.init({
|
|
120
|
-
dsn: sentryConfig.dsn,
|
|
121
|
-
environment: sentryConfig.environment,
|
|
122
|
-
sampleRate: sentryConfig.sampleRate,
|
|
123
|
-
tracesSampleRate: sentryConfig.tracesSampleRate,
|
|
124
|
-
beforeSend: sentryConfig.beforeSend,
|
|
125
|
-
|
|
126
|
-
// 使用自定义传输层,确保fetch上下文正确
|
|
127
|
-
transport: Sentry.makeBrowserOfflineTransport((options) => Sentry.makeFetchTransport(options, window.fetch.bind(window))),
|
|
128
|
-
|
|
129
|
-
// 设置追踪的 URL 匹配规则
|
|
130
|
-
tracePropagationTargets: ['localhost', /^https:\/\/yourapi\.domain\.com\/api/],
|
|
131
|
-
|
|
132
|
-
// 使用安全的集成配置
|
|
133
|
-
integrations,
|
|
134
|
-
|
|
135
|
-
// 错误过滤
|
|
136
|
-
ignoreErrors: [
|
|
137
|
-
// 忽略常见的无害错误
|
|
138
|
-
'Non-Error promise rejection captured',
|
|
139
|
-
'ResizeObserver loop limit exceeded',
|
|
140
|
-
'Script error.',
|
|
141
|
-
'Network Error',
|
|
142
|
-
'Loading chunk',
|
|
143
|
-
'Loading CSS chunk',
|
|
144
|
-
],
|
|
145
|
-
|
|
146
|
-
// URL 过滤
|
|
147
|
-
denyUrls: [
|
|
148
|
-
// 忽略浏览器扩展
|
|
149
|
-
/extensions\//i,
|
|
150
|
-
/^chrome:\/\//i,
|
|
151
|
-
/^moz-extension:\/\//i,
|
|
152
|
-
],
|
|
153
|
-
|
|
154
|
-
// 只在会话重放可用时设置这些选项
|
|
155
|
-
...(replayIntegration && {
|
|
156
|
-
replaysSessionSampleRate: 0.1,
|
|
157
|
-
replaysOnErrorSampleRate: 1.0,
|
|
158
|
-
}),
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// 设置应用上下文
|
|
162
|
-
Sentry.setContext('app', {
|
|
163
|
-
name: process.env.APP_NAME || 'React App',
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
// ✨ 手动开始会话(确保会话被正确追踪)
|
|
167
|
-
Sentry.startSession();
|
|
168
|
-
|
|
169
|
-
console.log('✅ Sentry initialized successfully with session tracking');
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
// ✨ 新增:会话管理工具
|
|
173
|
-
export const sentrySession = {
|
|
174
|
-
// 开始新会话
|
|
175
|
-
startSession: () => {
|
|
176
|
-
Sentry.startSession();
|
|
177
|
-
},
|
|
178
|
-
|
|
179
|
-
// 结束当前会话
|
|
180
|
-
endSession: () => {
|
|
181
|
-
Sentry.endSession();
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
// 标记会话为崩溃
|
|
185
|
-
captureSession: (crashed: boolean = false) => {
|
|
186
|
-
Sentry.captureSession(crashed);
|
|
187
|
-
},
|
|
188
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { useLocation, matchRoutes } from 'react-router';
|
|
3
|
-
import { useAppData } from '@config/router/appContext';
|
|
4
|
-
|
|
5
|
-
const APP_NAME = process.env.APP_NAME!;
|
|
6
|
-
|
|
7
|
-
export const useRouteTitle = () => {
|
|
8
|
-
const location = useLocation();
|
|
9
|
-
const { routes } = useAppData();
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
// 将路由配置转换为适合 matchRoutes 的格式
|
|
13
|
-
const routesList = Object.keys(routes).map((key) => {
|
|
14
|
-
const route = routes[key];
|
|
15
|
-
return {
|
|
16
|
-
path: route.absPath,
|
|
17
|
-
meta: route.props,
|
|
18
|
-
id: key,
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
// 匹配当前路径的路由
|
|
22
|
-
const matchedRoutes = matchRoutes(routesList, location);
|
|
23
|
-
|
|
24
|
-
if (matchedRoutes && matchedRoutes.length > 0) {
|
|
25
|
-
// 找到最后一个匹配的路由(叶子路由)
|
|
26
|
-
const leafRoute = matchedRoutes[matchedRoutes.length - 1];
|
|
27
|
-
const title = leafRoute.route.meta?.title;
|
|
28
|
-
|
|
29
|
-
if (title) {
|
|
30
|
-
document.title = title;
|
|
31
|
-
} else {
|
|
32
|
-
document.title = APP_NAME;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}, [location.pathname, routes]);
|
|
36
|
-
};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { useLocation } from 'react-router';
|
|
3
|
-
import { sentryPerformance, sentryContext, sentryError, sentrySession } from '@/utils/sentry';
|
|
4
|
-
|
|
5
|
-
// 页面性能监控 Hook
|
|
6
|
-
export const useSentryPageTracking = (pageName: string) => {
|
|
7
|
-
const location = useLocation();
|
|
8
|
-
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
// ✨ 记录页面访问(保持会话活跃)
|
|
11
|
-
sentrySession.recordPageView(pageName, `${location.pathname}${location.search}`);
|
|
12
|
-
|
|
13
|
-
const cleanup = sentryPerformance.withSpan(`Page: ${pageName}`, 'navigation', () => {
|
|
14
|
-
sentryContext.setContext('page', {
|
|
15
|
-
name: pageName,
|
|
16
|
-
path: location.pathname,
|
|
17
|
-
search: location.search,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
sentryPerformance.addBreadcrumb(`Navigation to ${pageName}`, 'navigation', 'info');
|
|
21
|
-
|
|
22
|
-
return () => {
|
|
23
|
-
// 清理函数
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
return cleanup;
|
|
28
|
-
}, [pageName, location]);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// 组件性能监控 Hook
|
|
32
|
-
export const useSentryComponentTracking = (componentName: string) => {
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
return sentryPerformance.withSpan(`Component: ${componentName}`, 'ui.react.mount', () => {
|
|
35
|
-
sentryPerformance.addBreadcrumb(`Component ${componentName} mounted`, 'ui', 'info');
|
|
36
|
-
|
|
37
|
-
return () => {
|
|
38
|
-
sentryPerformance.addBreadcrumb(`Component ${componentName} unmounted`, 'ui', 'info');
|
|
39
|
-
};
|
|
40
|
-
});
|
|
41
|
-
}, [componentName]);
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// 错误处理 Hook
|
|
45
|
-
export const useSentryErrorHandler = () => {
|
|
46
|
-
return {
|
|
47
|
-
captureError: (error: Error, context?: Record<string, any>) => {
|
|
48
|
-
sentryError.captureException(error, context);
|
|
49
|
-
},
|
|
50
|
-
captureMessage: (message: string, level?: 'info' | 'warning' | 'error') => {
|
|
51
|
-
sentryError.captureMessage(message, level);
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// 点击事件追踪 Hook
|
|
57
|
-
export const useSentryClickTracking = () => {
|
|
58
|
-
return {
|
|
59
|
-
trackClick: (
|
|
60
|
-
buttonName: string,
|
|
61
|
-
context?: {
|
|
62
|
-
buttonId?: string;
|
|
63
|
-
location?: string;
|
|
64
|
-
extraData?: Record<string, any>;
|
|
65
|
-
},
|
|
66
|
-
) => {
|
|
67
|
-
const clickData = {
|
|
68
|
-
buttonName,
|
|
69
|
-
buttonId: context?.buttonId,
|
|
70
|
-
location: context?.location || window.location.pathname,
|
|
71
|
-
clickTime: new Date().toISOString(),
|
|
72
|
-
timestamp: Date.now(),
|
|
73
|
-
...context?.extraData,
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// ✨ 主动发送点击事件到 Sentry(这会立即发送)
|
|
77
|
-
sentryError.captureMessage(`Button Click: ${buttonName}`, 'info');
|
|
78
|
-
|
|
79
|
-
// 设置点击上下文(会包含在上面的消息中)
|
|
80
|
-
sentryContext.setContext('clickData', clickData);
|
|
81
|
-
|
|
82
|
-
// 记录用户操作(用于埋点统计)
|
|
83
|
-
sentrySession.recordUserAction(`Button Click: ${buttonName}`, clickData);
|
|
84
|
-
|
|
85
|
-
// 添加面包屑用于调试
|
|
86
|
-
sentryPerformance.addBreadcrumb(`Button clicked: ${buttonName}`, 'user.click', 'info');
|
|
87
|
-
|
|
88
|
-
// 设置点击上下文
|
|
89
|
-
sentryContext.setContext('lastClick', clickData);
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { useThemeStore } from '@store/theme';
|
|
2
|
-
import { Button } from 'antd';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
|
|
5
|
-
export default function BasePage() {
|
|
6
|
-
const theme = useThemeStore(state => state.theme);
|
|
7
|
-
const setTheme = useThemeStore(state => state.setTheme);
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<>
|
|
11
|
-
<Button type="primary">antd按钮</Button>
|
|
12
|
-
<button
|
|
13
|
-
type="button"
|
|
14
|
-
className={
|
|
15
|
-
' dark:text-red-600 dark:bg-[var(--tailwindssantd-color-primary)] bg-[var(--tailwindssantd-color-primary)]'
|
|
16
|
-
}
|
|
17
|
-
>
|
|
18
|
-
tailwind按钮
|
|
19
|
-
</button>
|
|
20
|
-
<button type="button" onClick={() => setTheme('dark')}>
|
|
21
|
-
切换主题({theme})
|
|
22
|
-
</button>
|
|
23
|
-
</>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 字节转换函数
|
|
3
|
-
* @param kb
|
|
4
|
-
* @returns
|
|
5
|
-
*/
|
|
6
|
-
interface FormatSizeUnitsProps {
|
|
7
|
-
kb: number;
|
|
8
|
-
units?: string[];
|
|
9
|
-
}
|
|
10
|
-
export function formatSizeUnits(props: FormatSizeUnitsProps) {
|
|
11
|
-
const { kb, units = ['KB', 'MB', 'GB', 'TB', 'PB'] } = props;
|
|
12
|
-
let newKb = kb;
|
|
13
|
-
let unitIndex = 0;
|
|
14
|
-
|
|
15
|
-
while (kb >= 1024 && unitIndex < units.length - 1) {
|
|
16
|
-
newKb = newKb / 1024;
|
|
17
|
-
unitIndex++;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return `${kb.toFixed(2)} ${units[unitIndex]}`;
|
|
21
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// 创建一个空数组来存储匹配的对象
|
|
2
|
-
let matchedObjects: any[] = [];
|
|
3
|
-
|
|
4
|
-
// 定义一个递归函数来遍历子路由对象
|
|
5
|
-
function traverseRoutes(routes) {
|
|
6
|
-
for (const route of routes) {
|
|
7
|
-
// 检查当前子路由对象是否具有"microApp"属性
|
|
8
|
-
if (Object.prototype.hasOwnProperty.call(route, 'microApp')) {
|
|
9
|
-
// 如果有,将该子路由对象添加到结果数组中
|
|
10
|
-
matchedObjects.push(route);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// 检查当前子路由对象是否还有更深层级的子路由
|
|
14
|
-
if (Object.prototype.hasOwnProperty.call(route, 'routes')) {
|
|
15
|
-
// 递归调用自身来遍历更深层级的子路由对象
|
|
16
|
-
traverseRoutes(route.routes);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const getMicroApp = (a: any[]) => {
|
|
22
|
-
matchedObjects = [];
|
|
23
|
-
// 遍历变量a中的每个对象
|
|
24
|
-
for (const obj of a) {
|
|
25
|
-
// 检查当前对象是否具有"microApp"属性
|
|
26
|
-
if (Object.prototype.hasOwnProperty.call(obj, 'microApp')) {
|
|
27
|
-
// 如果有,将该对象添加到结果数组中
|
|
28
|
-
matchedObjects.push(obj);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 检查当前对象是否具有"routes"属性
|
|
32
|
-
if (Object.prototype.hasOwnProperty.call(obj, 'routes')) {
|
|
33
|
-
// 调用递归函数来遍历子路由对象
|
|
34
|
-
traverseRoutes(obj.routes);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return matchedObjects;
|
|
39
|
-
};
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import * as Sentry from '@sentry/react';
|
|
2
|
-
|
|
3
|
-
// 性能监控
|
|
4
|
-
export const sentryPerformance = {
|
|
5
|
-
// 开始性能追踪
|
|
6
|
-
startSpan: (name: string, op?: string) => {
|
|
7
|
-
return Sentry.startSpan(
|
|
8
|
-
{
|
|
9
|
-
name,
|
|
10
|
-
op: op || 'custom',
|
|
11
|
-
},
|
|
12
|
-
(span) => {
|
|
13
|
-
return span;
|
|
14
|
-
},
|
|
15
|
-
);
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
// 测量函数执行时间
|
|
19
|
-
measureFunction: <T extends any[], R>(fn: (...args: T) => R, name: string, op?: string): ((...args: T) => R) => {
|
|
20
|
-
return (...args: T): R => {
|
|
21
|
-
return Sentry.startSpan(
|
|
22
|
-
{
|
|
23
|
-
name,
|
|
24
|
-
op: op || 'function',
|
|
25
|
-
},
|
|
26
|
-
() => fn(...args),
|
|
27
|
-
);
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
// 测量异步函数
|
|
32
|
-
measureAsyncFunction: <T extends any[], R>(fn: (...args: T) => Promise<R>, name: string, op?: string): ((...args: T) => Promise<R>) => {
|
|
33
|
-
return async (...args: T): Promise<R> => {
|
|
34
|
-
return Sentry.startSpan(
|
|
35
|
-
{
|
|
36
|
-
name,
|
|
37
|
-
op: op || 'async_function',
|
|
38
|
-
},
|
|
39
|
-
async () => await fn(...args),
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
// 添加面包屑
|
|
45
|
-
addBreadcrumb: (message: string, category?: string, level?: Sentry.SeverityLevel) => {
|
|
46
|
-
Sentry.addBreadcrumb({
|
|
47
|
-
message,
|
|
48
|
-
category: category || 'custom',
|
|
49
|
-
level: level || 'info',
|
|
50
|
-
timestamp: Date.now() / 1000,
|
|
51
|
-
});
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
// 手动创建 span
|
|
55
|
-
withSpan: <T>(name: string, op: string, callback: () => T): T => {
|
|
56
|
-
return Sentry.startSpan({ name, op }, callback);
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// 错误报告
|
|
61
|
-
export const sentryError = {
|
|
62
|
-
// 捕获异常
|
|
63
|
-
captureException: (error: Error, context?: Record<string, any>) => {
|
|
64
|
-
Sentry.withScope((scope) => {
|
|
65
|
-
if (context) {
|
|
66
|
-
Object.entries(context).forEach(([key, value]) => {
|
|
67
|
-
scope.setExtra(key, value);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
Sentry.captureException(error);
|
|
71
|
-
});
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
// 捕获消息
|
|
75
|
-
captureMessage: (message: string, level?: Sentry.SeverityLevel) => {
|
|
76
|
-
Sentry.captureMessage(message, level || 'info');
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
// 手动报告错误
|
|
80
|
-
reportError: (error: Error, tags?: Record<string, string>) => {
|
|
81
|
-
Sentry.withScope((scope) => {
|
|
82
|
-
if (tags) {
|
|
83
|
-
Object.entries(tags).forEach(([key, value]) => {
|
|
84
|
-
scope.setTag(key, value);
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
scope.setLevel('error');
|
|
88
|
-
Sentry.captureException(error);
|
|
89
|
-
});
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// 用户上下文
|
|
94
|
-
export const sentryUser = {
|
|
95
|
-
// 设置用户信息
|
|
96
|
-
setUser: (user: { id: string; email?: string; username?: string }) => {
|
|
97
|
-
Sentry.setUser(user);
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
// 清除用户信息
|
|
101
|
-
clearUser: () => {
|
|
102
|
-
Sentry.setUser(null);
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
// 设置用户反馈
|
|
106
|
-
showReportDialog: (options?: Sentry.ReportDialogOptions) => {
|
|
107
|
-
Sentry.showReportDialog(options);
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// 自定义标签和上下文
|
|
112
|
-
export const sentryContext = {
|
|
113
|
-
// 设置标签
|
|
114
|
-
setTag: (key: string, value: string) => {
|
|
115
|
-
Sentry.setTag(key, value);
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
// 设置上下文
|
|
119
|
-
setContext: (key: string, context: Record<string, any>) => {
|
|
120
|
-
Sentry.setContext(key, context);
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
// 设置额外信息
|
|
124
|
-
setExtra: (key: string, extra: any) => {
|
|
125
|
-
Sentry.setExtra(key, extra);
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// ✨ 新增:会话管理
|
|
130
|
-
export const sentrySession = {
|
|
131
|
-
// 开始用户会话
|
|
132
|
-
startUserSession: (userId: string, userInfo?: { email?: string; username?: string }) => {
|
|
133
|
-
// 设置用户信息
|
|
134
|
-
Sentry.setUser({
|
|
135
|
-
id: userId,
|
|
136
|
-
...userInfo,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// 开始会话
|
|
140
|
-
Sentry.startSession();
|
|
141
|
-
|
|
142
|
-
// 添加会话开始的面包屑
|
|
143
|
-
Sentry.addBreadcrumb({
|
|
144
|
-
message: `User session started for ${userId}`,
|
|
145
|
-
category: 'session',
|
|
146
|
-
level: 'info',
|
|
147
|
-
});
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
// 结束用户会话
|
|
151
|
-
endUserSession: () => {
|
|
152
|
-
Sentry.addBreadcrumb({
|
|
153
|
-
message: 'User session ended',
|
|
154
|
-
category: 'session',
|
|
155
|
-
level: 'info',
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
Sentry.endSession();
|
|
159
|
-
Sentry.setUser(null);
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
// 记录页面访问(会话活动)
|
|
163
|
-
recordPageView: (pageName: string, url: string) => {
|
|
164
|
-
Sentry.addBreadcrumb({
|
|
165
|
-
message: `Page view: ${pageName}`,
|
|
166
|
-
category: 'navigation',
|
|
167
|
-
level: 'info',
|
|
168
|
-
data: {
|
|
169
|
-
url,
|
|
170
|
-
timestamp: new Date().toISOString(),
|
|
171
|
-
},
|
|
172
|
-
});
|
|
173
|
-
},
|
|
174
|
-
|
|
175
|
-
// 记录用户操作(保持会话活跃)
|
|
176
|
-
recordUserAction: (action: string, details?: Record<string, any>) => {
|
|
177
|
-
Sentry.addBreadcrumb({
|
|
178
|
-
message: `User action: ${action}`,
|
|
179
|
-
category: 'user',
|
|
180
|
-
level: 'info',
|
|
181
|
-
data: {
|
|
182
|
-
...details,
|
|
183
|
-
timestamp: new Date().toISOString(),
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
},
|
|
187
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { sentryPerformance } from './sentry';
|
|
2
|
-
|
|
3
|
-
// 函数性能监控装饰器
|
|
4
|
-
export function withSentryPerformance(name: string, op = 'function') {
|
|
5
|
-
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
6
|
-
const originalMethod = descriptor.value;
|
|
7
|
-
|
|
8
|
-
descriptor.value = sentryPerformance.measureFunction(
|
|
9
|
-
originalMethod,
|
|
10
|
-
name,
|
|
11
|
-
op,
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
return descriptor;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// 异步函数性能监控装饰器
|
|
19
|
-
export function withSentryAsyncPerformance(
|
|
20
|
-
name: string,
|
|
21
|
-
op = 'async_function',
|
|
22
|
-
) {
|
|
23
|
-
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
24
|
-
const originalMethod = descriptor.value;
|
|
25
|
-
|
|
26
|
-
descriptor.value = sentryPerformance.measureAsyncFunction(
|
|
27
|
-
originalMethod,
|
|
28
|
-
name,
|
|
29
|
-
op,
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
return descriptor;
|
|
33
|
-
};
|
|
34
|
-
}
|