nsgm-cli 2.1.13 → 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 +394 -156
- package/client/components/Button.tsx +3 -5
- 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/components/__tests__/Button.test.tsx +10 -10
- package/client/layout/index.tsx +153 -185
- package/client/redux/reducers.ts +1 -1
- package/client/redux/store.ts +2 -1
- package/client/redux/template/manage/actions.ts +77 -88
- package/client/redux/template/manage/reducers.ts +25 -37
- package/client/redux/template/manage/types.ts +1 -1
- package/client/service/template/manage.ts +20 -21
- package/client/styled/common.ts +12 -14
- package/client/styled/layout/index.ts +234 -120
- package/client/styled/template/manage.ts +102 -14
- package/client/utils/common.ts +23 -21
- package/client/utils/cookie.ts +18 -19
- package/client/utils/fetch.ts +64 -100
- package/client/utils/i18n.ts +68 -0
- package/client/utils/menu.tsx +42 -23
- package/client/utils/navigation.ts +58 -0
- package/client/utils/sso.ts +74 -84
- package/client/utils/suppressWarnings.ts +32 -0
- package/eslint.config.js +53 -19
- package/generation/README.md +25 -6
- package/generation/__tests__/example.test.js +41 -0
- package/generation/client/redux/reducers.ts +1 -1
- package/generation/client/utils/menu.tsx +36 -23
- package/generation/env +3 -0
- package/generation/env.example +3 -0
- package/generation/eslint.config.js +112 -0
- package/generation/gitignore +6 -1
- package/generation/jest.config.js +40 -0
- package/generation/next.config.js +7 -3
- package/generation/package.json +28 -4
- package/generation/tsconfig.json +6 -19
- package/jest.config.js +23 -6
- package/lib/args.js +9 -1
- package/lib/cli/app.d.ts +28 -0
- package/lib/cli/app.js +99 -0
- package/lib/cli/commands/build.d.ts +2 -0
- package/lib/cli/commands/build.js +29 -0
- package/lib/cli/commands/create.d.ts +2 -0
- package/lib/cli/commands/create.js +113 -0
- package/lib/cli/commands/delete.d.ts +3 -0
- package/lib/cli/commands/delete.js +151 -0
- package/lib/cli/commands/export.d.ts +2 -0
- package/lib/cli/commands/export.js +42 -0
- package/lib/cli/commands/help.d.ts +2 -0
- package/lib/cli/commands/help.js +42 -0
- package/lib/cli/commands/init.d.ts +2 -0
- package/lib/cli/commands/init.js +115 -0
- package/lib/cli/commands/server.d.ts +3 -0
- package/lib/cli/commands/server.js +26 -0
- package/lib/cli/commands/upgrade.d.ts +2 -0
- package/lib/cli/commands/upgrade.js +38 -0
- package/lib/cli/commands/version.d.ts +2 -0
- package/lib/cli/commands/version.js +24 -0
- package/lib/cli/index.d.ts +16 -0
- package/lib/cli/index.js +33 -0
- package/lib/cli/parser.d.ts +22 -0
- package/lib/cli/parser.js +115 -0
- package/lib/cli/registry.d.ts +33 -0
- package/lib/cli/registry.js +81 -0
- package/lib/cli/types/project.d.ts +10 -0
- package/lib/cli/types/project.js +2 -0
- package/lib/cli/types.d.ts +31 -0
- package/lib/cli/types.js +20 -0
- package/lib/cli/utils/console.d.ts +62 -0
- package/lib/cli/utils/console.js +148 -0
- package/lib/cli/utils/index.d.ts +2 -0
- package/lib/cli/utils/index.js +7 -0
- package/lib/cli/utils/prompt.d.ts +83 -0
- package/lib/cli/utils/prompt.js +327 -0
- package/lib/constants.d.ts +65 -0
- package/lib/constants.js +177 -0
- package/lib/generate.d.ts +25 -3
- package/lib/generate.js +98 -621
- package/lib/generate_create.d.ts +9 -0
- package/lib/generate_create.js +329 -0
- package/lib/generate_delete.d.ts +8 -0
- package/lib/generate_delete.js +233 -0
- package/lib/generate_init.d.ts +56 -0
- package/lib/generate_init.js +612 -0
- package/lib/generators/base-generator.d.ts +47 -0
- package/lib/generators/base-generator.js +92 -0
- package/lib/generators/file-generator.d.ts +48 -0
- package/lib/generators/file-generator.js +455 -0
- package/lib/generators/generator-factory.d.ts +20 -0
- package/lib/generators/generator-factory.js +25 -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 +45 -0
- package/lib/generators/page-generator.js +578 -0
- package/lib/generators/resolver-generator.d.ts +14 -0
- package/lib/generators/resolver-generator.js +342 -0
- package/lib/generators/schema-generator.d.ts +7 -0
- package/lib/generators/schema-generator.js +57 -0
- package/lib/generators/service-generator.d.ts +11 -0
- package/lib/generators/service-generator.js +233 -0
- package/lib/generators/sql-generator.d.ts +8 -0
- package/lib/generators/sql-generator.js +52 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +14 -173
- package/lib/server/csrf.js +9 -16
- package/lib/server/db.js +6 -7
- package/lib/server/graphql.js +5 -6
- package/lib/server/plugins/date.js +1 -1
- package/lib/server/utils/graphql-cache.js +3 -3
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils/project-config.d.ts +5 -0
- package/lib/utils/project-config.js +145 -0
- package/lib/utils.js +1 -1
- package/next-i18next.config.js +18 -0
- package/next.config.js +61 -18
- package/package.json +16 -8
- package/pages/_app.tsx +77 -33
- package/pages/_document.tsx +78 -21
- package/pages/_error.tsx +66 -0
- package/pages/index.tsx +109 -47
- package/pages/login.tsx +66 -41
- package/pages/template/manage.tsx +162 -151
- package/public/fonts/font-awesome.min.css +4 -0
- package/public/fonts/fontawesome-webfont.woff +0 -0
- package/public/fonts/fontawesome-webfont.woff2 +0 -0
- 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/public/slbhealthcheck.html +1 -1
- package/server/apis/template.js +0 -2
- package/server/utils/validation.js +163 -0
- package/types/i18next.d.ts +10 -0
- package/generation/eslintrc.js +0 -16
package/pages/_document.tsx
CHANGED
|
@@ -1,22 +1,85 @@
|
|
|
1
|
-
import Document, {
|
|
2
|
-
Html,
|
|
3
|
-
Head,
|
|
4
|
-
Main,
|
|
5
|
-
NextScript,
|
|
6
|
-
DocumentContext
|
|
7
|
-
} from 'next/document'
|
|
1
|
+
import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document'
|
|
8
2
|
import React from 'react'
|
|
9
3
|
import { ServerStyleSheet } from 'styled-components'
|
|
10
4
|
|
|
11
|
-
const MyDocument = () => {
|
|
5
|
+
const MyDocument = (props) => {
|
|
6
|
+
// 从 props 中获取语言信息,如果没有则默认为 zh-CN
|
|
7
|
+
const locale = props.locale || 'zh-CN'
|
|
8
|
+
|
|
12
9
|
return (
|
|
13
|
-
<Html>
|
|
10
|
+
<Html lang={locale}>
|
|
14
11
|
<title>NSGM CLI</title>
|
|
15
|
-
<meta
|
|
16
|
-
|
|
12
|
+
<meta
|
|
13
|
+
name="viewport"
|
|
14
|
+
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui"
|
|
15
|
+
/>
|
|
16
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
17
17
|
<meta charSet="utf-8" />
|
|
18
18
|
<Head>
|
|
19
|
-
|
|
19
|
+
{/* 直接使用现有的 FontAwesome CSS 文件 */}
|
|
20
|
+
<link rel="stylesheet" href="/fonts/font-awesome.min.css" />
|
|
21
|
+
|
|
22
|
+
{/* 预加载字体文件以改善性能 */}
|
|
23
|
+
<link
|
|
24
|
+
rel="preload"
|
|
25
|
+
href="/fonts/fontawesome-webfont.woff2?v=4.7.0"
|
|
26
|
+
as="font"
|
|
27
|
+
type="font/woff2"
|
|
28
|
+
crossOrigin="anonymous"
|
|
29
|
+
/>
|
|
30
|
+
<link
|
|
31
|
+
rel="preload"
|
|
32
|
+
href="/fonts/fontawesome-webfont.woff?v=4.7.0"
|
|
33
|
+
as="font"
|
|
34
|
+
type="font/woff"
|
|
35
|
+
crossOrigin="anonymous"
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
{/* 确保字体正确显示的额外样式 */}
|
|
39
|
+
<style>{`
|
|
40
|
+
.fa {
|
|
41
|
+
font-family: FontAwesome !important;
|
|
42
|
+
font-style: normal !important;
|
|
43
|
+
font-weight: normal !important;
|
|
44
|
+
text-decoration: inherit;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
-webkit-font-smoothing: antialiased;
|
|
47
|
+
-moz-osx-font-smoothing: grayscale;
|
|
48
|
+
}
|
|
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
|
+
/>
|
|
20
83
|
</Head>
|
|
21
84
|
<body>
|
|
22
85
|
<Main />
|
|
@@ -29,27 +92,21 @@ const MyDocument = () => {
|
|
|
29
92
|
// MyDocument.renderDocument = Document.renderDocument
|
|
30
93
|
|
|
31
94
|
MyDocument.getInitialProps = async (ctx: DocumentContext) => {
|
|
32
|
-
// console.log('document getInitialProps')
|
|
33
|
-
|
|
34
95
|
const sheet = new ServerStyleSheet()
|
|
35
96
|
const originalRenderPage = ctx.renderPage
|
|
36
97
|
|
|
37
98
|
try {
|
|
38
99
|
ctx.renderPage = () =>
|
|
39
100
|
originalRenderPage({
|
|
40
|
-
enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />)
|
|
101
|
+
enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
|
|
41
102
|
})
|
|
42
103
|
|
|
43
104
|
const initialProps = await Document?.getInitialProps(ctx)
|
|
44
105
|
|
|
45
106
|
return {
|
|
46
107
|
...initialProps,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{initialProps.styles}
|
|
50
|
-
{sheet.getStyleElement()}
|
|
51
|
-
</>
|
|
52
|
-
)
|
|
108
|
+
locale: ctx.locale || 'zh-CN',
|
|
109
|
+
styles: [initialProps.styles, sheet.getStyleElement()],
|
|
53
110
|
}
|
|
54
111
|
} finally {
|
|
55
112
|
sheet.seal()
|
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
|
@@ -1,104 +1,157 @@
|
|
|
1
|
-
import MarkdownIt from 'markdown-it'
|
|
2
1
|
import _ from 'lodash'
|
|
3
2
|
import { Container } from '../client/styled/common'
|
|
4
|
-
import getConfig from 'next/config'
|
|
5
3
|
import React from 'react'
|
|
6
4
|
import { Card, Typography, Divider, Row, Col, Tag } from 'antd'
|
|
7
5
|
import { CodeOutlined, BookOutlined, DatabaseOutlined, SettingOutlined } from '@ant-design/icons'
|
|
6
|
+
import { useTranslation } from 'next-i18next'
|
|
7
|
+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
|
8
8
|
|
|
9
9
|
const { Title, Paragraph, Text } = Typography
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
linkify: true,
|
|
14
|
-
typographer: true
|
|
15
|
-
})
|
|
11
|
+
const Page = () => {
|
|
12
|
+
const { t } = useTranslation(['common', 'home'])
|
|
16
13
|
|
|
17
|
-
const nextConfig = getConfig()
|
|
18
|
-
const { publicRuntimeConfig } = nextConfig
|
|
19
|
-
const { env } = publicRuntimeConfig
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const Page = ({ html }) => {
|
|
23
14
|
return (
|
|
24
15
|
<Container>
|
|
25
16
|
<Typography style={{ padding: '24px' }}>
|
|
26
|
-
<
|
|
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>
|
|
22
|
+
|
|
27
23
|
<Paragraph>
|
|
28
24
|
<Row gutter={[16, 16]}>
|
|
29
|
-
<Col
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<Col
|
|
25
|
+
<Col>
|
|
26
|
+
<Tag color="blue">Next</Tag>
|
|
27
|
+
</Col>
|
|
28
|
+
<Col>
|
|
29
|
+
<Tag color="purple">Styled-components</Tag>
|
|
30
|
+
</Col>
|
|
31
|
+
<Col>
|
|
32
|
+
<Tag color="magenta">Graphql</Tag>
|
|
33
|
+
</Col>
|
|
34
|
+
<Col>
|
|
35
|
+
<Tag color="green">Mysql</Tag>
|
|
36
|
+
</Col>
|
|
33
37
|
</Row>
|
|
34
38
|
</Paragraph>
|
|
35
|
-
<Paragraph>
|
|
36
|
-
全栈架构,代码模板生成,快速开发
|
|
37
|
-
</Paragraph>
|
|
39
|
+
<Paragraph>{t('home:page.description')}</Paragraph>
|
|
38
40
|
|
|
39
41
|
<Card style={{ marginBottom: '24px' }}>
|
|
40
42
|
<Row gutter={[24, 16]}>
|
|
41
43
|
<Col xs={24} md={8}>
|
|
42
|
-
<Card
|
|
43
|
-
|
|
44
|
+
<Card
|
|
45
|
+
type="inner"
|
|
46
|
+
title={
|
|
47
|
+
<>
|
|
48
|
+
<DatabaseOutlined /> {t('home:page.sections.database.title')}
|
|
49
|
+
</>
|
|
50
|
+
}
|
|
51
|
+
>
|
|
52
|
+
{t('home:page.sections.database.description')}
|
|
44
53
|
</Card>
|
|
45
54
|
</Col>
|
|
46
55
|
<Col xs={24} md={8}>
|
|
47
|
-
<Card
|
|
48
|
-
|
|
56
|
+
<Card
|
|
57
|
+
type="inner"
|
|
58
|
+
title={
|
|
59
|
+
<>
|
|
60
|
+
<SettingOutlined /> {t('home:page.sections.project.title')}
|
|
61
|
+
</>
|
|
62
|
+
}
|
|
63
|
+
>
|
|
64
|
+
{t('home:page.sections.project.description')}
|
|
49
65
|
</Card>
|
|
50
66
|
</Col>
|
|
51
67
|
<Col xs={24} md={8}>
|
|
52
|
-
<Card
|
|
53
|
-
|
|
68
|
+
<Card
|
|
69
|
+
type="inner"
|
|
70
|
+
title={
|
|
71
|
+
<>
|
|
72
|
+
<CodeOutlined /> {t('home:page.sections.framework.title')}
|
|
73
|
+
</>
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
{t('home:page.sections.framework.description')}
|
|
54
77
|
</Card>
|
|
55
78
|
</Col>
|
|
56
79
|
</Row>
|
|
57
80
|
</Card>
|
|
58
81
|
|
|
59
|
-
<Title level={2}
|
|
82
|
+
<Title level={2}>
|
|
83
|
+
<BookOutlined /> {t('home:page.commands.title')}
|
|
84
|
+
</Title>
|
|
60
85
|
<Divider />
|
|
61
86
|
|
|
62
87
|
<Row gutter={[16, 16]}>
|
|
63
88
|
<Col xs={24} md={8}>
|
|
64
89
|
<Card hoverable>
|
|
65
|
-
<Title level={4}
|
|
90
|
+
<Title level={4}>{t('home:page.commands.categories.projectManagement.title')}</Title>
|
|
66
91
|
<ul>
|
|
67
|
-
<li
|
|
68
|
-
|
|
92
|
+
<li>
|
|
93
|
+
<Text strong>nsgm init</Text> - {t('home:page.commands.categories.projectManagement.items.init')}
|
|
94
|
+
</li>
|
|
95
|
+
<li>
|
|
96
|
+
<Text strong>nsgm upgrade</Text> -{' '}
|
|
97
|
+
{t('home:page.commands.categories.projectManagement.items.upgrade')}
|
|
98
|
+
</li>
|
|
69
99
|
</ul>
|
|
70
100
|
</Card>
|
|
71
101
|
</Col>
|
|
72
102
|
<Col xs={24} md={8}>
|
|
73
103
|
<Card hoverable>
|
|
74
|
-
<Title level={4}
|
|
104
|
+
<Title level={4}>{t('home:page.commands.categories.templateOperations.title')}</Title>
|
|
75
105
|
<ul>
|
|
76
|
-
<li
|
|
77
|
-
|
|
78
|
-
|
|
106
|
+
<li>
|
|
107
|
+
<Text strong>nsgm create</Text> - {t('home:page.commands.categories.templateOperations.items.create')}
|
|
108
|
+
</li>
|
|
109
|
+
<li>
|
|
110
|
+
<Text strong>nsgm delete</Text> - {t('home:page.commands.categories.templateOperations.items.delete')}
|
|
111
|
+
</li>
|
|
112
|
+
<li>
|
|
113
|
+
<Text strong>nsgm deletedb</Text> -{' '}
|
|
114
|
+
{t('home:page.commands.categories.templateOperations.items.deletedb')}
|
|
115
|
+
</li>
|
|
79
116
|
</ul>
|
|
80
117
|
</Card>
|
|
81
118
|
</Col>
|
|
82
119
|
<Col xs={24} md={8}>
|
|
83
120
|
<Card hoverable>
|
|
84
|
-
<Title level={4}
|
|
121
|
+
<Title level={4}>{t('home:page.commands.categories.runBuild.title')}</Title>
|
|
85
122
|
<ul>
|
|
86
|
-
<li
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
<li
|
|
123
|
+
<li>
|
|
124
|
+
<Text strong>nsgm dev</Text> - {t('home:page.commands.categories.runBuild.items.dev')}
|
|
125
|
+
</li>
|
|
126
|
+
<li>
|
|
127
|
+
<Text strong>nsgm start</Text> - {t('home:page.commands.categories.runBuild.items.start')}
|
|
128
|
+
</li>
|
|
129
|
+
<li>
|
|
130
|
+
<Text strong>nsgm build</Text> - {t('home:page.commands.categories.runBuild.items.build')}
|
|
131
|
+
</li>
|
|
132
|
+
<li>
|
|
133
|
+
<Text strong>nsgm export</Text> - {t('home:page.commands.categories.runBuild.items.export')}
|
|
134
|
+
</li>
|
|
90
135
|
</ul>
|
|
91
136
|
</Card>
|
|
92
137
|
</Col>
|
|
93
138
|
</Row>
|
|
94
139
|
|
|
95
|
-
<Title level={2} style={{ marginTop: '24px' }}
|
|
140
|
+
<Title level={2} style={{ marginTop: '24px' }}>
|
|
141
|
+
{t('home:page.parameters.title')}
|
|
142
|
+
</Title>
|
|
96
143
|
<Divider />
|
|
97
144
|
<Card>
|
|
98
145
|
<ul>
|
|
99
|
-
<li
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
<li>
|
|
147
|
+
<Text strong>dictionary:</Text> {t('home:page.parameters.items.dictionary')}
|
|
148
|
+
</li>
|
|
149
|
+
<li>
|
|
150
|
+
<Text strong>controller:</Text> {t('home:page.parameters.items.controller')}
|
|
151
|
+
</li>
|
|
152
|
+
<li>
|
|
153
|
+
<Text strong>action:</Text> {t('home:page.parameters.items.action')}
|
|
154
|
+
</li>
|
|
102
155
|
</ul>
|
|
103
156
|
</Card>
|
|
104
157
|
</Typography>
|
|
@@ -106,8 +159,17 @@ const Page = ({ html }) => {
|
|
|
106
159
|
)
|
|
107
160
|
}
|
|
108
161
|
|
|
109
|
-
|
|
110
|
-
|
|
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
|
+
}
|
|
111
171
|
}
|
|
112
172
|
|
|
113
|
-
|
|
173
|
+
Page.displayName = 'HomePage'
|
|
174
|
+
|
|
175
|
+
export default Page
|
package/pages/login.tsx
CHANGED
|
@@ -2,15 +2,20 @@ import MarkdownIt from 'markdown-it'
|
|
|
2
2
|
import _ from 'lodash'
|
|
3
3
|
import { LoginContainer } from '../client/styled/common'
|
|
4
4
|
// import getConfig from 'next/config'
|
|
5
|
-
import React, { useState } from 'react'
|
|
5
|
+
import React, { useState, useEffect } from 'react'
|
|
6
6
|
import { Input, Button, Form, Typography, message } from 'antd'
|
|
7
7
|
import { UserOutlined, LockOutlined } from '@ant-design/icons'
|
|
8
8
|
import { directLogin } from '../client/utils/sso'
|
|
9
|
+
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
|
10
|
+
import { useTranslation } from 'next-i18next'
|
|
11
|
+
import { useRouter } from 'next/router'
|
|
12
|
+
import LanguageSwitcher from '@/components/LanguageSwitcher'
|
|
13
|
+
import { navigateToHome } from '@/utils/navigation'
|
|
9
14
|
|
|
10
15
|
const md = new MarkdownIt({
|
|
11
16
|
html: true,
|
|
12
17
|
linkify: true,
|
|
13
|
-
typographer: true
|
|
18
|
+
typographer: true,
|
|
14
19
|
})
|
|
15
20
|
|
|
16
21
|
// const nextConfig = getConfig()
|
|
@@ -19,48 +24,56 @@ const md = new MarkdownIt({
|
|
|
19
24
|
|
|
20
25
|
const renderArr: any = []
|
|
21
26
|
|
|
22
|
-
renderArr.push('
|
|
27
|
+
renderArr.push('NSGM')
|
|
23
28
|
|
|
24
29
|
const Page = ({ html }) => {
|
|
25
|
-
const
|
|
26
|
-
const
|
|
30
|
+
const { t } = useTranslation(['login'])
|
|
31
|
+
const router = useRouter()
|
|
32
|
+
const [userName, setUserName] = useState('')
|
|
33
|
+
const [userPassword, setUserPassword] = useState('')
|
|
34
|
+
const [mounted, setMounted] = useState(false)
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
setMounted(true)
|
|
38
|
+
}, [])
|
|
27
39
|
|
|
28
40
|
const createMarkup = () => {
|
|
29
41
|
return {
|
|
30
|
-
__html: html
|
|
42
|
+
__html: html,
|
|
31
43
|
}
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
const doLogin = () => {
|
|
35
|
-
if (typeof window
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
if (!mounted || typeof window === 'undefined') return
|
|
48
|
+
|
|
49
|
+
if (userName === '') {
|
|
50
|
+
message.error(t('login:login.errors.usernameRequired'))
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if (userPassword === '') {
|
|
54
|
+
message.error(t('login:login.errors.passwordRequired'))
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const result = directLogin(userName, userPassword, (user) => {
|
|
59
|
+
if (user && mounted) {
|
|
60
|
+
// 跳转到首页,保持当前语言设置,强制添加语言前缀避免自动检测
|
|
61
|
+
navigateToHome(router, true)
|
|
43
62
|
}
|
|
63
|
+
})
|
|
44
64
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// 检查是否是 Promise
|
|
52
|
-
if (result && typeof (result as any).then === 'function') {
|
|
53
|
-
(result as Promise<any>).then(loginResult => {
|
|
54
|
-
if (!loginResult.success) {
|
|
55
|
-
message.error(loginResult.message);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
} else {
|
|
59
|
-
// 直接返回的结果
|
|
60
|
-
const syncResult = result as { success: boolean; message?: string };
|
|
61
|
-
if (!syncResult.success) {
|
|
62
|
-
message.error(syncResult.message || '登录失败');
|
|
65
|
+
// 检查是否是 Promise
|
|
66
|
+
if (result && typeof (result as any).then === 'function') {
|
|
67
|
+
;(result as Promise<any>).then((loginResult) => {
|
|
68
|
+
if (!loginResult.success) {
|
|
69
|
+
message.error(loginResult.message)
|
|
63
70
|
}
|
|
71
|
+
})
|
|
72
|
+
} else {
|
|
73
|
+
// 直接返回的结果
|
|
74
|
+
const syncResult = result as { success: boolean; message?: string }
|
|
75
|
+
if (!syncResult.success) {
|
|
76
|
+
message.error(syncResult.message || t('login:login.errors.loginFailed'))
|
|
64
77
|
}
|
|
65
78
|
}
|
|
66
79
|
}
|
|
@@ -75,13 +88,18 @@ const Page = ({ html }) => {
|
|
|
75
88
|
|
|
76
89
|
return (
|
|
77
90
|
<LoginContainer>
|
|
91
|
+
<div style={{ position: 'absolute', top: '20px', right: '20px' }}>
|
|
92
|
+
<LanguageSwitcher />
|
|
93
|
+
</div>
|
|
78
94
|
<div dangerouslySetInnerHTML={createMarkup()} />
|
|
79
|
-
<Typography.Title level={3} style={{ textAlign: 'center', marginBottom: 24 }}
|
|
95
|
+
<Typography.Title level={3} style={{ textAlign: 'center', marginBottom: 24 }}>
|
|
96
|
+
{t('login:login.title')}
|
|
97
|
+
</Typography.Title>
|
|
80
98
|
<Form layout="vertical" style={{ width: '100%' }}>
|
|
81
99
|
<Form.Item>
|
|
82
100
|
<Input
|
|
83
101
|
prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
|
|
84
|
-
placeholder=
|
|
102
|
+
placeholder={t('login:login.username')}
|
|
85
103
|
size="large"
|
|
86
104
|
value={userName}
|
|
87
105
|
onChange={doChangeName}
|
|
@@ -91,7 +109,7 @@ const Page = ({ html }) => {
|
|
|
91
109
|
<Form.Item>
|
|
92
110
|
<Input.Password
|
|
93
111
|
prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
|
|
94
|
-
placeholder=
|
|
112
|
+
placeholder={t('login:login.password')}
|
|
95
113
|
size="large"
|
|
96
114
|
value={userPassword}
|
|
97
115
|
onChange={doChangePassword}
|
|
@@ -100,7 +118,7 @@ const Page = ({ html }) => {
|
|
|
100
118
|
</Form.Item>
|
|
101
119
|
<Form.Item>
|
|
102
120
|
<Button type="primary" onClick={doLogin} size="large" block>
|
|
103
|
-
|
|
121
|
+
{t('login:login.loginButton')}
|
|
104
122
|
</Button>
|
|
105
123
|
</Form.Item>
|
|
106
124
|
</Form>
|
|
@@ -108,17 +126,24 @@ const Page = ({ html }) => {
|
|
|
108
126
|
)
|
|
109
127
|
}
|
|
110
128
|
|
|
111
|
-
|
|
129
|
+
export const getServerSideProps = async ({ locale }) => {
|
|
130
|
+
// 确保 locale 有默认值,避免 serverSideTranslations 报错
|
|
131
|
+
const currentLocale = locale || 'zh-CN'
|
|
132
|
+
|
|
133
|
+
// 处理 markdown 内容
|
|
112
134
|
let html = ''
|
|
113
135
|
_.each(renderArr, (item) => {
|
|
114
136
|
html += md.render(item)
|
|
115
137
|
})
|
|
116
138
|
|
|
117
|
-
console.log("Generated HTML:", html);
|
|
118
|
-
|
|
119
139
|
return {
|
|
120
|
-
|
|
140
|
+
props: {
|
|
141
|
+
html,
|
|
142
|
+
...(await serverSideTranslations(currentLocale, ['common', 'layout', 'login'])),
|
|
143
|
+
},
|
|
121
144
|
}
|
|
122
145
|
}
|
|
123
146
|
|
|
124
|
-
|
|
147
|
+
Page.displayName = 'LoginPage'
|
|
148
|
+
|
|
149
|
+
export default Page
|