nsgm-cli 2.1.19 → 2.1.21

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 (99) hide show
  1. package/client/components/Button.tsx +3 -3
  2. package/client/components/ClientProviders.tsx +12 -12
  3. package/client/components/LanguageSwitcher.tsx +26 -26
  4. package/client/components/SSRSafeAntdProvider.tsx +7 -7
  5. package/client/components/SuppressHydrationWarnings.tsx +30 -30
  6. package/client/components/__tests__/Button.test.tsx +12 -12
  7. package/client/layout/index.tsx +124 -124
  8. package/client/redux/reducers.ts +2 -2
  9. package/client/redux/store.ts +24 -24
  10. package/client/redux/template/manage/actions.ts +40 -40
  11. package/client/redux/template/manage/reducers.ts +32 -32
  12. package/client/redux/template/manage/types.ts +19 -19
  13. package/client/service/template/manage.ts +29 -29
  14. package/client/styled/common.ts +6 -6
  15. package/client/styled/layout/index.ts +17 -17
  16. package/client/styled/template/manage.ts +19 -19
  17. package/client/utils/common.ts +54 -54
  18. package/client/utils/cookie.ts +30 -30
  19. package/client/utils/fetch.ts +111 -111
  20. package/client/utils/i18n.ts +41 -41
  21. package/client/utils/menu.tsx +12 -12
  22. package/client/utils/navigation.ts +22 -22
  23. package/client/utils/sso.ts +124 -124
  24. package/client/utils/suppressWarnings.ts +17 -17
  25. package/generation/prettierrc +6 -0
  26. package/lib/args.js +19 -19
  27. package/lib/cli/app.d.ts +1 -1
  28. package/lib/cli/app.js +2 -2
  29. package/lib/cli/commands/build.d.ts +1 -1
  30. package/lib/cli/commands/build.js +9 -9
  31. package/lib/cli/commands/create.d.ts +1 -1
  32. package/lib/cli/commands/create.js +36 -36
  33. package/lib/cli/commands/delete.d.ts +1 -1
  34. package/lib/cli/commands/delete.js +55 -55
  35. package/lib/cli/commands/export.d.ts +1 -1
  36. package/lib/cli/commands/export.js +12 -12
  37. package/lib/cli/commands/help.d.ts +1 -1
  38. package/lib/cli/commands/help.js +29 -29
  39. package/lib/cli/commands/init.d.ts +1 -1
  40. package/lib/cli/commands/init.js +31 -31
  41. package/lib/cli/commands/server.d.ts +1 -1
  42. package/lib/cli/commands/server.js +12 -12
  43. package/lib/cli/commands/upgrade.d.ts +1 -1
  44. package/lib/cli/commands/upgrade.js +13 -13
  45. package/lib/cli/commands/version.d.ts +1 -1
  46. package/lib/cli/commands/version.js +7 -7
  47. package/lib/cli/index.d.ts +13 -13
  48. package/lib/cli/parser.d.ts +1 -1
  49. package/lib/cli/parser.js +12 -12
  50. package/lib/cli/registry.d.ts +1 -1
  51. package/lib/cli/types.d.ts +2 -2
  52. package/lib/cli/utils/console.d.ts +2 -2
  53. package/lib/cli/utils/console.js +22 -22
  54. package/lib/cli/utils/index.d.ts +2 -2
  55. package/lib/cli/utils/prompt.d.ts +1 -1
  56. package/lib/cli/utils/prompt.js +98 -98
  57. package/lib/constants.js +28 -28
  58. package/lib/generate.d.ts +2 -2
  59. package/lib/generate.js +19 -19
  60. package/lib/generate_create.d.ts +1 -1
  61. package/lib/generate_create.js +38 -38
  62. package/lib/generate_delete.js +63 -63
  63. package/lib/generate_init.js +94 -94
  64. package/lib/generators/base-generator.d.ts +1 -1
  65. package/lib/generators/base-generator.js +23 -23
  66. package/lib/generators/file-generator.js +15 -15
  67. package/lib/generators/generator-factory.d.ts +5 -5
  68. package/lib/generators/i18n-generator.d.ts +1 -1
  69. package/lib/generators/i18n-generator.js +127 -127
  70. package/lib/generators/page-generator.d.ts +1 -1
  71. package/lib/generators/page-generator.js +25 -25
  72. package/lib/generators/resolver-generator.d.ts +1 -1
  73. package/lib/generators/resolver-generator.js +27 -27
  74. package/lib/generators/schema-generator.d.ts +1 -1
  75. package/lib/generators/schema-generator.js +4 -4
  76. package/lib/generators/service-generator.d.ts +1 -1
  77. package/lib/generators/service-generator.js +29 -29
  78. package/lib/generators/sql-generator.d.ts +1 -1
  79. package/lib/generators/sql-generator.js +10 -10
  80. package/lib/index.js +23 -23
  81. package/lib/server/csrf.d.ts +3 -3
  82. package/lib/server/csrf.js +20 -20
  83. package/lib/server/db.d.ts +1 -1
  84. package/lib/server/db.js +21 -21
  85. package/lib/server/graphql.js +26 -26
  86. package/lib/server/plugins/date.d.ts +1 -1
  87. package/lib/server/plugins/date.js +6 -6
  88. package/lib/server/utils/graphql-cache.js +5 -5
  89. package/lib/tsconfig.build.tsbuildinfo +1 -1
  90. package/lib/utils/project-config.d.ts +1 -1
  91. package/lib/utils/project-config.js +20 -20
  92. package/lib/utils.js +3 -3
  93. package/package.json +1 -1
  94. package/pages/_app.tsx +62 -62
  95. package/pages/_document.tsx +15 -15
  96. package/pages/_error.tsx +26 -26
  97. package/pages/index.tsx +48 -48
  98. package/pages/login.tsx +64 -64
  99. package/pages/template/manage.tsx +175 -175
@@ -1,21 +1,21 @@
1
1
  // GraphQL 客户端与 CSRF 保护工具
2
2
 
3
- import axios from 'axios'
4
- import { getLocalApiPrefix } from './common'
3
+ import axios from "axios";
4
+ import { getLocalApiPrefix } from "./common";
5
5
 
6
6
  // 配置 axios 默认行为
7
- axios.defaults.withCredentials = true
7
+ axios.defaults.withCredentials = true;
8
8
 
9
9
  // ==================== GraphQL 配置 ====================
10
10
 
11
11
  export const GRAPHQL_CONFIG = {
12
12
  // GraphQL 端点
13
- endpoint: '/graphql',
13
+ endpoint: "/graphql",
14
14
 
15
15
  // 默认请求头
16
16
  defaultHeaders: {
17
- 'Content-Type': 'application/json',
18
- Accept: 'application/json',
17
+ "Content-Type": "application/json",
18
+ Accept: "application/json",
19
19
  },
20
20
 
21
21
  // 缓存配置
@@ -28,61 +28,61 @@ export const GRAPHQL_CONFIG = {
28
28
  // CSRF 配置
29
29
  csrf: {
30
30
  enabled: true,
31
- tokenHeader: 'X-CSRF-Token',
32
- cookieName: 'csrfToken',
31
+ tokenHeader: "X-CSRF-Token",
32
+ cookieName: "csrfToken",
33
33
  },
34
34
 
35
35
  // 开发模式配置
36
36
  development: {
37
- enableDebugLogs: process.env.NODE_ENV === 'development',
37
+ enableDebugLogs: process.env.NODE_ENV === "development",
38
38
  },
39
- }
39
+ };
40
40
 
41
41
  // GraphQL 操作类型
42
42
  export enum GraphQLOperationType {
43
- QUERY = 'query',
44
- MUTATION = 'mutation',
45
- SUBSCRIPTION = 'subscription',
43
+ QUERY = "query",
44
+ MUTATION = "mutation",
45
+ SUBSCRIPTION = "subscription",
46
46
  }
47
47
 
48
48
  // GraphQL 工具函数
49
49
  export const GraphQLUtils = {
50
50
  // 检测操作类型
51
51
  getOperationType(query: string): GraphQLOperationType {
52
- const trimmed = query.trim().toLowerCase()
53
- if (trimmed.startsWith('mutation')) return GraphQLOperationType.MUTATION
54
- if (trimmed.startsWith('subscription')) return GraphQLOperationType.SUBSCRIPTION
55
- return GraphQLOperationType.QUERY
52
+ const trimmed = query.trim().toLowerCase();
53
+ if (trimmed.startsWith("mutation")) return GraphQLOperationType.MUTATION;
54
+ if (trimmed.startsWith("subscription")) return GraphQLOperationType.SUBSCRIPTION;
55
+ return GraphQLOperationType.QUERY;
56
56
  },
57
57
 
58
58
  // 提取操作名称
59
59
  getOperationName(query: string): string | null {
60
- const match = query.match(/(?:query|mutation|subscription)\s+(\w+)/)
61
- return match ? match[1] : null
60
+ const match = query.match(/(?:query|mutation|subscription)\s+(\w+)/);
61
+ return match ? match[1] : null;
62
62
  },
63
63
 
64
64
  // 生成缓存键
65
65
  generateCacheKey(query: string, variables?: any): string {
66
- const operationName = this.getOperationName(query) || 'anonymous'
67
- const variablesHash = variables ? JSON.stringify(variables) : ''
68
- return `${operationName}_${btoa(variablesHash)}`
66
+ const operationName = this.getOperationName(query) || "anonymous";
67
+ const variablesHash = variables ? JSON.stringify(variables) : "";
68
+ return `${operationName}_${btoa(variablesHash)}`;
69
69
  },
70
70
 
71
71
  // 验证 GraphQL 查询语法
72
72
  isValidQuery(query: string): boolean {
73
73
  try {
74
- const trimmed = query.trim()
74
+ const trimmed = query.trim();
75
75
  return (
76
76
  trimmed.length > 0 &&
77
- (trimmed.includes('query') || trimmed.includes('mutation') || trimmed.includes('subscription')) &&
78
- trimmed.includes('{') &&
79
- trimmed.includes('}')
80
- )
77
+ (trimmed.includes("query") || trimmed.includes("mutation") || trimmed.includes("subscription")) &&
78
+ trimmed.includes("{") &&
79
+ trimmed.includes("}")
80
+ );
81
81
  } catch {
82
- return false
82
+ return false;
83
83
  }
84
84
  },
85
- }
85
+ };
86
86
 
87
87
  // ==================== CSRF 工具 ====================
88
88
 
@@ -94,18 +94,18 @@ export const getCSRFToken = async (): Promise<string> => {
94
94
  try {
95
95
  const response = await axios.get(`${getLocalApiPrefix()}/csrf-token`, {
96
96
  withCredentials: true,
97
- })
97
+ });
98
98
 
99
99
  if (!response.data?.csrfToken) {
100
- throw new Error('服务器返回的 CSRF token 为空')
100
+ throw new Error("服务器返回的 CSRF token 为空");
101
101
  }
102
102
 
103
- return response.data.csrfToken
103
+ return response.data.csrfToken;
104
104
  } catch (error) {
105
- console.error('获取 CSRF token 错误:', error)
106
- throw error
105
+ console.error("获取 CSRF token 错误:", error);
106
+ throw error;
107
107
  }
108
- }
108
+ };
109
109
 
110
110
  // ==================== GraphQL 客户端 ====================
111
111
  /**
@@ -115,28 +115,28 @@ export const getCSRFToken = async (): Promise<string> => {
115
115
  export const getLocalGraphql = async (query: string, variables: any = {}) => {
116
116
  // 验证查询语法
117
117
  if (!GraphQLUtils.isValidQuery(query)) {
118
- throw new Error('Invalid GraphQL query syntax')
118
+ throw new Error("Invalid GraphQL query syntax");
119
119
  }
120
120
 
121
121
  try {
122
122
  // 检测操作类型
123
- const operationType = GraphQLUtils.getOperationType(query)
124
- const isMutation = operationType === GraphQLOperationType.MUTATION
123
+ const operationType = GraphQLUtils.getOperationType(query);
124
+ const isMutation = operationType === GraphQLOperationType.MUTATION;
125
125
 
126
126
  const headers: Record<string, string> = {
127
127
  ...GRAPHQL_CONFIG.defaultHeaders,
128
- }
128
+ };
129
129
 
130
- let response
130
+ let response;
131
131
 
132
132
  if (isMutation) {
133
133
  // Mutation 使用 POST 方法并需要 CSRF token
134
134
  if (GRAPHQL_CONFIG.csrf.enabled) {
135
135
  try {
136
- const csrfToken = await getCSRFToken()
137
- headers[GRAPHQL_CONFIG.csrf.tokenHeader] = csrfToken
136
+ const csrfToken = await getCSRFToken();
137
+ headers[GRAPHQL_CONFIG.csrf.tokenHeader] = csrfToken;
138
138
  } catch (csrfError) {
139
- console.warn('获取 CSRF token 失败,继续执行 GraphQL 请求:', csrfError)
139
+ console.warn("获取 CSRF token 失败,继续执行 GraphQL 请求:", csrfError);
140
140
  }
141
141
  }
142
142
 
@@ -150,61 +150,61 @@ export const getLocalGraphql = async (query: string, variables: any = {}) => {
150
150
  headers,
151
151
  withCredentials: true,
152
152
  }
153
- )
153
+ );
154
154
  } else {
155
155
  // Query 和 Subscription 使用 GET 方法,不需要 CSRF token
156
- const params = new URLSearchParams()
157
- params.append('query', query)
156
+ const params = new URLSearchParams();
157
+ params.append("query", query);
158
158
  if (variables && Object.keys(variables).length > 0) {
159
- params.append('variables', JSON.stringify(variables))
159
+ params.append("variables", JSON.stringify(variables));
160
160
  }
161
161
 
162
162
  response = await axios.get(`${getLocalApiPrefix()}/graphql?${params.toString()}`, {
163
163
  headers: {
164
- Accept: 'application/json',
164
+ Accept: "application/json",
165
165
  },
166
166
  withCredentials: true,
167
- })
167
+ });
168
168
  }
169
169
 
170
170
  if (response?.data) {
171
- return response.data
171
+ return response.data;
172
172
  } else {
173
- throw new Error('GraphQL response is empty')
173
+ throw new Error("GraphQL response is empty");
174
174
  }
175
175
  } catch (error) {
176
176
  // 只为 mutation 检查 CSRF 错误 (403),因为 query 使用 GET 不需要 CSRF token
177
177
  if (axios.isAxiosError(error) && error.response?.status === 403) {
178
- const operationType = GraphQLUtils.getOperationType(query)
178
+ const operationType = GraphQLUtils.getOperationType(query);
179
179
 
180
180
  if (operationType === GraphQLOperationType.MUTATION) {
181
- console.warn('🔄 CSRF token 可能已过期,尝试重试 mutation...')
181
+ console.warn("🔄 CSRF token 可能已过期,尝试重试 mutation...");
182
182
  try {
183
183
  // 重新获取 token 并重试 mutation
184
- const newCsrfToken = await getCSRFToken()
184
+ const newCsrfToken = await getCSRFToken();
185
185
  const retryHeaders = {
186
186
  ...GRAPHQL_CONFIG.defaultHeaders,
187
187
  [GRAPHQL_CONFIG.csrf.tokenHeader]: newCsrfToken,
188
- }
188
+ };
189
189
 
190
190
  const retryResponse = await axios.post(
191
191
  `${getLocalApiPrefix()}/graphql`,
192
192
  { query, variables },
193
193
  { headers: retryHeaders, withCredentials: true }
194
- )
194
+ );
195
195
 
196
- return retryResponse.data
196
+ return retryResponse.data;
197
197
  } catch (retryError) {
198
- console.error('❌ CSRF mutation 重试失败:', retryError)
199
- throw retryError
198
+ console.error("❌ CSRF mutation 重试失败:", retryError);
199
+ throw retryError;
200
200
  }
201
201
  }
202
202
  }
203
203
 
204
- console.error('GraphQL request failed:', error)
205
- throw error
204
+ console.error("GraphQL request failed:", error);
205
+ throw error;
206
206
  }
207
- }
207
+ };
208
208
 
209
209
  // ==================== 文件上传工具 ====================
210
210
 
@@ -214,140 +214,140 @@ export const getLocalGraphql = async (query: string, variables: any = {}) => {
214
214
  export const createCSRFUploadProps = (
215
215
  action: string,
216
216
  options: {
217
- name?: string
218
- onSuccess?: (fileName: string) => void
219
- onError?: (fileName: string) => void
220
- beforeUpload?: (file: File) => boolean | Promise<boolean>
221
- accept?: string
222
- multiple?: boolean
217
+ name?: string;
218
+ onSuccess?: (fileName: string) => void;
219
+ onError?: (fileName: string) => void;
220
+ beforeUpload?: (file: File) => boolean | Promise<boolean>;
221
+ accept?: string;
222
+ multiple?: boolean;
223
223
  } = {}
224
224
  ) => {
225
- const { name = 'file', onSuccess, onError, beforeUpload: customBeforeUpload, accept, multiple = false } = options
225
+ const { name = "file", onSuccess, onError, beforeUpload: customBeforeUpload, accept, multiple = false } = options;
226
226
 
227
227
  const uploadProps: any = {
228
228
  name,
229
229
  action,
230
230
  multiple,
231
231
  customRequest: async (options: any) => {
232
- const { onError: onUploadError, onSuccess: onUploadSuccess, file } = options
232
+ const { onError: onUploadError, onSuccess: onUploadSuccess, file } = options;
233
233
 
234
234
  try {
235
235
  // 获取 CSRF token
236
- const csrfToken = await getCSRFToken()
236
+ const csrfToken = await getCSRFToken();
237
237
  if (!csrfToken) {
238
- throw new Error('CSRF Token 获取失败')
238
+ throw new Error("CSRF Token 获取失败");
239
239
  }
240
240
 
241
241
  // 创建 FormData
242
- const formData = new FormData()
243
- formData.append(name, file)
242
+ const formData = new FormData();
243
+ formData.append(name, file);
244
244
 
245
245
  // 发送请求
246
- const uploadUrl = action.startsWith('http') ? action : getLocalApiPrefix() + action
246
+ const uploadUrl = action.startsWith("http") ? action : getLocalApiPrefix() + action;
247
247
  const response = await axios.post(uploadUrl, formData, {
248
248
  headers: {
249
249
  [GRAPHQL_CONFIG.csrf.tokenHeader]: csrfToken,
250
250
  },
251
251
  withCredentials: true,
252
- })
252
+ });
253
253
 
254
254
  if (response.status >= 200 && response.status < 300) {
255
- onUploadSuccess(response)
255
+ onUploadSuccess(response);
256
256
  } else {
257
- throw new Error(`Upload failed: ${response.statusText}`)
257
+ throw new Error(`Upload failed: ${response.statusText}`);
258
258
  }
259
259
  } catch (error) {
260
- onUploadError(error)
260
+ onUploadError(error);
261
261
  }
262
262
  },
263
263
  beforeUpload: async (file: File) => {
264
264
  try {
265
265
  // 验证 CSRF token
266
- const validation = await validateCSRFForUpload()
266
+ const validation = await validateCSRFForUpload();
267
267
  if (!validation.valid) {
268
- throw new Error(validation.error)
268
+ throw new Error(validation.error);
269
269
  }
270
270
 
271
271
  // 执行自定义的 beforeUpload 检查
272
272
  if (customBeforeUpload) {
273
- const result = await customBeforeUpload(file)
274
- return result
273
+ const result = await customBeforeUpload(file);
274
+ return result;
275
275
  }
276
276
 
277
- return true
277
+ return true;
278
278
  } catch (error) {
279
- console.error('Upload preparation failed:', error)
280
- return false
279
+ console.error("Upload preparation failed:", error);
280
+ return false;
281
281
  }
282
282
  },
283
283
  onChange(info: any) {
284
- const { status, name: fileName } = info.file
284
+ const { status, name: fileName } = info.file;
285
285
 
286
- if (status === 'done') {
286
+ if (status === "done") {
287
287
  if (onSuccess) {
288
- onSuccess(fileName)
288
+ onSuccess(fileName);
289
289
  }
290
- } else if (status === 'error') {
290
+ } else if (status === "error") {
291
291
  if (onError) {
292
- onError(fileName)
292
+ onError(fileName);
293
293
  }
294
294
  }
295
295
  },
296
- }
296
+ };
297
297
 
298
298
  // 只有当 accept 有值时才添加该属性
299
299
  if (accept) {
300
- uploadProps.accept = accept
300
+ uploadProps.accept = accept;
301
301
  }
302
302
 
303
- return uploadProps
304
- }
303
+ return uploadProps;
304
+ };
305
305
 
306
306
  /**
307
307
  * 验证上传前的 CSRF 状态
308
308
  */
309
309
  export const validateCSRFForUpload = async (): Promise<{ valid: boolean; token?: string; error?: string }> => {
310
310
  try {
311
- const csrfToken = await getCSRFToken()
311
+ const csrfToken = await getCSRFToken();
312
312
  if (!csrfToken) {
313
313
  return {
314
314
  valid: false,
315
- error: 'CSRF Token 获取失败,请刷新页面重试',
316
- }
315
+ error: "CSRF Token 获取失败,请刷新页面重试",
316
+ };
317
317
  }
318
318
  return {
319
319
  valid: true,
320
320
  token: csrfToken,
321
- }
321
+ };
322
322
  } catch (error) {
323
323
  return {
324
324
  valid: false,
325
- error: error instanceof Error ? error.message : '获取 CSRF Token 时发生未知错误',
326
- }
325
+ error: error instanceof Error ? error.message : "获取 CSRF Token 时发生未知错误",
326
+ };
327
327
  }
328
- }
328
+ };
329
329
 
330
330
  // ==================== 工具函数 ====================
331
331
 
332
332
  // GraphQL 查询辅助函数
333
333
  export const graphqlQuery = async (query: string, variables?: any) => {
334
- return getLocalGraphql(query, variables)
335
- }
334
+ return getLocalGraphql(query, variables);
335
+ };
336
336
 
337
337
  // GraphQL 变更辅助函数 (Mutation)
338
338
  export const graphqlMutation = async (mutation: string, variables?: any) => {
339
- return getLocalGraphql(mutation, variables)
340
- }
339
+ return getLocalGraphql(mutation, variables);
340
+ };
341
341
 
342
342
  // 检查 GraphQL 响应是否有错误
343
343
  export const hasGraphqlErrors = (response: any): boolean => {
344
- return response?.errors && response.errors.length > 0
345
- }
344
+ return response?.errors && response.errors.length > 0;
345
+ };
346
346
 
347
347
  // 获取 GraphQL 错误信息
348
348
  export const getGraphqlErrorMessage = (response: any): string => {
349
349
  if (hasGraphqlErrors(response)) {
350
- return response.errors.map((error: any) => error.message).join('; ')
350
+ return response.errors.map((error: any) => error.message).join("; ");
351
351
  }
352
- return ''
353
- }
352
+ return "";
353
+ };
@@ -1,68 +1,68 @@
1
- import { useTranslation } from 'next-i18next'
2
- import { useRouter } from 'next/router'
3
- import zhCN from 'antd/locale/zh_CN'
4
- import enUS from 'antd/locale/en_US'
5
- import jaJP from 'antd/locale/ja_JP'
1
+ import { useTranslation } from "next-i18next";
2
+ import { useRouter } from "next/router";
3
+ import zhCN from "antd/locale/zh_CN";
4
+ import enUS from "antd/locale/en_US";
5
+ import jaJP from "antd/locale/ja_JP";
6
6
 
7
7
  // Antd locale mapping
8
8
  export const getAntdLocale = (locale: string) => {
9
9
  switch (locale) {
10
- case 'zh-CN':
11
- return zhCN
12
- case 'en-US':
13
- return enUS
14
- case 'ja-JP':
15
- return jaJP
10
+ case "zh-CN":
11
+ return zhCN;
12
+ case "en-US":
13
+ return enUS;
14
+ case "ja-JP":
15
+ return jaJP;
16
16
  default:
17
- return zhCN
17
+ return zhCN;
18
18
  }
19
- }
19
+ };
20
20
 
21
21
  // Custom hook for translation with namespace
22
- export const useI18n = (namespace = 'common') => {
23
- const { t, i18n } = useTranslation(namespace)
24
- const router = useRouter()
22
+ export const useI18n = (namespace = "common") => {
23
+ const { t, i18n } = useTranslation(namespace);
24
+ const router = useRouter();
25
25
 
26
26
  return {
27
27
  t,
28
- locale: typeof window !== 'undefined' ? router.locale || 'zh-CN' : 'zh-CN',
28
+ locale: typeof window !== "undefined" ? router.locale || "zh-CN" : "zh-CN",
29
29
  language: i18n.language,
30
30
  changeLanguage: (lng: string) => {
31
- if (typeof window !== 'undefined') {
32
- const { pathname, asPath, query } = router
33
- router.push({ pathname, query }, asPath, { locale: lng })
31
+ if (typeof window !== "undefined") {
32
+ const { pathname, asPath, query } = router;
33
+ router.push({ pathname, query }, asPath, { locale: lng });
34
34
  }
35
35
  },
36
36
  isRTL: false, // Add RTL support if needed
37
- }
38
- }
37
+ };
38
+ };
39
39
 
40
40
  // Format currency based on locale
41
- export const formatCurrency = (amount: number, locale = 'zh-CN') => {
41
+ export const formatCurrency = (amount: number, locale = "zh-CN") => {
42
42
  const currencyMap: Record<string, string> = {
43
- 'zh-CN': 'CNY',
44
- 'en-US': 'USD',
45
- 'ja-JP': 'JPY',
46
- }
43
+ "zh-CN": "CNY",
44
+ "en-US": "USD",
45
+ "ja-JP": "JPY",
46
+ };
47
47
 
48
48
  return new Intl.NumberFormat(locale, {
49
- style: 'currency',
50
- currency: currencyMap[locale] || 'CNY',
51
- }).format(amount)
52
- }
49
+ style: "currency",
50
+ currency: currencyMap[locale] || "CNY",
51
+ }).format(amount);
52
+ };
53
53
 
54
54
  // Format date based on locale
55
- export const formatDate = (date: Date | string, locale = 'zh-CN') => {
56
- const dateObj = typeof date === 'string' ? new Date(date) : date
55
+ export const formatDate = (date: Date | string, locale = "zh-CN") => {
56
+ const dateObj = typeof date === "string" ? new Date(date) : date;
57
57
 
58
58
  return new Intl.DateTimeFormat(locale, {
59
- year: 'numeric',
60
- month: 'long',
61
- day: 'numeric',
62
- }).format(dateObj)
63
- }
59
+ year: "numeric",
60
+ month: "long",
61
+ day: "numeric",
62
+ }).format(dateObj);
63
+ };
64
64
 
65
65
  // Format number based on locale
66
- export const formatNumber = (number: number, locale = 'zh-CN') => {
67
- return new Intl.NumberFormat(locale).format(number)
68
- }
66
+ export const formatNumber = (number: number, locale = "zh-CN") => {
67
+ return new Intl.NumberFormat(locale).format(number);
68
+ };
@@ -1,28 +1,28 @@
1
- import { BookOutlined, SolutionOutlined } from '@ant-design/icons'
2
- import React from 'react'
1
+ import { BookOutlined, SolutionOutlined } from "@ant-design/icons";
2
+ import React from "react";
3
3
 
4
4
  // 统一的菜单配置函数,支持可选的多语言翻译
5
5
  export const getMenuConfig = (t?: (key: string) => string) => {
6
- let key = 1
6
+ let key = 1;
7
7
 
8
8
  return [
9
9
  {
10
10
  key: (++key).toString(),
11
- text: t ? t('layout:layout.menu.introduction') : '介绍',
12
- url: '/',
11
+ text: t ? t("layout:layout.menu.introduction") : "介绍",
12
+ url: "/",
13
13
  icon: <BookOutlined rev={undefined} />,
14
14
  subMenus: null,
15
15
  },
16
16
  {
17
17
  key: (++key).toString(),
18
- text: t ? t('layout:layout.menu.template') : '模板',
19
- url: '/template/manage',
18
+ text: t ? t("layout:layout.menu.template") : "模板",
19
+ url: "/template/manage",
20
20
  icon: <SolutionOutlined rev={undefined} />,
21
21
  subMenus: [
22
22
  {
23
23
  key: `${key}_1`,
24
- text: t ? t('layout:layout.menu.template1') : '模板1',
25
- url: '/template/manage',
24
+ text: t ? t("layout:layout.menu.template1") : "模板1",
25
+ url: "/template/manage",
26
26
  },
27
27
  ],
28
28
  },
@@ -39,8 +39,8 @@ export const getMenuConfig = (t?: (key: string) => string) => {
39
39
  },
40
40
  ],
41
41
  }*/
42
- ]
43
- }
42
+ ];
43
+ };
44
44
 
45
45
  // 默认导出不传翻译函数,使用中文
46
- export default getMenuConfig()
46
+ export default getMenuConfig();