nsgm-cli 2.1.14 → 2.1.15
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/README.md +49 -26
- package/client/components/ClientProviders.tsx +29 -0
- package/client/components/LanguageSwitcher.tsx +59 -0
- package/client/components/SSRSafeAntdProvider.tsx +24 -0
- package/client/components/SuppressHydrationWarnings.tsx +55 -0
- package/client/layout/index.tsx +82 -126
- package/client/styled/common.ts +0 -1
- package/client/styled/layout/index.ts +218 -104
- package/client/styled/template/manage.ts +88 -1
- package/client/utils/i18n.ts +68 -0
- package/client/utils/menu.tsx +42 -36
- package/client/utils/navigation.ts +58 -0
- package/client/utils/suppressWarnings.ts +32 -0
- package/eslint.config.js +17 -20
- package/generation/client/redux/reducers.ts +1 -1
- package/generation/client/utils/menu.tsx +36 -30
- package/generation/env +3 -0
- package/generation/next.config.js +7 -3
- package/generation/package.json +5 -2
- package/generation/tsconfig.json +6 -19
- package/lib/cli/commands/create.js +1 -1
- package/lib/cli/commands/delete.js +1 -1
- package/lib/cli/commands/init.js +6 -6
- package/lib/cli/utils/prompt.d.ts +1 -1
- package/lib/cli/utils/prompt.js +76 -117
- package/lib/constants.d.ts +8 -1
- package/lib/constants.js +17 -2
- package/lib/generate.js +1 -0
- package/lib/generate_create.js +14 -11
- package/lib/generate_delete.js +86 -9
- package/lib/generate_init.d.ts +6 -0
- package/lib/generate_init.js +125 -5
- package/lib/generators/file-generator.d.ts +48 -0
- package/lib/generators/file-generator.js +455 -0
- package/lib/generators/i18n-generator.d.ts +51 -0
- package/lib/generators/i18n-generator.js +320 -0
- package/lib/generators/page-generator.d.ts +6 -2
- package/lib/generators/page-generator.js +182 -156
- package/lib/generators/resolver-generator.d.ts +6 -4
- package/lib/generators/resolver-generator.js +114 -75
- package/lib/generators/service-generator.d.ts +4 -0
- package/lib/generators/service-generator.js +120 -6
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/next-i18next.config.js +18 -0
- package/next.config.js +55 -16
- package/package.json +7 -2
- package/pages/_app.tsx +84 -35
- package/pages/_document.tsx +39 -2
- package/pages/_error.tsx +66 -0
- package/pages/index.tsx +46 -29
- package/pages/login.tsx +58 -33
- package/pages/template/manage.tsx +95 -109
- package/public/locales/en-US/common.json +48 -0
- package/public/locales/en-US/home.json +57 -0
- package/public/locales/en-US/layout.json +22 -0
- package/public/locales/en-US/login.json +13 -0
- package/public/locales/en-US/template.json +42 -0
- package/public/locales/ja-JP/common.json +48 -0
- package/public/locales/ja-JP/home.json +57 -0
- package/public/locales/ja-JP/layout.json +22 -0
- package/public/locales/ja-JP/login.json +13 -0
- package/public/locales/ja-JP/template.json +42 -0
- package/public/locales/zh-CN/common.json +48 -0
- package/public/locales/zh-CN/home.json +57 -0
- package/public/locales/zh-CN/layout.json +22 -0
- package/public/locales/zh-CN/login.json +13 -0
- package/public/locales/zh-CN/template.json +42 -0
- package/server/utils/validation.js +163 -0
- package/types/i18next.d.ts +10 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @type {import('next-i18next').UserConfig}
|
|
3
|
+
*/
|
|
4
|
+
module.exports = {
|
|
5
|
+
i18n: {
|
|
6
|
+
defaultLocale: 'zh-CN',
|
|
7
|
+
locales: ['zh-CN', 'en-US', 'ja-JP'],
|
|
8
|
+
localeDetection: false, // 禁用自动语言检测
|
|
9
|
+
},
|
|
10
|
+
localePath: './public/locales',
|
|
11
|
+
/** To avoid issues when deploying to some platforms, we can configure the cache */
|
|
12
|
+
saveMissing: false,
|
|
13
|
+
strictMode: true,
|
|
14
|
+
serializeConfig: false,
|
|
15
|
+
react: {
|
|
16
|
+
useSuspense: false,
|
|
17
|
+
},
|
|
18
|
+
}
|
package/next.config.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const { PHASE_DEVELOPMENT_SERVER, PHASE_EXPORT } = require('next/constants')
|
|
5
5
|
const fs = require('fs')
|
|
6
6
|
const path = require('path')
|
|
7
|
+
const { i18n } = require('./next-i18next.config')
|
|
7
8
|
|
|
8
9
|
module.exports = (phase, defaultConfig, options) => {
|
|
9
10
|
let projectConfig = null
|
|
@@ -38,10 +39,11 @@ module.exports = (phase, defaultConfig, options) => {
|
|
|
38
39
|
if (phase === PHASE_DEVELOPMENT_SERVER) {
|
|
39
40
|
prefix = ''
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
let configObj = {
|
|
43
44
|
// target: 'serverless',
|
|
44
45
|
// crossOrign: 'anonymous',
|
|
46
|
+
i18n,
|
|
45
47
|
serverRuntimeConfig: {},
|
|
46
48
|
publicRuntimeConfig: {
|
|
47
49
|
version,
|
|
@@ -51,22 +53,32 @@ module.exports = (phase, defaultConfig, options) => {
|
|
|
51
53
|
port,
|
|
52
54
|
env,
|
|
53
55
|
phase,
|
|
54
|
-
isExport:
|
|
56
|
+
isExport: phase === PHASE_EXPORT,
|
|
55
57
|
},
|
|
56
|
-
transpilePackages: [
|
|
58
|
+
transpilePackages: [
|
|
59
|
+
'antd',
|
|
60
|
+
'@ant-design',
|
|
61
|
+
'rc-util',
|
|
62
|
+
'rc-pagination',
|
|
63
|
+
'rc-picker',
|
|
64
|
+
'rc-notification',
|
|
65
|
+
'rc-tooltip',
|
|
66
|
+
'rc-tree',
|
|
67
|
+
'rc-table',
|
|
68
|
+
],
|
|
57
69
|
// Bundle 优化配置
|
|
58
70
|
experimental: {
|
|
59
71
|
optimizeCss: true, // 启用 CSS 优化(已安装 critters 依赖)
|
|
60
|
-
esmExternals: true // 支持 ESM 外部依赖
|
|
72
|
+
esmExternals: true, // 支持 ESM 外部依赖
|
|
61
73
|
},
|
|
62
74
|
compiler: {
|
|
63
75
|
removeConsole: phase !== PHASE_DEVELOPMENT_SERVER,
|
|
64
|
-
styledComponents: true
|
|
76
|
+
styledComponents: true,
|
|
65
77
|
},
|
|
66
78
|
...(phase === PHASE_DEVELOPMENT_SERVER && {
|
|
67
79
|
devIndicators: {
|
|
68
|
-
position: 'bottom-right'
|
|
69
|
-
}
|
|
80
|
+
position: 'bottom-right',
|
|
81
|
+
},
|
|
70
82
|
}),
|
|
71
83
|
allowedDevOrigins: [
|
|
72
84
|
'http://127.0.0.1:8080',
|
|
@@ -76,9 +88,39 @@ module.exports = (phase, defaultConfig, options) => {
|
|
|
76
88
|
'127.0.0.1:8080',
|
|
77
89
|
'localhost:8080',
|
|
78
90
|
'127.0.0.1',
|
|
79
|
-
'localhost'
|
|
91
|
+
'localhost',
|
|
80
92
|
],
|
|
81
93
|
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
|
94
|
+
// 抑制服务端渲染时的 useLayoutEffect 警告
|
|
95
|
+
if (dev && isServer) {
|
|
96
|
+
const originalWarn = console.warn
|
|
97
|
+
const originalError = console.error
|
|
98
|
+
|
|
99
|
+
console.warn = (...args) => {
|
|
100
|
+
const warnMessage = args[0]
|
|
101
|
+
if (
|
|
102
|
+
typeof warnMessage === 'string' &&
|
|
103
|
+
(warnMessage.includes('useLayoutEffect does nothing on the server') ||
|
|
104
|
+
warnMessage.includes('Warning: useLayoutEffect does nothing on the server'))
|
|
105
|
+
) {
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
originalWarn.apply(console, args)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.error = (...args) => {
|
|
112
|
+
const errorMessage = args[0]
|
|
113
|
+
if (
|
|
114
|
+
typeof errorMessage === 'string' &&
|
|
115
|
+
(errorMessage.includes('useLayoutEffect does nothing on the server') ||
|
|
116
|
+
errorMessage.includes('Warning: useLayoutEffect does nothing on the server'))
|
|
117
|
+
) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
originalError.apply(console, args)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
82
124
|
// 启用压缩
|
|
83
125
|
if (!dev && !isServer) {
|
|
84
126
|
config.optimization = {
|
|
@@ -134,10 +176,7 @@ module.exports = (phase, defaultConfig, options) => {
|
|
|
134
176
|
}
|
|
135
177
|
|
|
136
178
|
// 支持 TypeScript 路径映射
|
|
137
|
-
config.resolve.modules = [
|
|
138
|
-
path.resolve(__dirname, 'client'),
|
|
139
|
-
'node_modules'
|
|
140
|
-
]
|
|
179
|
+
config.resolve.modules = [path.resolve(__dirname, 'client'), 'node_modules']
|
|
141
180
|
|
|
142
181
|
return config
|
|
143
182
|
},
|
|
@@ -164,14 +203,14 @@ module.exports = (phase, defaultConfig, options) => {
|
|
|
164
203
|
return [
|
|
165
204
|
{
|
|
166
205
|
source: prefix === '' ? '/' : prefix,
|
|
167
|
-
destination: '/'
|
|
206
|
+
destination: '/',
|
|
168
207
|
},
|
|
169
208
|
{
|
|
170
209
|
source: prefix + '/:slug*',
|
|
171
|
-
destination: '/:slug*'
|
|
172
|
-
}
|
|
210
|
+
destination: '/:slug*',
|
|
211
|
+
},
|
|
173
212
|
]
|
|
174
|
-
}
|
|
213
|
+
},
|
|
175
214
|
}
|
|
176
215
|
}
|
|
177
216
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nsgm-cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.15",
|
|
4
4
|
"description": "A CLI tool to run Next/Style-components and Graphql/Mysql fullstack project",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -68,9 +68,11 @@
|
|
|
68
68
|
"lib/*",
|
|
69
69
|
"public/*",
|
|
70
70
|
"scripts/*",
|
|
71
|
+
"types/*",
|
|
71
72
|
"*.config.js",
|
|
72
73
|
".babelrc",
|
|
73
|
-
"next-env.d.ts"
|
|
74
|
+
"next-env.d.ts",
|
|
75
|
+
"next-i18next.config.js"
|
|
74
76
|
],
|
|
75
77
|
"homepage": "https://github.com/erishen/nsgm#readme",
|
|
76
78
|
"dependencies": {
|
|
@@ -79,6 +81,9 @@
|
|
|
79
81
|
"@types/bcrypt": "6.0.0",
|
|
80
82
|
"@types/express-session": "1.18.2",
|
|
81
83
|
"antd": "5.26.6",
|
|
84
|
+
"next-i18next": "15.3.0",
|
|
85
|
+
"react-i18next": "15.2.0",
|
|
86
|
+
"i18next": "24.1.0",
|
|
82
87
|
"axios": "1.11.0",
|
|
83
88
|
"bcrypt": "6.0.0",
|
|
84
89
|
"body-parser": "2.2.0",
|
package/pages/_app.tsx
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
+
// 必须在所有其他导入之前执行
|
|
2
|
+
import '@/utils/suppressWarnings'
|
|
3
|
+
|
|
1
4
|
import React, { useEffect, useState } from 'react'
|
|
2
5
|
import { Provider } from 'react-redux'
|
|
3
|
-
import {
|
|
6
|
+
import { Spin } from 'antd'
|
|
7
|
+
import { appWithTranslation } from 'next-i18next'
|
|
8
|
+
import { useRouter } from 'next/router'
|
|
4
9
|
import { useStore } from '@/redux/store'
|
|
5
|
-
import {
|
|
10
|
+
import { Loading } from '@/styled/common'
|
|
6
11
|
import LayoutComponent from '@/layout'
|
|
12
|
+
import ClientProviders from '@/components/ClientProviders'
|
|
13
|
+
import SuppressHydrationWarnings from '@/components/SuppressHydrationWarnings'
|
|
14
|
+
import SSRSafeAntdProvider from '@/components/SSRSafeAntdProvider'
|
|
7
15
|
import { login } from '@/utils/sso'
|
|
8
|
-
import {
|
|
16
|
+
import { getAntdLocale } from '@/utils/i18n'
|
|
17
|
+
import { navigateToLogin } from '@/utils/navigation'
|
|
18
|
+
import nextI18NextConfig from '../next-i18next.config.js'
|
|
9
19
|
import 'antd/dist/reset.css'
|
|
10
20
|
|
|
11
21
|
const theme = {
|
|
@@ -16,16 +26,53 @@ const theme = {
|
|
|
16
26
|
|
|
17
27
|
const App = ({ Component, pageProps }) => {
|
|
18
28
|
const store = useStore(pageProps.initialReduxState)
|
|
29
|
+
const router = useRouter()
|
|
19
30
|
const [ssoUser, setSsoUser] = useState(null)
|
|
20
31
|
const [pageLoad, setPageLoad] = useState(false)
|
|
21
32
|
const [loginChecked, setLoginChecked] = useState(false)
|
|
33
|
+
const [mounted, setMounted] = useState(false)
|
|
34
|
+
const [currentLocale, setCurrentLocale] = useState('zh-CN')
|
|
35
|
+
|
|
36
|
+
// 检查是否为特殊页面(登录页、错误页)
|
|
37
|
+
// 避免在服务器端访问 router.pathname
|
|
38
|
+
const isSpecialPage =
|
|
39
|
+
Component.displayName === 'ErrorPage' ||
|
|
40
|
+
Component.name === 'ErrorPage' ||
|
|
41
|
+
Component.displayName === 'LoginPage' ||
|
|
42
|
+
Component.name === 'LoginPage'
|
|
43
|
+
|
|
44
|
+
// Get Antd locale based on current locale
|
|
45
|
+
const antdLocale = getAntdLocale(currentLocale)
|
|
22
46
|
|
|
23
47
|
useEffect(() => {
|
|
24
|
-
|
|
48
|
+
setMounted(true)
|
|
49
|
+
// 只在客户端设置当前语言
|
|
50
|
+
if (typeof window !== 'undefined') {
|
|
51
|
+
const locale = router.locale || 'zh-CN'
|
|
52
|
+
setCurrentLocale(locale)
|
|
53
|
+
}
|
|
54
|
+
}, [router.locale])
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!mounted) return
|
|
58
|
+
|
|
59
|
+
// 对于特殊页面,跳过登录检查
|
|
60
|
+
if (isSpecialPage) {
|
|
61
|
+
setLoginChecked(true)
|
|
62
|
+
setPageLoad(true)
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 检查当前路径是否为登录页或错误页
|
|
25
67
|
const isLoginPage = typeof window !== 'undefined' && window.location.pathname === '/login'
|
|
68
|
+
const isErrorPage =
|
|
69
|
+
typeof window !== 'undefined' &&
|
|
70
|
+
(window.location.pathname === '/404' ||
|
|
71
|
+
window.location.pathname === '/500' ||
|
|
72
|
+
window.location.pathname === '/_error')
|
|
26
73
|
|
|
27
|
-
//
|
|
28
|
-
if (isLoginPage) {
|
|
74
|
+
// 如果是登录页或错误页,直接设置加载完成,不进行登录检查
|
|
75
|
+
if (isLoginPage || isErrorPage) {
|
|
29
76
|
setLoginChecked(true)
|
|
30
77
|
setPageLoad(true)
|
|
31
78
|
return
|
|
@@ -34,9 +81,9 @@ const App = ({ Component, pageProps }) => {
|
|
|
34
81
|
// 检查是否有登录凭证
|
|
35
82
|
const hasLoginCookie = typeof window !== 'undefined' && document.cookie.includes('_cas_nsgm')
|
|
36
83
|
|
|
37
|
-
//
|
|
84
|
+
// 如果没有登录凭证,直接跳转到登录页面(保持当前语言)
|
|
38
85
|
if (!hasLoginCookie && typeof window !== 'undefined') {
|
|
39
|
-
|
|
86
|
+
navigateToLogin(router)
|
|
40
87
|
return
|
|
41
88
|
}
|
|
42
89
|
|
|
@@ -51,40 +98,42 @@ const App = ({ Component, pageProps }) => {
|
|
|
51
98
|
setTimeout(() => {
|
|
52
99
|
setPageLoad(true)
|
|
53
100
|
}, 100)
|
|
54
|
-
}, [])
|
|
101
|
+
}, [mounted, isSpecialPage])
|
|
55
102
|
|
|
56
103
|
return (
|
|
57
104
|
<>
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
105
|
+
<SuppressHydrationWarnings />
|
|
106
|
+
<SSRSafeAntdProvider locale={antdLocale}>
|
|
107
|
+
<ClientProviders theme={theme} whiteColor={true}>
|
|
108
|
+
<Provider store={store}>
|
|
109
|
+
{isSpecialPage ? (
|
|
110
|
+
// 特殊页面(错误页、登录页)直接渲染,不使用 Layout
|
|
111
|
+
<Component {...pageProps} />
|
|
112
|
+
) : !loginChecked ? (
|
|
113
|
+
<Loading>
|
|
114
|
+
<Spin size="large" />
|
|
115
|
+
</Loading>
|
|
116
|
+
) : pageLoad ? (
|
|
117
|
+
ssoUser ? (
|
|
118
|
+
<LayoutComponent user={ssoUser}>
|
|
119
|
+
<Component {...pageProps} />
|
|
120
|
+
</LayoutComponent>
|
|
121
|
+
) : (
|
|
68
122
|
<Component {...pageProps} />
|
|
69
|
-
|
|
123
|
+
)
|
|
70
124
|
) : (
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
</Provider>
|
|
79
|
-
</ThemeProvider>
|
|
125
|
+
<Loading>
|
|
126
|
+
<Spin size="large" />
|
|
127
|
+
</Loading>
|
|
128
|
+
)}
|
|
129
|
+
</Provider>
|
|
130
|
+
</ClientProviders>
|
|
131
|
+
</SSRSafeAntdProvider>
|
|
80
132
|
</>
|
|
81
133
|
)
|
|
82
134
|
}
|
|
83
135
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
pageProps: await Component?.getInitialProps(ctx),
|
|
87
|
-
}
|
|
88
|
-
}
|
|
136
|
+
// 移除 getInitialProps 以启用静态优化
|
|
137
|
+
// 如果需要页面级别的数据获取,请在各个页面中使用 getStaticProps 或 getServerSideProps
|
|
89
138
|
|
|
90
|
-
export default App
|
|
139
|
+
export default appWithTranslation(App, nextI18NextConfig)
|
package/pages/_document.tsx
CHANGED
|
@@ -2,9 +2,12 @@ import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/do
|
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { ServerStyleSheet } from 'styled-components'
|
|
4
4
|
|
|
5
|
-
const MyDocument = () => {
|
|
5
|
+
const MyDocument = (props) => {
|
|
6
|
+
// 从 props 中获取语言信息,如果没有则默认为 zh-CN
|
|
7
|
+
const locale = props.locale || 'zh-CN'
|
|
8
|
+
|
|
6
9
|
return (
|
|
7
|
-
<Html>
|
|
10
|
+
<Html lang={locale}>
|
|
8
11
|
<title>NSGM CLI</title>
|
|
9
12
|
<meta
|
|
10
13
|
name="viewport"
|
|
@@ -44,6 +47,39 @@ const MyDocument = () => {
|
|
|
44
47
|
-moz-osx-font-smoothing: grayscale;
|
|
45
48
|
}
|
|
46
49
|
`}</style>
|
|
50
|
+
|
|
51
|
+
{/* 抑制服务端渲染的 useLayoutEffect 警告 */}
|
|
52
|
+
<script
|
|
53
|
+
dangerouslySetInnerHTML={{
|
|
54
|
+
__html: `
|
|
55
|
+
if (typeof window === 'undefined') {
|
|
56
|
+
global.window = {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 在服务端抑制 useLayoutEffect 警告
|
|
60
|
+
if (typeof console !== 'undefined' && process.env.NODE_ENV === 'development') {
|
|
61
|
+
const originalError = console.error;
|
|
62
|
+
const originalWarn = console.warn;
|
|
63
|
+
|
|
64
|
+
console.error = function(...args) {
|
|
65
|
+
const message = args[0];
|
|
66
|
+
if (typeof message === 'string' && message.includes('useLayoutEffect does nothing on the server')) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
originalError.apply(console, args);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
console.warn = function(...args) {
|
|
73
|
+
const message = args[0];
|
|
74
|
+
if (typeof message === 'string' && message.includes('useLayoutEffect does nothing on the server')) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
originalWarn.apply(console, args);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
`,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
47
83
|
</Head>
|
|
48
84
|
<body>
|
|
49
85
|
<Main />
|
|
@@ -69,6 +105,7 @@ MyDocument.getInitialProps = async (ctx: DocumentContext) => {
|
|
|
69
105
|
|
|
70
106
|
return {
|
|
71
107
|
...initialProps,
|
|
108
|
+
locale: ctx.locale || 'zh-CN',
|
|
72
109
|
styles: [initialProps.styles, sheet.getStyleElement()],
|
|
73
110
|
}
|
|
74
111
|
} finally {
|
package/pages/_error.tsx
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Result, Button } from 'antd'
|
|
3
|
+
import { NextPageContext } from 'next'
|
|
4
|
+
|
|
5
|
+
interface ErrorProps {
|
|
6
|
+
statusCode?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function ErrorPage({ statusCode }: ErrorProps) {
|
|
10
|
+
const getErrorMessage = () => {
|
|
11
|
+
if (statusCode === 404) {
|
|
12
|
+
return '页面未找到'
|
|
13
|
+
} else if (statusCode === 500) {
|
|
14
|
+
return '服务器错误'
|
|
15
|
+
}
|
|
16
|
+
return '发生了未知错误'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const getErrorTitle = () => {
|
|
20
|
+
if (statusCode === 404) {
|
|
21
|
+
return '404'
|
|
22
|
+
} else if (statusCode === 500) {
|
|
23
|
+
return '500'
|
|
24
|
+
}
|
|
25
|
+
return '错误'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
style={{
|
|
31
|
+
minHeight: '100vh',
|
|
32
|
+
display: 'flex',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
padding: '20px',
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
<Result
|
|
39
|
+
status={statusCode === 404 ? '404' : '500'}
|
|
40
|
+
title={getErrorTitle()}
|
|
41
|
+
subTitle={getErrorMessage()}
|
|
42
|
+
extra={
|
|
43
|
+
<Button
|
|
44
|
+
type="primary"
|
|
45
|
+
onClick={() => {
|
|
46
|
+
if (typeof window !== 'undefined') {
|
|
47
|
+
window.location.href = '/'
|
|
48
|
+
}
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
返回首页
|
|
52
|
+
</Button>
|
|
53
|
+
}
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ErrorPage.getInitialProps = ({ res, err }: NextPageContext) => {
|
|
60
|
+
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
|
|
61
|
+
return { statusCode }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
ErrorPage.displayName = 'ErrorPage'
|
|
65
|
+
|
|
66
|
+
export default ErrorPage
|
package/pages/index.tsx
CHANGED
|
@@ -3,14 +3,22 @@ import { Container } from '../client/styled/common'
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { Card, Typography, Divider, Row, Col, Tag } from 'antd'
|
|
5
5
|
import { CodeOutlined, BookOutlined, DatabaseOutlined, SettingOutlined } from '@ant-design/icons'
|
|
6
|
+
import { useTranslation } from 'next-i18next'
|
|
7
|
+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
|
6
8
|
|
|
7
9
|
const { Title, Paragraph, Text } = Typography
|
|
8
10
|
|
|
9
11
|
const Page = () => {
|
|
12
|
+
const { t } = useTranslation(['common', 'home'])
|
|
13
|
+
|
|
10
14
|
return (
|
|
11
15
|
<Container>
|
|
12
16
|
<Typography style={{ padding: '24px' }}>
|
|
13
|
-
<
|
|
17
|
+
<Row justify="space-between" align="middle" style={{ marginBottom: '24px' }}>
|
|
18
|
+
<Col>
|
|
19
|
+
<Title level={1}>{t('home:page.title')}</Title>
|
|
20
|
+
</Col>
|
|
21
|
+
</Row>
|
|
14
22
|
|
|
15
23
|
<Paragraph>
|
|
16
24
|
<Row gutter={[16, 16]}>
|
|
@@ -28,7 +36,7 @@ const Page = () => {
|
|
|
28
36
|
</Col>
|
|
29
37
|
</Row>
|
|
30
38
|
</Paragraph>
|
|
31
|
-
<Paragraph
|
|
39
|
+
<Paragraph>{t('home:page.description')}</Paragraph>
|
|
32
40
|
|
|
33
41
|
<Card style={{ marginBottom: '24px' }}>
|
|
34
42
|
<Row gutter={[24, 16]}>
|
|
@@ -37,11 +45,11 @@ const Page = () => {
|
|
|
37
45
|
type="inner"
|
|
38
46
|
title={
|
|
39
47
|
<>
|
|
40
|
-
<DatabaseOutlined />
|
|
48
|
+
<DatabaseOutlined /> {t('home:page.sections.database.title')}
|
|
41
49
|
</>
|
|
42
50
|
}
|
|
43
51
|
>
|
|
44
|
-
|
|
52
|
+
{t('home:page.sections.database.description')}
|
|
45
53
|
</Card>
|
|
46
54
|
</Col>
|
|
47
55
|
<Col xs={24} md={8}>
|
|
@@ -49,11 +57,11 @@ const Page = () => {
|
|
|
49
57
|
type="inner"
|
|
50
58
|
title={
|
|
51
59
|
<>
|
|
52
|
-
<SettingOutlined />
|
|
60
|
+
<SettingOutlined /> {t('home:page.sections.project.title')}
|
|
53
61
|
</>
|
|
54
62
|
}
|
|
55
63
|
>
|
|
56
|
-
|
|
64
|
+
{t('home:page.sections.project.description')}
|
|
57
65
|
</Card>
|
|
58
66
|
</Col>
|
|
59
67
|
<Col xs={24} md={8}>
|
|
@@ -61,66 +69,68 @@ const Page = () => {
|
|
|
61
69
|
type="inner"
|
|
62
70
|
title={
|
|
63
71
|
<>
|
|
64
|
-
<CodeOutlined />
|
|
72
|
+
<CodeOutlined /> {t('home:page.sections.framework.title')}
|
|
65
73
|
</>
|
|
66
74
|
}
|
|
67
75
|
>
|
|
68
|
-
|
|
76
|
+
{t('home:page.sections.framework.description')}
|
|
69
77
|
</Card>
|
|
70
78
|
</Col>
|
|
71
79
|
</Row>
|
|
72
80
|
</Card>
|
|
73
81
|
|
|
74
82
|
<Title level={2}>
|
|
75
|
-
<BookOutlined />
|
|
83
|
+
<BookOutlined /> {t('home:page.commands.title')}
|
|
76
84
|
</Title>
|
|
77
85
|
<Divider />
|
|
78
86
|
|
|
79
87
|
<Row gutter={[16, 16]}>
|
|
80
88
|
<Col xs={24} md={8}>
|
|
81
89
|
<Card hoverable>
|
|
82
|
-
<Title level={4}
|
|
90
|
+
<Title level={4}>{t('home:page.commands.categories.projectManagement.title')}</Title>
|
|
83
91
|
<ul>
|
|
84
92
|
<li>
|
|
85
|
-
<Text strong>nsgm init</Text> -
|
|
93
|
+
<Text strong>nsgm init</Text> - {t('home:page.commands.categories.projectManagement.items.init')}
|
|
86
94
|
</li>
|
|
87
95
|
<li>
|
|
88
|
-
<Text strong>nsgm upgrade</Text> -
|
|
96
|
+
<Text strong>nsgm upgrade</Text> -{' '}
|
|
97
|
+
{t('home:page.commands.categories.projectManagement.items.upgrade')}
|
|
89
98
|
</li>
|
|
90
99
|
</ul>
|
|
91
100
|
</Card>
|
|
92
101
|
</Col>
|
|
93
102
|
<Col xs={24} md={8}>
|
|
94
103
|
<Card hoverable>
|
|
95
|
-
<Title level={4}
|
|
104
|
+
<Title level={4}>{t('home:page.commands.categories.templateOperations.title')}</Title>
|
|
96
105
|
<ul>
|
|
97
106
|
<li>
|
|
98
|
-
<Text strong>nsgm create</Text> -
|
|
107
|
+
<Text strong>nsgm create</Text> - {t('home:page.commands.categories.templateOperations.items.create')}
|
|
99
108
|
</li>
|
|
100
109
|
<li>
|
|
101
|
-
<Text strong>nsgm delete</Text> -
|
|
110
|
+
<Text strong>nsgm delete</Text> - {t('home:page.commands.categories.templateOperations.items.delete')}
|
|
102
111
|
</li>
|
|
103
112
|
<li>
|
|
104
|
-
<Text strong>nsgm deletedb</Text> -
|
|
113
|
+
<Text strong>nsgm deletedb</Text> -{' '}
|
|
114
|
+
{t('home:page.commands.categories.templateOperations.items.deletedb')}
|
|
105
115
|
</li>
|
|
106
116
|
</ul>
|
|
107
117
|
</Card>
|
|
108
118
|
</Col>
|
|
109
119
|
<Col xs={24} md={8}>
|
|
110
120
|
<Card hoverable>
|
|
111
|
-
<Title level={4}
|
|
121
|
+
<Title level={4}>{t('home:page.commands.categories.runBuild.title')}</Title>
|
|
112
122
|
<ul>
|
|
113
123
|
<li>
|
|
114
|
-
<Text strong>nsgm dev</Text> -
|
|
124
|
+
<Text strong>nsgm dev</Text> - {t('home:page.commands.categories.runBuild.items.dev')}
|
|
115
125
|
</li>
|
|
116
126
|
<li>
|
|
117
|
-
<Text strong>nsgm start</Text> -
|
|
127
|
+
<Text strong>nsgm start</Text> - {t('home:page.commands.categories.runBuild.items.start')}
|
|
118
128
|
</li>
|
|
119
129
|
<li>
|
|
120
|
-
<Text strong>nsgm build</Text> -
|
|
130
|
+
<Text strong>nsgm build</Text> - {t('home:page.commands.categories.runBuild.items.build')}
|
|
121
131
|
</li>
|
|
122
132
|
<li>
|
|
123
|
-
<Text strong>nsgm export</Text> -
|
|
133
|
+
<Text strong>nsgm export</Text> - {t('home:page.commands.categories.runBuild.items.export')}
|
|
124
134
|
</li>
|
|
125
135
|
</ul>
|
|
126
136
|
</Card>
|
|
@@ -128,21 +138,19 @@ const Page = () => {
|
|
|
128
138
|
</Row>
|
|
129
139
|
|
|
130
140
|
<Title level={2} style={{ marginTop: '24px' }}>
|
|
131
|
-
|
|
141
|
+
{t('home:page.parameters.title')}
|
|
132
142
|
</Title>
|
|
133
143
|
<Divider />
|
|
134
144
|
<Card>
|
|
135
145
|
<ul>
|
|
136
146
|
<li>
|
|
137
|
-
<Text strong>dictionary:</Text>
|
|
138
|
-
dictionary=webapp 或者 nsgm export/init webapp
|
|
147
|
+
<Text strong>dictionary:</Text> {t('home:page.parameters.items.dictionary')}
|
|
139
148
|
</li>
|
|
140
149
|
<li>
|
|
141
|
-
<Text strong>controller:</Text>
|
|
150
|
+
<Text strong>controller:</Text> {t('home:page.parameters.items.controller')}
|
|
142
151
|
</li>
|
|
143
152
|
<li>
|
|
144
|
-
<Text strong>action:</Text>
|
|
145
|
-
create/delete math test
|
|
153
|
+
<Text strong>action:</Text> {t('home:page.parameters.items.action')}
|
|
146
154
|
</li>
|
|
147
155
|
</ul>
|
|
148
156
|
</Card>
|
|
@@ -151,8 +159,17 @@ const Page = () => {
|
|
|
151
159
|
)
|
|
152
160
|
}
|
|
153
161
|
|
|
154
|
-
|
|
155
|
-
|
|
162
|
+
export const getServerSideProps = async ({ locale }) => {
|
|
163
|
+
// 确保 locale 有默认值,避免 serverSideTranslations 报错
|
|
164
|
+
const currentLocale = locale || 'zh-CN'
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
props: {
|
|
168
|
+
...(await serverSideTranslations(currentLocale, ['common', 'home', 'layout'])),
|
|
169
|
+
},
|
|
170
|
+
}
|
|
156
171
|
}
|
|
157
172
|
|
|
173
|
+
Page.displayName = 'HomePage'
|
|
174
|
+
|
|
158
175
|
export default Page
|