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
package/pages/login.tsx
CHANGED
|
@@ -2,10 +2,15 @@ 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,
|
|
@@ -19,11 +24,18 @@ 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 }) => {
|
|
30
|
+
const { t } = useTranslation(['login'])
|
|
31
|
+
const router = useRouter()
|
|
25
32
|
const [userName, setUserName] = useState('')
|
|
26
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 {
|
|
@@ -32,35 +44,36 @@ const Page = ({ html }) => {
|
|
|
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
|
-
|
|
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)
|
|
48
70
|
}
|
|
49
71
|
})
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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 || '登录失败')
|
|
63
|
-
}
|
|
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,15 +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
95
|
<Typography.Title level={3} style={{ textAlign: 'center', marginBottom: 24 }}>
|
|
80
|
-
|
|
96
|
+
{t('login:login.title')}
|
|
81
97
|
</Typography.Title>
|
|
82
98
|
<Form layout="vertical" style={{ width: '100%' }}>
|
|
83
99
|
<Form.Item>
|
|
84
100
|
<Input
|
|
85
101
|
prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
|
|
86
|
-
placeholder=
|
|
102
|
+
placeholder={t('login:login.username')}
|
|
87
103
|
size="large"
|
|
88
104
|
value={userName}
|
|
89
105
|
onChange={doChangeName}
|
|
@@ -93,7 +109,7 @@ const Page = ({ html }) => {
|
|
|
93
109
|
<Form.Item>
|
|
94
110
|
<Input.Password
|
|
95
111
|
prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
|
|
96
|
-
placeholder=
|
|
112
|
+
placeholder={t('login:login.password')}
|
|
97
113
|
size="large"
|
|
98
114
|
value={userPassword}
|
|
99
115
|
onChange={doChangePassword}
|
|
@@ -102,7 +118,7 @@ const Page = ({ html }) => {
|
|
|
102
118
|
</Form.Item>
|
|
103
119
|
<Form.Item>
|
|
104
120
|
<Button type="primary" onClick={doLogin} size="large" block>
|
|
105
|
-
|
|
121
|
+
{t('login:login.loginButton')}
|
|
106
122
|
</Button>
|
|
107
123
|
</Form.Item>
|
|
108
124
|
</Form>
|
|
@@ -110,15 +126,24 @@ const Page = ({ html }) => {
|
|
|
110
126
|
)
|
|
111
127
|
}
|
|
112
128
|
|
|
113
|
-
|
|
129
|
+
export const getServerSideProps = async ({ locale }) => {
|
|
130
|
+
// 确保 locale 有默认值,避免 serverSideTranslations 报错
|
|
131
|
+
const currentLocale = locale || 'zh-CN'
|
|
132
|
+
|
|
133
|
+
// 处理 markdown 内容
|
|
114
134
|
let html = ''
|
|
115
135
|
_.each(renderArr, (item) => {
|
|
116
136
|
html += md.render(item)
|
|
117
137
|
})
|
|
118
138
|
|
|
119
139
|
return {
|
|
120
|
-
|
|
140
|
+
props: {
|
|
141
|
+
html,
|
|
142
|
+
...(await serverSideTranslations(currentLocale, ['common', 'layout', 'login'])),
|
|
143
|
+
},
|
|
121
144
|
}
|
|
122
145
|
}
|
|
123
146
|
|
|
147
|
+
Page.displayName = 'LoginPage'
|
|
148
|
+
|
|
124
149
|
export default Page
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
|
-
import { ConfigProvider,
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { ConfigProvider, Modal, Space, Upload, message } from 'antd'
|
|
3
|
+
import {
|
|
4
|
+
Container,
|
|
5
|
+
SearchRow,
|
|
6
|
+
ModalContainer,
|
|
7
|
+
StyledButton,
|
|
8
|
+
StyledInput,
|
|
9
|
+
StyledTable,
|
|
10
|
+
ModalTitle,
|
|
11
|
+
ModalInput,
|
|
12
|
+
IconWrapper,
|
|
13
|
+
RoundedButton,
|
|
14
|
+
GlobalStyle,
|
|
15
|
+
} from '@/styled/template/manage'
|
|
5
16
|
import { useDispatch, useSelector } from 'react-redux'
|
|
6
17
|
import {
|
|
7
18
|
addTemplate,
|
|
@@ -14,7 +25,9 @@ import {
|
|
|
14
25
|
import { getTemplateService } from '@/service/template/manage'
|
|
15
26
|
import { RootState, AppDispatch } from '@/redux/store'
|
|
16
27
|
import _ from 'lodash'
|
|
17
|
-
import
|
|
28
|
+
import { useTranslation } from 'next-i18next'
|
|
29
|
+
import { getAntdLocale } from '@/utils/i18n'
|
|
30
|
+
import { useRouter } from 'next/router'
|
|
18
31
|
import { handleXSS, checkModalObj } from '@/utils/common'
|
|
19
32
|
import { UploadOutlined } from '@ant-design/icons'
|
|
20
33
|
import ExcelJS from 'exceljs'
|
|
@@ -23,78 +36,10 @@ import { createCSRFUploadProps } from '@/utils/fetch'
|
|
|
23
36
|
|
|
24
37
|
const pageSize = 100
|
|
25
38
|
|
|
26
|
-
const keyTitles = {
|
|
27
|
-
name: '名称',
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// styled-components
|
|
31
|
-
const StyledButton = styled(Button)<{ $primary?: boolean; $export?: boolean; $import?: boolean; $danger?: boolean }>`
|
|
32
|
-
display: flex;
|
|
33
|
-
align-items: center;
|
|
34
|
-
border-radius: 6px;
|
|
35
|
-
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
|
|
36
|
-
${(props) =>
|
|
37
|
-
props.$export &&
|
|
38
|
-
`
|
|
39
|
-
background-color: #f6ffed;
|
|
40
|
-
color: #52c41a;
|
|
41
|
-
border-color: #b7eb8f;
|
|
42
|
-
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
|
43
|
-
transition: all 0.3s ease;
|
|
44
|
-
`}
|
|
45
|
-
${(props) =>
|
|
46
|
-
props.$import &&
|
|
47
|
-
`
|
|
48
|
-
background-color: #e6f7ff;
|
|
49
|
-
color: #1890ff;
|
|
50
|
-
border-color: #91d5ff;
|
|
51
|
-
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
|
52
|
-
transition: all 0.3s ease;
|
|
53
|
-
`}
|
|
54
|
-
${(props) =>
|
|
55
|
-
props.$danger &&
|
|
56
|
-
`
|
|
57
|
-
background-color: #fff1f0;
|
|
58
|
-
border-color: #ffa39e;
|
|
59
|
-
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
|
60
|
-
transition: all 0.3s ease;
|
|
61
|
-
`}
|
|
62
|
-
`
|
|
63
|
-
const StyledInput = styled(Input)`
|
|
64
|
-
width: 200px;
|
|
65
|
-
border-radius: 6px;
|
|
66
|
-
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
|
|
67
|
-
`
|
|
68
|
-
const StyledTable = styled(Table)`
|
|
69
|
-
margin-top: 16px;
|
|
70
|
-
border-radius: 8px;
|
|
71
|
-
overflow: hidden;
|
|
72
|
-
|
|
73
|
-
.styled-pagination {
|
|
74
|
-
margin-top: 16px;
|
|
75
|
-
margin-bottom: 16px;
|
|
76
|
-
}
|
|
77
|
-
`
|
|
78
|
-
const ModalTitle = styled.div`
|
|
79
|
-
color: #1890ff;
|
|
80
|
-
font-weight: 500;
|
|
81
|
-
`
|
|
82
|
-
const ModalInput = styled(Input)`
|
|
83
|
-
border-radius: 4px;
|
|
84
|
-
`
|
|
85
|
-
const IconWrapper = styled.i`
|
|
86
|
-
margin-right: 5px;
|
|
87
|
-
`
|
|
88
|
-
const RoundedButton = styled(Button)`
|
|
89
|
-
border-radius: 4px;
|
|
90
|
-
`
|
|
91
|
-
const GlobalStyle = styled.div`
|
|
92
|
-
.rounded-button {
|
|
93
|
-
border-radius: 4px;
|
|
94
|
-
}
|
|
95
|
-
`
|
|
96
|
-
|
|
97
39
|
const Page = ({ template }) => {
|
|
40
|
+
const { t } = useTranslation(['common', 'template'])
|
|
41
|
+
const router = useRouter()
|
|
42
|
+
const antdLocale = getAntdLocale(router.locale || 'zh-CN')
|
|
98
43
|
const dispatch = useDispatch<AppDispatch>()
|
|
99
44
|
const [isModalVisiable, setIsModalVisible] = useState(false)
|
|
100
45
|
const [modalId, setModalId] = useState(0)
|
|
@@ -102,10 +47,39 @@ const Page = ({ template }) => {
|
|
|
102
47
|
const [searchName, setSearchName] = useState('')
|
|
103
48
|
const [batchDelIds, setBatchDelIds] = useState([])
|
|
104
49
|
|
|
50
|
+
const keyTitles = {
|
|
51
|
+
name: t('template:template.fields.name'),
|
|
52
|
+
}
|
|
53
|
+
|
|
105
54
|
useEffect(() => {
|
|
106
55
|
dispatch(updateSSRTemplate(template))
|
|
107
56
|
}, [dispatch])
|
|
108
57
|
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
// 管理弹窗打开时的滚动条显示
|
|
60
|
+
if (isModalVisiable) {
|
|
61
|
+
// 记录原始样式
|
|
62
|
+
const originalStyle = window.getComputedStyle(document.body).overflow
|
|
63
|
+
const originalPaddingRight = window.getComputedStyle(document.body).paddingRight
|
|
64
|
+
|
|
65
|
+
// 设置定时器,在 Modal 设置样式后覆盖
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
document.body.style.overflow = 'auto'
|
|
68
|
+
document.body.style.paddingRight = '0px'
|
|
69
|
+
}, 0)
|
|
70
|
+
|
|
71
|
+
return () => {
|
|
72
|
+
clearTimeout(timer)
|
|
73
|
+
// 清理时恢复原始样式
|
|
74
|
+
document.body.style.overflow = originalStyle
|
|
75
|
+
document.body.style.paddingRight = originalPaddingRight
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 当弹窗关闭时,不需要清理函数
|
|
80
|
+
return undefined
|
|
81
|
+
}, [isModalVisiable])
|
|
82
|
+
|
|
109
83
|
const templateManage = useSelector((state: RootState) => state.templateManage)
|
|
110
84
|
|
|
111
85
|
if (!templateManage.firstLoadFlag) {
|
|
@@ -122,7 +96,7 @@ const Page = ({ template }) => {
|
|
|
122
96
|
const dataSource = templateItems
|
|
123
97
|
const columns: any = [
|
|
124
98
|
{
|
|
125
|
-
title: '
|
|
99
|
+
title: t('template:template.fields.id'),
|
|
126
100
|
dataIndex: 'id',
|
|
127
101
|
key: 'id',
|
|
128
102
|
sorter: (a: any, b: any) => a.id - b.id,
|
|
@@ -132,7 +106,7 @@ const Page = ({ template }) => {
|
|
|
132
106
|
align: 'center',
|
|
133
107
|
},
|
|
134
108
|
{
|
|
135
|
-
title:
|
|
109
|
+
title: t('template:template.fields.name'),
|
|
136
110
|
dataIndex: 'name',
|
|
137
111
|
key: 'name',
|
|
138
112
|
sorter: (a: any, b: any) => a.name.length - b.name.length,
|
|
@@ -142,7 +116,7 @@ const Page = ({ template }) => {
|
|
|
142
116
|
ellipsis: true,
|
|
143
117
|
},
|
|
144
118
|
{
|
|
145
|
-
title: '
|
|
119
|
+
title: t('template:template.fields.actions'),
|
|
146
120
|
dataIndex: '',
|
|
147
121
|
width: '25%',
|
|
148
122
|
align: 'center',
|
|
@@ -156,7 +130,7 @@ const Page = ({ template }) => {
|
|
|
156
130
|
updateTemplate(record)
|
|
157
131
|
}}
|
|
158
132
|
>
|
|
159
|
-
|
|
133
|
+
{t('template:template.buttons.edit')}
|
|
160
134
|
</RoundedButton>
|
|
161
135
|
<RoundedButton
|
|
162
136
|
danger
|
|
@@ -166,7 +140,7 @@ const Page = ({ template }) => {
|
|
|
166
140
|
deleteTemplate(id)
|
|
167
141
|
}}
|
|
168
142
|
>
|
|
169
|
-
|
|
143
|
+
{t('template:template.buttons.delete')}
|
|
170
144
|
</RoundedButton>
|
|
171
145
|
</Space>
|
|
172
146
|
)
|
|
@@ -197,10 +171,10 @@ const Page = ({ template }) => {
|
|
|
197
171
|
|
|
198
172
|
const deleteTemplate = (id: number) => {
|
|
199
173
|
Modal.confirm({
|
|
200
|
-
title: '
|
|
201
|
-
content: '
|
|
202
|
-
okText: '
|
|
203
|
-
cancelText: '
|
|
174
|
+
title: t('common:common.warning'),
|
|
175
|
+
content: t('template:template.messages.confirmDelete'),
|
|
176
|
+
okText: t('template:template.buttons.confirm'),
|
|
177
|
+
cancelText: t('template:template.buttons.cancel'),
|
|
204
178
|
onOk: () => {
|
|
205
179
|
dispatch(delTemplate(id))
|
|
206
180
|
Modal.destroyAll()
|
|
@@ -284,18 +258,18 @@ const Page = ({ template }) => {
|
|
|
284
258
|
// 导出失败
|
|
285
259
|
})
|
|
286
260
|
} else {
|
|
287
|
-
message.info('
|
|
261
|
+
message.info(t('template:template.messages.noData'))
|
|
288
262
|
}
|
|
289
263
|
}
|
|
290
264
|
|
|
291
265
|
const uploadProps = createCSRFUploadProps('/rest/template/import', {
|
|
292
266
|
name: 'file',
|
|
293
267
|
onSuccess: (fileName) => {
|
|
294
|
-
message.success(`${fileName}
|
|
268
|
+
message.success(`${fileName} ${t('template:template.messages.uploadSuccess')}`)
|
|
295
269
|
window.location.reload()
|
|
296
270
|
},
|
|
297
271
|
onError: (fileName) => {
|
|
298
|
-
message.error(`${fileName}
|
|
272
|
+
message.error(`${fileName} ${t('template:template.messages.uploadFailed')}`)
|
|
299
273
|
},
|
|
300
274
|
beforeUpload: (file) => {
|
|
301
275
|
// 可以在这里添加文件类型、大小等验证
|
|
@@ -303,12 +277,12 @@ const Page = ({ template }) => {
|
|
|
303
277
|
file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
|
|
304
278
|
file.type === 'application/vnd.ms-excel'
|
|
305
279
|
if (!isExcel) {
|
|
306
|
-
message.error('
|
|
280
|
+
message.error(t('template:template.messages.onlyExcel'))
|
|
307
281
|
return false
|
|
308
282
|
}
|
|
309
283
|
const isLt2M = file.size / 1024 / 1024 < 2
|
|
310
284
|
if (!isLt2M) {
|
|
311
|
-
message.error('
|
|
285
|
+
message.error(t('template:template.messages.fileSizeLimit'))
|
|
312
286
|
return false
|
|
313
287
|
}
|
|
314
288
|
return true
|
|
@@ -318,55 +292,55 @@ const Page = ({ template }) => {
|
|
|
318
292
|
const batchDeleteTemplate = () => {
|
|
319
293
|
if (batchDelIds.length > 0) {
|
|
320
294
|
Modal.confirm({
|
|
321
|
-
title: '
|
|
322
|
-
content: '
|
|
323
|
-
okText: '
|
|
324
|
-
cancelText: '
|
|
295
|
+
title: t('common:common.warning'),
|
|
296
|
+
content: t('template:template.messages.confirmBatchDelete'),
|
|
297
|
+
okText: t('template:template.buttons.confirm'),
|
|
298
|
+
cancelText: t('template:template.buttons.cancel'),
|
|
325
299
|
onOk: () => {
|
|
326
300
|
dispatch(batchDelTemplate(batchDelIds))
|
|
327
301
|
Modal.destroyAll()
|
|
328
302
|
},
|
|
329
303
|
})
|
|
330
304
|
} else {
|
|
331
|
-
message.info('
|
|
305
|
+
message.info(t('template:template.messages.noDataBatchDelete'))
|
|
332
306
|
}
|
|
333
307
|
}
|
|
334
308
|
|
|
335
309
|
return (
|
|
336
310
|
<Container>
|
|
337
311
|
<GlobalStyle />
|
|
338
|
-
<div className="page-title">
|
|
339
|
-
<ConfigProvider locale={
|
|
312
|
+
<div className="page-title">{t('template:template.title')}</div>
|
|
313
|
+
<ConfigProvider locale={antdLocale}>
|
|
340
314
|
<SearchRow>
|
|
341
315
|
<Space size="middle" wrap>
|
|
342
316
|
<Space size="small">
|
|
343
317
|
<StyledButton type="primary" onClick={createTemplate} $primary>
|
|
344
318
|
<IconWrapper className="fa fa-plus"></IconWrapper>
|
|
345
|
-
|
|
319
|
+
{t('template:template.buttons.add')}
|
|
346
320
|
</StyledButton>
|
|
347
321
|
<StyledInput
|
|
348
322
|
value={searchName}
|
|
349
|
-
placeholder=
|
|
323
|
+
placeholder={t('template:template.placeholders.enterName')}
|
|
350
324
|
allowClear
|
|
351
325
|
onChange={(e) => setSearchName(e.target.value)}
|
|
352
326
|
onPressEnter={doSearch}
|
|
353
327
|
/>
|
|
354
328
|
<StyledButton type="primary" onClick={doSearch} $primary>
|
|
355
329
|
<IconWrapper className="fa fa-search"></IconWrapper>
|
|
356
|
-
|
|
330
|
+
{t('template:template.buttons.search')}
|
|
357
331
|
</StyledButton>
|
|
358
332
|
</Space>
|
|
359
333
|
<Space size="small">
|
|
360
334
|
<StyledButton onClick={exportTemplate} icon={<UploadOutlined rotate={180} />} $export>
|
|
361
|
-
|
|
335
|
+
{t('template:template.buttons.export')}
|
|
362
336
|
</StyledButton>
|
|
363
337
|
<Upload {...uploadProps}>
|
|
364
338
|
<StyledButton icon={<UploadOutlined />} $import>
|
|
365
|
-
|
|
339
|
+
{t('template:template.buttons.import')}
|
|
366
340
|
</StyledButton>
|
|
367
341
|
</Upload>
|
|
368
342
|
<StyledButton danger onClick={batchDeleteTemplate} $danger>
|
|
369
|
-
|
|
343
|
+
{t('template:template.buttons.batchDelete')}
|
|
370
344
|
</StyledButton>
|
|
371
345
|
</Space>
|
|
372
346
|
</Space>
|
|
@@ -385,7 +359,7 @@ const Page = ({ template }) => {
|
|
|
385
359
|
pageSize: pageSize,
|
|
386
360
|
showSizeChanger: false,
|
|
387
361
|
showQuickJumper: true,
|
|
388
|
-
showTotal: (total) =>
|
|
362
|
+
showTotal: (total) => t('template:template.pagination.total', { total }),
|
|
389
363
|
onChange: (page, pageSize) => {
|
|
390
364
|
dispatch(searchTemplate(page - 1, pageSize, { name: handleXSS(searchName) }))
|
|
391
365
|
},
|
|
@@ -393,12 +367,16 @@ const Page = ({ template }) => {
|
|
|
393
367
|
}}
|
|
394
368
|
/>
|
|
395
369
|
<Modal
|
|
396
|
-
title={
|
|
370
|
+
title={
|
|
371
|
+
<ModalTitle>
|
|
372
|
+
{modalId == 0 ? t('template:template.modal.addTitle') : t('template:template.modal.editTitle')}
|
|
373
|
+
</ModalTitle>
|
|
374
|
+
}
|
|
397
375
|
open={isModalVisiable}
|
|
398
376
|
onOk={handleOk}
|
|
399
377
|
onCancel={handleCancel}
|
|
400
|
-
okText=
|
|
401
|
-
cancelText=
|
|
378
|
+
okText={t('template:template.buttons.confirm')}
|
|
379
|
+
cancelText={t('template:template.buttons.cancel')}
|
|
402
380
|
centered
|
|
403
381
|
maskClosable={false}
|
|
404
382
|
destroyOnHidden
|
|
@@ -410,7 +388,7 @@ const Page = ({ template }) => {
|
|
|
410
388
|
<label>{keyTitles.name}:</label>
|
|
411
389
|
<ModalInput
|
|
412
390
|
value={modalName}
|
|
413
|
-
placeholder=
|
|
391
|
+
placeholder={t('template:template.placeholders.inputName')}
|
|
414
392
|
allowClear
|
|
415
393
|
autoFocus
|
|
416
394
|
onChange={(e) => setModalName(e.target.value)}
|
|
@@ -423,7 +401,9 @@ const Page = ({ template }) => {
|
|
|
423
401
|
)
|
|
424
402
|
}
|
|
425
403
|
|
|
426
|
-
|
|
404
|
+
export async function getServerSideProps(context) {
|
|
405
|
+
const { serverSideTranslations } = await import('next-i18next/serverSideTranslations')
|
|
406
|
+
|
|
427
407
|
let template = null
|
|
428
408
|
|
|
429
409
|
await getTemplateService(0, pageSize).then((res: any) => {
|
|
@@ -431,8 +411,14 @@ Page.getInitialProps = async () => {
|
|
|
431
411
|
template = data.template
|
|
432
412
|
})
|
|
433
413
|
|
|
414
|
+
const { locale } = context
|
|
415
|
+
const translations = await serverSideTranslations(locale || 'zh-CN', ['common', 'template', 'layout', 'login'])
|
|
416
|
+
|
|
434
417
|
return {
|
|
435
|
-
|
|
418
|
+
props: {
|
|
419
|
+
template,
|
|
420
|
+
...translations,
|
|
421
|
+
},
|
|
436
422
|
}
|
|
437
423
|
}
|
|
438
424
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"common": {
|
|
3
|
+
"confirm": "Confirm",
|
|
4
|
+
"cancel": "Cancel",
|
|
5
|
+
"save": "Save",
|
|
6
|
+
"edit": "Edit",
|
|
7
|
+
"delete": "Delete",
|
|
8
|
+
"add": "Add",
|
|
9
|
+
"search": "Search",
|
|
10
|
+
"reset": "Reset",
|
|
11
|
+
"submit": "Submit",
|
|
12
|
+
"back": "Back",
|
|
13
|
+
"next": "Next",
|
|
14
|
+
"previous": "Previous",
|
|
15
|
+
"loading": "Loading...",
|
|
16
|
+
"success": "Success",
|
|
17
|
+
"error": "Error",
|
|
18
|
+
"warning": "Warning",
|
|
19
|
+
"info": "Info",
|
|
20
|
+
"yes": "Yes",
|
|
21
|
+
"no": "No",
|
|
22
|
+
"close": "Close",
|
|
23
|
+
"refresh": "Refresh"
|
|
24
|
+
},
|
|
25
|
+
"navigation": {
|
|
26
|
+
"home": "Home",
|
|
27
|
+
"dashboard": "Dashboard",
|
|
28
|
+
"settings": "Settings",
|
|
29
|
+
"profile": "Profile",
|
|
30
|
+
"logout": "Logout"
|
|
31
|
+
},
|
|
32
|
+
"form": {
|
|
33
|
+
"required": "This field is required",
|
|
34
|
+
"invalidEmail": "Please enter a valid email address",
|
|
35
|
+
"invalidPhone": "Please enter a valid phone number",
|
|
36
|
+
"passwordTooShort": "Password must be at least 8 characters",
|
|
37
|
+
"confirmPassword": "Confirm Password",
|
|
38
|
+
"passwordMismatch": "Passwords do not match"
|
|
39
|
+
},
|
|
40
|
+
"messages": {
|
|
41
|
+
"saveSuccess": "Save successful",
|
|
42
|
+
"deleteSuccess": "Delete successful",
|
|
43
|
+
"updateSuccess": "Update successful",
|
|
44
|
+
"createSuccess": "Create successful",
|
|
45
|
+
"operationFailed": "Operation failed",
|
|
46
|
+
"networkError": "Network error, please try again later"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"page": {
|
|
3
|
+
"title": "NSGM CLI",
|
|
4
|
+
"description": "Full-stack architecture, code template generation, rapid development",
|
|
5
|
+
"sections": {
|
|
6
|
+
"database": {
|
|
7
|
+
"title": "Database Configuration",
|
|
8
|
+
"description": "Database uses Mysql, see mysql.config.js for configuration"
|
|
9
|
+
},
|
|
10
|
+
"project": {
|
|
11
|
+
"title": "Project Configuration",
|
|
12
|
+
"description": "See project.config.js for project configuration"
|
|
13
|
+
},
|
|
14
|
+
"framework": {
|
|
15
|
+
"title": "Framework Configuration",
|
|
16
|
+
"description": "See next.config.js for Next framework configuration"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"commands": {
|
|
20
|
+
"title": "Commands",
|
|
21
|
+
"categories": {
|
|
22
|
+
"projectManagement": {
|
|
23
|
+
"title": "Project Management",
|
|
24
|
+
"items": {
|
|
25
|
+
"init": "Initialize project",
|
|
26
|
+
"upgrade": "Upgrade project base files"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"templateOperations": {
|
|
30
|
+
"title": "Template Operations",
|
|
31
|
+
"items": {
|
|
32
|
+
"create": "Create template page",
|
|
33
|
+
"delete": "Delete template page",
|
|
34
|
+
"deletedb": "Delete template page and database table"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"runBuild": {
|
|
38
|
+
"title": "Run & Build",
|
|
39
|
+
"items": {
|
|
40
|
+
"dev": "Development mode",
|
|
41
|
+
"start": "Production mode",
|
|
42
|
+
"build": "Build",
|
|
43
|
+
"export": "Export static pages"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"parameters": {
|
|
49
|
+
"title": "Parameters",
|
|
50
|
+
"items": {
|
|
51
|
+
"dictionary": "Used in export/init, default webapp",
|
|
52
|
+
"controller": "Required when using create/delete",
|
|
53
|
+
"action": "Used in create/delete, default manage"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"layout": {
|
|
3
|
+
"userActions": {
|
|
4
|
+
"logout": "Logout",
|
|
5
|
+
"profile": "Profile",
|
|
6
|
+
"settings": "Account Settings",
|
|
7
|
+
"notifications": "Notifications",
|
|
8
|
+
"user": "User"
|
|
9
|
+
},
|
|
10
|
+
"navigation": {
|
|
11
|
+
"home": "Home",
|
|
12
|
+
"dashboard": "Dashboard",
|
|
13
|
+
"management": "Management",
|
|
14
|
+
"system": "System"
|
|
15
|
+
},
|
|
16
|
+
"menu": {
|
|
17
|
+
"introduction": "Introduction",
|
|
18
|
+
"template": "Template",
|
|
19
|
+
"template1": "Template 1"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"login": {
|
|
3
|
+
"title": "System Login",
|
|
4
|
+
"username": "Username",
|
|
5
|
+
"password": "Password",
|
|
6
|
+
"loginButton": "Login",
|
|
7
|
+
"errors": {
|
|
8
|
+
"usernameRequired": "Please enter username",
|
|
9
|
+
"passwordRequired": "Please enter password",
|
|
10
|
+
"loginFailed": "Login failed"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|