nsgm-cli 2.1.6 → 2.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,28 +1,62 @@
1
1
  # NSGM CLI
2
- - 技术栈: [Next](https://github.com/vercel/next.js), [Styled-components](https://github.com/styled-components/styled-components), [Graphql](https://graphql.org/), [Mysql](https://www.mysql.com/)
3
- - 全栈架构,代码模板生成,快速开发
4
- - 数据库采用 Mysql, 配置见 mysql.config.js
5
- - 项目配置见 project.config.js
6
- - Next 框架配置见 next.config.js
7
-
8
- ## 命令
9
- - nsgm init 初始化项目
10
- - nsgm upgrade 升级项目基础文件
11
- - nsgm create 创建模板页面
12
- - nsgm delete 删除模板页面
13
- - nsgm deletedb 删除模板页面及数据库表
14
- - nsgm dev 开发模式
15
- - nsgm start 生产模式
16
- - nsgm build 编译
17
- - nsgm export 导出静态页面
18
-
19
- ## 参数
20
- - dictionary: export/init 的时候使用, 默认 webapp, 譬如: nsgm init|export dictionary=webapp 或者 nsgm init|export webapp
21
- - controller: 在 create/delete 的时候使用, 必须有。譬如:nsgm create|delete math
22
- - action: 在 create/delete 的时候使用, 默认 manage, 跟在 controller 后面, 譬如 nsgm create|delete math test
23
-
24
- ## 根目录新增 next.config.js
25
- ```
2
+
3
+ A full-stack development framework with code template generation capabilities, helping developers efficiently build web applications.
4
+
5
+ ## Tech Stack
6
+
7
+ - [Next.js](https://github.com/vercel/next.js) - React framework
8
+ - [Styled-components](https://github.com/styled-components/styled-components) - CSS-in-JS solution
9
+ - [GraphQL](https://graphql.org/) - API query language
10
+ - [MySQL](https://www.mysql.com/) - Relational database
11
+
12
+ ## Features
13
+
14
+ - Full-stack architecture design
15
+ - Automatic code template generation
16
+ - Rapid development workflow
17
+ - Integrated GraphQL API
18
+ - MySQL database support
19
+
20
+ ## Command Line Tools
21
+
22
+ ### Basic Commands
23
+
24
+ | Command | Description |
25
+ |------|------|
26
+ | `nsgm init` | Initialize project |
27
+ | `nsgm upgrade` | Upgrade project base files |
28
+ | `nsgm create` | Create template page |
29
+ | `nsgm delete` | Delete template page |
30
+ | `nsgm deletedb` | Delete template page and database table |
31
+ | `nsgm dev` | Development mode |
32
+ | `nsgm start` | Production mode |
33
+ | `nsgm build` | Build project |
34
+ | `nsgm export` | Export static pages |
35
+
36
+ ### Parameter Description
37
+
38
+ - **dictionary**: Used with `export`/`init` commands, default value is `webapp`
39
+ ```
40
+ nsgm init dictionary=webapp
41
+ # or simplified as
42
+ nsgm init webapp
43
+ ```
44
+
45
+ - **controller**: Used with `create`/`delete` commands, required parameter
46
+ ```
47
+ nsgm create math
48
+ ```
49
+
50
+ - **action**: Used with `create`/`delete` commands, default value is `manage`, follows the controller
51
+ ```
52
+ nsgm create math test
53
+ ```
54
+
55
+ ## Project Configuration
56
+
57
+ ### next.config.js
58
+
59
+ ```javascript
26
60
  const { nextConfig } = require('nsgm-cli')
27
61
  const projectConfig = require('./project.config')
28
62
 
@@ -37,8 +71,9 @@ module.exports = (phase, defaultConfig) => {
37
71
  }
38
72
  ```
39
73
 
40
- ## 根目录新增 mysql.config.js
41
- ```
74
+ ### mysql.config.js
75
+
76
+ ```javascript
42
77
  const { mysqlConfig } = require('nsgm-cli')
43
78
  const { mysqlOptions } = mysqlConfig
44
79
  const { user, password, host, port, database } = mysqlOptions
@@ -54,8 +89,9 @@ module.exports = {
54
89
  }
55
90
  ```
56
91
 
57
- ## 根目录新增 project.config.js
58
- ```
92
+ ### project.config.js
93
+
94
+ ```javascript
59
95
  const { projectConfig } = require('nsgm-cli')
60
96
  const pkg = require('./package.json')
61
97
 
@@ -71,34 +107,44 @@ module.exports = {
71
107
  }
72
108
  ```
73
109
 
74
- ## 根目录新增 server
75
- - apis 存放 Rest Api
76
- - modules 存放 graphql 的 resolver 和 schema
77
- - plugins 存放 graphql 的 plugin
78
- - *.js 举例: test.js => 用于响应 /test/*, ${prefix}/test/* 请求
110
+ ## Server Directory Structure
79
111
 
80
- ```
81
- const express = require('express')
82
- const moment = require('moment')
112
+ The `server` folder in the project root contains the following:
83
113
 
84
- const router = express.Router()
114
+ ### Directory Description
85
115
 
86
- router.use((req, res, next) => {
87
- const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl
88
- console.log(moment().format('YYYY-MM-DD HH:mm:ss') + ' ' + fullUrl)
89
- next()
90
- })
116
+ - `apis/` - Stores REST API interfaces
117
+ - `modules/` - Stores GraphQL resolvers and schemas
118
+ - `plugins/` - Stores GraphQL plugins
119
+ - `*.js` - Route files, e.g., `test.js` handles requests to `/test/*` and `${prefix}/test/*`
91
120
 
92
- router.get('/*', (req, res) => {
93
- res.statusCode = 200
94
- res.json({ name: 'TEST' })
95
- })
121
+ ### Example Code
96
122
 
97
- module.exports = router
98
- ```
123
+ #### Route File Example (server/test.js)
99
124
 
100
- - apis/hello.js
125
+ ```javascript
126
+ const express = require('express')
127
+ const moment = require('moment')
128
+
129
+ const router = express.Router()
130
+
131
+ router.use((req, res, next) => {
132
+ const fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl
133
+ console.log(moment().format('YYYY-MM-DD HH:mm:ss') + ' ' + fullUrl)
134
+ next()
135
+ })
136
+
137
+ router.get('/*', (req, res) => {
138
+ res.statusCode = 200
139
+ res.json({ name: 'TEST' })
140
+ })
141
+
142
+ module.exports = router
101
143
  ```
144
+
145
+ #### REST API Example (server/apis/hello.js)
146
+
147
+ ```javascript
102
148
  const express = require('express')
103
149
  const router = express.Router()
104
150
 
@@ -110,8 +156,9 @@ router.get('/*', (req, res) => {
110
156
  module.exports = router
111
157
  ```
112
158
 
113
- - modules/link/schema.js
114
- ```
159
+ #### GraphQL Schema Example (server/modules/link/schema.js)
160
+
161
+ ```javascript
115
162
  module.exports = {
116
163
  query: `
117
164
  link: String
@@ -124,15 +171,16 @@ module.exports = {
124
171
  }
125
172
  ```
126
173
 
127
- - modules/link/resolver.js
128
- ```
174
+ #### GraphQL Resolver Example (server/modules/link/resolver.js)
175
+
176
+ ```javascript
129
177
  let localLink = ''
130
178
 
131
179
  module.exports = {
132
180
  link: () => {
133
181
  return localLink
134
182
  },
135
- linkUpdate: ({ link }) =>{
183
+ linkUpdate: ({ link }) => {
136
184
  console.log('link', link)
137
185
  localLink = link
138
186
  return localLink
@@ -140,8 +188,9 @@ module.exports = {
140
188
  }
141
189
  ```
142
190
 
143
- - plugins/date.js
144
- ```
191
+ #### GraphQL Plugin Example (server/plugins/date.js)
192
+
193
+ ```javascript
145
194
  const moment = require('moment')
146
195
  const { Kind } = require('graphql/language')
147
196
  const { GraphQLScalarType } = require('graphql')
@@ -157,5 +206,4 @@ const customScalarDate = new GraphQLScalarType({
157
206
  })
158
207
 
159
208
  module.exports = { Date: customScalarDate }
160
- ```
161
-
209
+ ```
@@ -1,13 +1,13 @@
1
1
  import React, { useEffect, useState } from 'react'
2
- import { Layout, Menu, Breadcrumb, Image, Select, Avatar, Dropdown, Space, Tooltip } from 'antd'
3
- import { Container } from '../styled/layout'
2
+ import { Layout, Menu, Breadcrumb, Image, Select, Dropdown, Space, Tooltip } from 'antd'
3
+ import { Container } from '@/styled/layout'
4
4
  import styled from 'styled-components'
5
5
  import { useRouter } from 'next/router'
6
6
  import _ from 'lodash'
7
- import menuConfig from '../utils/menu'
8
- import { logout } from '../utils/sso'
7
+ import menuConfig from '@/utils/menu'
8
+ import { logout } from '@/utils/sso'
9
9
  import getConfig from 'next/config'
10
- import { UserOutlined, LogoutOutlined, SettingOutlined, BellOutlined } from '@ant-design/icons'
10
+ import { LogoutOutlined, SettingOutlined, BellOutlined, UserOutlined } from '@ant-design/icons'
11
11
 
12
12
  const { Option } = Select
13
13
  const { SubMenu } = Menu
@@ -25,24 +25,80 @@ const FlexLayout = styled(Layout)`
25
25
  const StyledSider = styled(Sider)`
26
26
  display: flex;
27
27
  flex-direction: column;
28
- justify-content: space-between;
29
- `
30
- const SiderFooter = styled.div<{ collapsed: boolean }>`
31
- padding: ${props => props.collapsed ? '8px 0' : '8px 16px'};
32
- text-align: center;
33
- color: rgba(0,0,0,0.45);
34
- font-size: 12px;
35
- border-top: 1px solid #ebeef5;
36
- background: #f5f7fa;
28
+ box-shadow: 2px 0 8px -4px rgba(0, 0, 0, 0.1);
29
+ z-index: 5;
30
+ position: relative;
37
31
  `
32
+
38
33
  const SideMenu = styled(Menu)`
39
34
  height: 100%;
40
35
  border-right: 0;
36
+ padding: 8px 0;
41
37
  `
38
+
42
39
  const ContentLayout = styled(Layout)`
43
40
  display: flex;
44
41
  flex-direction: column;
45
42
  flex: 1;
43
+ background: #f5f7fa;
44
+ position: relative;
45
+ z-index: 1;
46
+ `
47
+ const StyledHeader = styled(Header)`
48
+ display: flex;
49
+ align-items: center;
50
+ padding: 0 24px;
51
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
52
+ z-index: 11;
53
+
54
+ .logo {
55
+ margin-right: 24px;
56
+ }
57
+
58
+ .main-menu {
59
+ flex: 1;
60
+ }
61
+
62
+ .user-actions {
63
+ display: flex;
64
+ align-items: center;
65
+
66
+ .action-icon {
67
+ font-size: 18px;
68
+ color: rgba(255, 255, 255, 0.85);
69
+ cursor: pointer;
70
+ padding: 0 8px;
71
+ transition: color 0.3s;
72
+
73
+ &:hover {
74
+ color: #fff;
75
+ }
76
+ }
77
+
78
+ .user-dropdown {
79
+ cursor: pointer;
80
+ padding: 0 8px;
81
+
82
+ .username {
83
+ color: rgba(255, 255, 255, 0.85);
84
+ margin-left: 8px;
85
+ }
86
+ }
87
+ }
88
+ `
89
+ const StyledBreadcrumb = styled(Breadcrumb)`
90
+ margin: 16px 24px;
91
+ font-size: 14px;
92
+ `
93
+ const StyledContent = styled(Content)`
94
+ margin: 0 24px 24px;
95
+ padding: 24px;
96
+ background: #fff;
97
+ border-radius: 4px;
98
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
99
+ min-height: calc(100vh - 180px);
100
+ position: relative;
101
+ z-index: 1;
46
102
  `
47
103
 
48
104
  const getLocationKey = () => {
@@ -208,9 +264,9 @@ const LayoutComponent = ({ user, children }) => {
208
264
  return (
209
265
  <Layout className="main-layout">
210
266
  <Container>
211
- <Header className="header">
267
+ <StyledHeader>
212
268
  <div className="logo">
213
- <Image width={100} src={prefix + "/images/zhizuotu_1.png"} preview={false} />
269
+ <Image width={120} src={prefix + "/images/zhizuotu_1.png"} preview={false} />
214
270
  </div>
215
271
  <Menu
216
272
  theme="dark"
@@ -221,7 +277,7 @@ const LayoutComponent = ({ user, children }) => {
221
277
  className="main-menu"
222
278
  />
223
279
  <div className="user-actions">
224
- <Space size={16} align="center">
280
+ <Space size={20} align="center">
225
281
  <Tooltip title="通知">
226
282
  <BellOutlined className="action-icon" />
227
283
  </Tooltip>
@@ -259,10 +315,10 @@ const LayoutComponent = ({ user, children }) => {
259
315
  </Dropdown>
260
316
  </Space>
261
317
  </div>
262
- </Header>
318
+ </StyledHeader>
263
319
  <FlexLayout>
264
320
  <StyledSider
265
- width={200}
321
+ width={220}
266
322
  className="site-layout-background sidebar"
267
323
  collapsible
268
324
  collapsed={collapsed}
@@ -279,12 +335,9 @@ const LayoutComponent = ({ user, children }) => {
279
335
  className="side-menu"
280
336
  />
281
337
  </div>
282
- <SiderFooter collapsed={collapsed}>
283
- {collapsed ? '©' : '© 2025 NSGM'}
284
- </SiderFooter>
285
338
  </StyledSider>
286
339
  <ContentLayout className="content-layout">
287
- <Breadcrumb className="breadcrumb-container">
340
+ <StyledBreadcrumb>
288
341
  {_.map(menuConfig, (item, index) => {
289
342
  const { key, text, subMenus } = item
290
343
 
@@ -294,7 +347,7 @@ const LayoutComponent = ({ user, children }) => {
294
347
  const { key: subKey, text: subText } = subItem
295
348
  if (subKey === topMenuKey + '_' + sliderMenuKey) {
296
349
  subContent.push(<Breadcrumb.Item key={'breadcrumb' + subIndex}>{text}</Breadcrumb.Item>)
297
- subContent.push(<Breadcrumb.Item key={'breadcrumb' + subIndex}>{subText}</Breadcrumb.Item>)
350
+ subContent.push(<Breadcrumb.Item key={'breadcrumb' + subIndex + '_sub'}>{subText}</Breadcrumb.Item>)
298
351
  return false
299
352
  }
300
353
  })
@@ -305,12 +358,10 @@ const LayoutComponent = ({ user, children }) => {
305
358
  }
306
359
  }
307
360
  })}
308
- </Breadcrumb>
309
- <Content
310
- className="site-layout-background content-container"
311
- >
361
+ </StyledBreadcrumb>
362
+ <StyledContent>
312
363
  {children}
313
- </Content>
364
+ </StyledContent>
314
365
  </ContentLayout>
315
366
  </FlexLayout>
316
367
  </Container>
@@ -1,5 +1,5 @@
1
1
  import * as types from './types'
2
- import { getTemplateService, addTemplateService, updateTemplateService, deleteTemplateService, searchTemplateService, batchDeleteTemplateService } from '../../../service/template/manage'
2
+ import { getTemplateService, addTemplateService, updateTemplateService, deleteTemplateService, searchTemplateService, batchDeleteTemplateService } from '@/service/template/manage'
3
3
 
4
4
  export const getTemplate = (page=0, pageSize=10) => (
5
5
  dispatch: (arg0: {
@@ -1,7 +1,7 @@
1
- import { getLocalGraphql } from '../../utils/fetch'
1
+ import { getLocalGraphql } from '@/utils/fetch'
2
2
  import _ from 'lodash'
3
3
 
4
- export const getTemplateService = (page=0, pageSize=10) => {
4
+ export const getTemplateService = (page = 0, pageSize = 10) => {
5
5
  const getTemplateQuery = `query ($page: Int, $pageSize: Int) { template(page: $page, pageSize: $pageSize) {
6
6
  totalCounts items {
7
7
  id name
@@ -9,10 +9,10 @@ export const getTemplateService = (page=0, pageSize=10) => {
9
9
  }
10
10
  }`
11
11
 
12
- return getLocalGraphql(getTemplateQuery, {
13
- page,
14
- pageSize
15
- })
12
+ return getLocalGraphql(getTemplateQuery, {
13
+ page,
14
+ pageSize
15
+ })
16
16
  }
17
17
 
18
18
  export const searchTemplateByIdService = (id: number) => {
@@ -39,7 +39,7 @@ export const searchTemplateService = (page = 0, pageSize = 10, data: any) => {
39
39
  }`
40
40
 
41
41
  return getLocalGraphql(searchTemplateQuery, {
42
- page,
42
+ page,
43
43
  pageSize,
44
44
  data: {
45
45
  name
@@ -47,7 +47,7 @@ export const searchTemplateService = (page = 0, pageSize = 10, data: any) => {
47
47
  })
48
48
  }
49
49
 
50
- export const addTemplateService = (data: any) => {
50
+ export const addTemplateService = (data: any) => {
51
51
  const { name } = data
52
52
 
53
53
  const addTemplateQuery = `mutation ($data: TemplateAddInput) { templateAdd(data: $data) }`
@@ -59,7 +59,7 @@ export const addTemplateService = (data: any) => {
59
59
  })
60
60
  }
61
61
 
62
- export const updateTemplateService = (id: number, data: any) => {
62
+ export const updateTemplateService = (id: number, data: any) => {
63
63
  const { name } = data
64
64
 
65
65
  const updateTemplateQuery = `mutation ($id: Int, $data: TemplateAddInput) { templateUpdate(id: $id, data: $data) }`
@@ -72,7 +72,7 @@ export const updateTemplateService = (id: number, data: any) => {
72
72
  })
73
73
  }
74
74
 
75
- export const deleteTemplateService = (id: number) => {
75
+ export const deleteTemplateService = (id: number) => {
76
76
  const deleteTemplateQuery = `mutation ($id: Int) { templateDelete(id: $id) }`
77
77
 
78
78
  return getLocalGraphql(deleteTemplateQuery, {
@@ -88,7 +88,7 @@ export const batchAddTemplateService = (datas: any) => {
88
88
  })
89
89
  }
90
90
 
91
- export const batchDeleteTemplateService = (ids: any) => {
91
+ export const batchDeleteTemplateService = (ids: any) => {
92
92
  const batchDeleteTemplateQuery = `mutation ($ids: [Int]) { templateBatchDelete(ids: $ids) }`
93
93
 
94
94
  return getLocalGraphql(batchDeleteTemplateQuery, {
@@ -8,17 +8,17 @@ const env = getLocalEnv()
8
8
  const LOGIN_COOKIE_ID = env + '_cas_nsgm'
9
9
  const LOGIN_COOKIE_USER = env + '_nsgm_user'
10
10
 
11
- const getPrincipalUrl = () => {
11
+ const getPrincipalUrl = () => {
12
12
  const url = getLocalApiPrefix() + '/rest/sso/sessionCheck'
13
13
  return url
14
14
  }
15
15
 
16
- const getValidateUrl = () => {
16
+ const getValidateUrl = () => {
17
17
  const url = getLocalApiPrefix() + '/rest/sso/ticketCheck'
18
18
  return url
19
19
  }
20
20
 
21
- const handleLocationHref = () => {
21
+ const handleLocationHref = () => {
22
22
  let newHref = ''
23
23
  if (typeof window !== 'undefined') {
24
24
  const locationHref = window.location.href
@@ -27,12 +27,12 @@ const handleLocationHref = () => {
27
27
  const locationHrefArrLen = locationHrefArr.length
28
28
 
29
29
  let newParamStr = ''
30
-
30
+
31
31
  if (locationHrefArrLen > 1) {
32
32
  const paramStr = locationHrefArr[1]
33
33
  if (paramStr.indexOf('&') !== -1) {
34
34
  const paramArr = paramStr.split('&')
35
-
35
+
36
36
  _.each(paramArr, (item, index) => {
37
37
  if (item.indexOf('=') !== -1) {
38
38
  const itemArr = item.split('=')
@@ -42,7 +42,7 @@ const handleLocationHref = () => {
42
42
  let value = ''
43
43
  if (itemArrLen > 1)
44
44
  value = itemArr[1]
45
-
45
+
46
46
  if ('ticket' !== key) {
47
47
  newParamStr += key + '=' + value + '&'
48
48
  }
@@ -58,11 +58,11 @@ const handleLocationHref = () => {
58
58
  }
59
59
 
60
60
  const locationHrefArrFirst = locationHrefArr[0]
61
- if(newParamStr !== '')
61
+ if (newParamStr !== '')
62
62
  newHref = locationHrefArrFirst + '?' + newParamStr
63
63
  else
64
64
  newHref = locationHrefArrFirst
65
- } else {
65
+ } else {
66
66
  newHref = locationHref
67
67
  }
68
68
  }
@@ -71,43 +71,43 @@ const handleLocationHref = () => {
71
71
  return encodeURIComponent(newHref)
72
72
  }
73
73
 
74
- const jumpToLogin = () => {
74
+ const jumpToLogin = () => {
75
75
  delCookie(LOGIN_COOKIE_ID)
76
76
  delCookie(LOGIN_COOKIE_USER)
77
-
77
+
78
78
  if (typeof window !== 'undefined') {
79
79
  window.location.href = window.location.origin + '/login'
80
80
  }
81
81
  }
82
82
 
83
- const jumpToLogout = () => {
83
+ const jumpToLogout = () => {
84
84
  delCookie(LOGIN_COOKIE_ID)
85
85
  delCookie(LOGIN_COOKIE_USER)
86
-
86
+
87
87
  if (typeof window !== 'undefined') {
88
88
  window.location.href = window.location.origin
89
89
  }
90
90
  }
91
91
 
92
- const principalLogin = (cookie:string, callback:any) => {
92
+ const principalLogin = (cookie: string, callback: any) => {
93
93
  let url = getPrincipalUrl()
94
94
 
95
95
  if (typeof window !== 'undefined') {
96
96
  url += '?cookieValue=' + cookie + '&redirectUrl=' + handleLocationHref()
97
97
  }
98
98
 
99
- console.log('principalLogin_url', url)
100
- axios.get(url, { params: { credentials: 'include' } }).then((res:any) => {
101
- console.log('principalLogin_res', res)
99
+ // console.log('principalLogin_url', url)
100
+ axios.get(url, { params: { credentials: 'include' } }).then((res: any) => {
101
+ // console.log('principalLogin_res', res)
102
102
  const { data } = res
103
103
  if (data) {
104
104
  const { returnCode, userAttr } = data
105
105
  if (returnCode !== 0) {
106
106
  jumpToLogin()
107
- } else {
107
+ } else {
108
108
  storeLoginUser(userAttr, callback)
109
109
  }
110
- } else {
110
+ } else {
111
111
  jumpToLogin()
112
112
  }
113
113
  }).catch((e) => {
@@ -116,42 +116,42 @@ const principalLogin = (cookie:string, callback:any) => {
116
116
  })
117
117
  }
118
118
 
119
- const storeLoginUser = (userAttr:any, callback:any) => {
120
- console.log('storeLoginUser', userAttr)
119
+ const storeLoginUser = (userAttr: any, callback: any) => {
120
+ // console.log('storeLoginUser', userAttr)
121
121
 
122
122
  if (userAttr) {
123
123
  const user = JSON.stringify(userAttr, ['city', 'company', 'department', 'displayName', 'employee', 'mail', 'name', 'sn'])
124
124
  setCookie(LOGIN_COOKIE_USER, user, null)
125
125
  callback && callback(JSON.parse(user))
126
- } else {
126
+ } else {
127
127
  callback && callback()
128
128
  }
129
129
  }
130
130
 
131
- const storeLogin = (cookie:any, cookieExpire:any, userAttr:any, callback:any) => {
132
- console.log('storeLogin_cookie', cookie)
131
+ const storeLogin = (cookie: any, cookieExpire: any, userAttr: any, callback: any) => {
132
+ // console.log('storeLogin_cookie', cookie)
133
133
 
134
- if (cookie) {
134
+ if (cookie) {
135
135
  setCookie(LOGIN_COOKIE_ID, cookie, cookieExpire)
136
136
  }
137
137
 
138
138
  storeLoginUser(userAttr, callback)
139
139
  }
140
140
 
141
- const validateLogin = (ticket:string, name:string = '', callback:any) => {
141
+ const validateLogin = (ticket: string, name: string = '', callback: any) => {
142
142
  let url = getValidateUrl()
143
143
 
144
144
  if (typeof window !== 'undefined') {
145
145
  url += '?ticket=' + ticket
146
146
 
147
- if(name !== ''){
147
+ if (name !== '') {
148
148
  url += '&name=' + name
149
149
  }
150
150
  }
151
-
152
- console.log('validateLogin_url', url)
153
- axios.get(url, { params: { credentials: 'include' } }).then((res:any) => {
154
- console.log('validateLogin_res', res)
151
+
152
+ // console.log('validateLogin_url', url)
153
+ axios.get(url, { params: { credentials: 'include' } }).then((res: any) => {
154
+ // console.log('validateLogin_res', res)
155
155
 
156
156
  if (res) {
157
157
  const { data } = res
@@ -159,13 +159,13 @@ const validateLogin = (ticket:string, name:string = '', callback:any) => {
159
159
  const { cookieValue, cookieExpire, returnCode, userAttr } = data
160
160
  if (returnCode === 0) {
161
161
  storeLogin(cookieValue, cookieExpire, userAttr, callback)
162
- } else {
162
+ } else {
163
163
  jumpToLogin()
164
164
  }
165
- } else {
165
+ } else {
166
166
  jumpToLogin()
167
167
  }
168
- } else {
168
+ } else {
169
169
  jumpToLogin()
170
170
  }
171
171
  }).catch((e) => {
@@ -173,25 +173,25 @@ const validateLogin = (ticket:string, name:string = '', callback:any) => {
173
173
  })
174
174
  }
175
175
 
176
- export const login = (callback:any) => {
176
+ export const login = (callback: any) => {
177
177
  const cookieLoginValue = getCookie(LOGIN_COOKIE_ID)
178
- console.log('cookieLoginValue', cookieLoginValue)
178
+ // console.log('cookieLoginValue', cookieLoginValue)
179
179
 
180
- if(typeof window !== 'undefined'){
180
+ if (typeof window !== 'undefined') {
181
181
  const locationHref = window.location.href
182
182
 
183
- if(locationHref.indexOf('/login') === -1){
183
+ if (locationHref.indexOf('/login') === -1) {
184
184
 
185
185
  if (cookieLoginValue !== '') {
186
186
  principalLogin(cookieLoginValue, callback)
187
- } else {
187
+ } else {
188
188
  const urlParamTicket = getUrlParamByKey('ticket')
189
189
  const urlParamName = getUrlParamByKey('name')
190
- console.log('urlParamTicket', urlParamTicket, urlParamName)
190
+ // console.log('urlParamTicket', urlParamTicket, urlParamName)
191
191
 
192
192
  if (urlParamTicket !== '') {
193
193
  validateLogin(urlParamTicket, urlParamName, callback)
194
- } else {
194
+ } else {
195
195
  jumpToLogin()
196
196
  }
197
197
  }
@@ -199,7 +199,7 @@ export const login = (callback:any) => {
199
199
  }
200
200
  }
201
201
 
202
- export const logout = () => {
202
+ export const logout = () => {
203
203
  jumpToLogout()
204
204
  }
205
205
 
@@ -1,16 +1,147 @@
1
- # NSGM CLI PROJECT
2
-
3
- ## 命令
4
- - npm run init 初始化项目
5
- - npm run upgrade 升级项目基础文件
6
- - npm run create 创建模板页面
7
- - npm run delete 删除模板页面
8
- - npm run dev 开发模式
9
- - npm run start 生产模式
10
- - npm run build 编译
11
- - npm run export 导出静态页面
12
-
13
- ## 参数
14
- - dictionary: 在 export/init 的时候使用, 默认 webapp, 譬如: npm run init|export dictionary=webapp 或者 npm run init|export webapp
15
- - controller: 在 create/delete 的时候使用, 必须有。譬如: npm run create|delete math
16
- - action: 在 create/delete 的时候使用, 默认 manage, 跟在 controller 后面, 譬如 npm run create|delete math test
1
+ # 欢迎使用 NSGM 项目
2
+
3
+ 这是一个由 NSGM CLI 创建的全栈开发项目,集成了 Next.js、Styled-components、GraphQL 和 MySQL 技术栈。
4
+
5
+ ## 技术栈
6
+
7
+ - [Next.js](https://github.com/vercel/next.js) - React 框架
8
+ - [Styled-components](https://github.com/styled-components/styled-components) - CSS-in-JS 解决方案
9
+ - [GraphQL](https://graphql.org/) - API 查询语言
10
+ - [MySQL](https://www.mysql.com/) - 关系型数据库
11
+
12
+ ## 快速入门
13
+
14
+ ### 开发命令
15
+
16
+ | 命令 | 说明 |
17
+ |---------|-------------|
18
+ | `npm run dev` | 开发模式 |
19
+ | `npm run start` | 生产模式 |
20
+ | `npm run build` | 编译项目 |
21
+ | `npm run export` | 导出静态页面 |
22
+
23
+ ### 代码生成命令
24
+
25
+ | 命令 | 说明 |
26
+ |---------|-------------|
27
+ | `npm run create` | 创建模板页面 |
28
+ | `npm run delete` | 删除模板页面 |
29
+
30
+ ### 项目维护命令
31
+
32
+ | 命令 | 说明 |
33
+ |---------|-------------|
34
+ | `npm run upgrade` | 升级项目基础文件 |
35
+
36
+ ## 参数说明
37
+
38
+ ### controller
39
+ - 用于 `create`/`delete` 命令
40
+ - 必填参数
41
+ - 示例:
42
+ ```
43
+ npm run create math
44
+ ```
45
+
46
+ ### action
47
+ - 用于 `create`/`delete` 命令
48
+ - 默认值为 `manage`
49
+ - 跟在 controller 参数后面
50
+ - 示例:
51
+ ```
52
+ npm run create math test
53
+ ```
54
+
55
+ ### dictionary
56
+ - 用于 `export` 命令
57
+ - 默认值为 `webapp`
58
+ - 示例:
59
+ ```
60
+ npm run export dictionary=webapp
61
+ # 或简化为
62
+ npm run export webapp
63
+ ```
64
+
65
+ ## 项目结构
66
+
67
+ ```
68
+ ├── components/ # 公共组件
69
+ ├── pages/ # 页面文件
70
+ │ ├── api/ # API 路由
71
+ │ └── [controller]/ # 控制器页面
72
+ ├── public/ # 静态资源
73
+ ├── server/ # 服务端代码
74
+ │ ├── apis/ # REST API 接口
75
+ │ ├── modules/ # GraphQL 解析器和模式
76
+ │ └── plugins/ # GraphQL 插件
77
+ ├── styles/ # 全局样式
78
+ ├── next.config.js # Next.js 配置
79
+ ├── mysql.config.js # MySQL 配置
80
+ └── project.config.js # 项目配置
81
+ ```
82
+
83
+ ## 配置文件
84
+
85
+ ### next.config.js
86
+
87
+ ```javascript
88
+ const { nextConfig } = require('nsgm-cli')
89
+ const projectConfig = require('./project.config')
90
+
91
+ const { version, prefix, protocol, host } = projectConfig
92
+
93
+ module.exports = (phase, defaultConfig) => {
94
+ let configObj = nextConfig(phase, defaultConfig, {
95
+ version, prefix, protocol, host
96
+ })
97
+
98
+ return configObj
99
+ }
100
+ ```
101
+
102
+ ### mysql.config.js
103
+
104
+ ```javascript
105
+ const { mysqlConfig } = require('nsgm-cli')
106
+ const { mysqlOptions } = mysqlConfig
107
+ const { user, password, host, port, database } = mysqlOptions
108
+
109
+ module.exports = {
110
+ mysqlOptions: {
111
+ user,
112
+ password,
113
+ host,
114
+ port,
115
+ database
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### project.config.js
121
+
122
+ ```javascript
123
+ const { projectConfig } = require('nsgm-cli')
124
+ const pkg = require('./package.json')
125
+
126
+ const { prefix, protocol, host, port } = projectConfig
127
+ const { version } = pkg
128
+
129
+ module.exports = {
130
+ version,
131
+ prefix,
132
+ protocol,
133
+ host,
134
+ port
135
+ }
136
+ ```
137
+
138
+ ## 开发指南
139
+
140
+ 1. **创建新页面**:使用 `npm run create [controller] [action]` 命令
141
+ 2. **启动开发服务器**:运行 `npm run dev`
142
+ 3. **构建生产版本**:运行 `npm run build` 然后 `npm run start`
143
+ 4. **导出静态网站**:运行 `npm run export`
144
+
145
+ ## 更多资源
146
+
147
+ 更多详细信息,请参考 [NSGM CLI 文档](https://github.com/erishen/nsgm-cli)。
package/next.config.js CHANGED
@@ -63,12 +63,17 @@ module.exports = (phase, defaultConfig, options) => {
63
63
  // Bundle 优化配置
64
64
  experimental: {
65
65
  optimizeCss: true, // 启用 CSS 优化(已安装 critters 依赖)
66
- swcMinify: true, // 使用 SWC 压缩器
67
66
  esmExternals: true // 支持 ESM 外部依赖
68
67
  },
69
68
  compiler: {
70
69
  removeConsole: phase !== PHASE_DEVELOPMENT_SERVER,
71
70
  },
71
+ allowedDevOrigins: [
72
+ 'http://127.0.0.1:8080',
73
+ 'http://localhost:8080',
74
+ 'http://127.0.0.1:3000',
75
+ 'http://localhost:3000'
76
+ ],
72
77
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
73
78
  // 启用压缩
74
79
  if (!dev && !isServer) {
@@ -105,7 +110,7 @@ module.exports = (phase, defaultConfig, options) => {
105
110
  },
106
111
  minimize: true,
107
112
  }
108
-
113
+
109
114
  // 添加分析工具
110
115
  if (process.env.ANALYZE === 'true') {
111
116
  const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
@@ -117,13 +122,13 @@ module.exports = (phase, defaultConfig, options) => {
117
122
  )
118
123
  }
119
124
  }
120
-
125
+
121
126
  // 优化模块解析
122
127
  config.resolve.alias = {
123
128
  ...config.resolve.alias,
124
129
  '@': path.resolve(__dirname, 'client'),
125
130
  }
126
-
131
+
127
132
  return config
128
133
  },
129
134
  generateBuildId: async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nsgm-cli",
3
- "version": "2.1.6",
3
+ "version": "2.1.8",
4
4
  "description": "A CLI tool to run Next/Style-components and Graphql/Mysql fullstack project",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/pages/_app.tsx CHANGED
@@ -1,10 +1,10 @@
1
1
  import React, { useEffect, useState } from 'react'
2
2
  import { Provider } from 'react-redux'
3
3
  import { ThemeProvider } from 'styled-components'
4
- import { useStore } from '../client/redux/store'
5
- import { GlobalStyle, Loading } from '../client/styled/common'
6
- import LayoutComponent from '../client/layout'
7
- import { login } from '../client/utils/sso'
4
+ import { useStore } from '@/redux/store'
5
+ import { GlobalStyle, Loading } from '@/styled/common'
6
+ import LayoutComponent from '@/layout'
7
+ import { login } from '@/utils/sso'
8
8
  import { Spin } from 'antd'
9
9
  import 'antd/dist/reset.css'
10
10
 
@@ -15,7 +15,9 @@ const MyDocument = () => {
15
15
  <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui" />
16
16
  <meta name="apple-mobile-web-app-capable" content="yes" />
17
17
  <meta charSet="utf-8" />
18
- <Head />
18
+ <Head>
19
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
20
+ </Head>
19
21
  <body>
20
22
  <Main />
21
23
  <NextScript />
@@ -1,15 +1,15 @@
1
1
  import React, { useEffect, useState } from 'react'
2
2
  import { ConfigProvider, Table, Modal, Button, Input, Space, Upload, message } from 'antd'
3
- import { Container, SearchRow, ModalContainer } from '../../client/styled/template/manage'
3
+ import { Container, SearchRow, ModalContainer } from '@/styled/template/manage'
4
4
  import styled from 'styled-components'
5
5
  import { useDispatch, useSelector } from 'react-redux'
6
- import { getTemplate, addTemplate, modTemplate, delTemplate, updateSSRTemplate, searchTemplate, batchDelTemplate } from '../../client/redux/template/manage/actions'
7
- import { getTemplateService } from '../../client/service/template/manage'
8
- import { RootState } from '../../client/redux/store'
6
+ import { getTemplate, addTemplate, modTemplate, delTemplate, updateSSRTemplate, searchTemplate, batchDelTemplate } from '@/redux/template/manage/actions'
7
+ import { getTemplateService } from '@/service/template/manage'
8
+ import { RootState } from '@/redux/store'
9
9
  import _ from 'lodash'
10
10
  import dayjs from 'dayjs'
11
11
  import locale from 'antd/lib/locale/zh_CN'
12
- import { handleXSS, checkModalObj } from '../../client/utils/common'
12
+ import { handleXSS, checkModalObj } from '@/utils/common'
13
13
  import { UploadOutlined } from '@ant-design/icons'
14
14
  import ExcelJS from 'exceljs'
15
15
  import { saveAs } from 'file-saver'
@@ -58,6 +58,11 @@ const StyledTable = styled(Table)`
58
58
  margin-top: 16px;
59
59
  border-radius: 8px;
60
60
  overflow: hidden;
61
+
62
+ .styled-pagination {
63
+ margin-top: 16px;
64
+ margin-bottom: 16px;
65
+ }
61
66
  `
62
67
  const ModalTitle = styled.div`
63
68
  color: #1890ff;
@@ -66,6 +71,21 @@ const ModalTitle = styled.div`
66
71
  const ModalInput = styled(Input)`
67
72
  border-radius: 4px;
68
73
  `
74
+ const IconWrapper = styled.i`
75
+ margin-right: 5px;
76
+ `
77
+ const StyledPagination = styled.div`
78
+ margin-top: 16px;
79
+ margin-bottom: 16px;
80
+ `
81
+ const RoundedButton = styled(Button)`
82
+ border-radius: 4px;
83
+ `
84
+ const GlobalStyle = styled.div`
85
+ .rounded-button {
86
+ border-radius: 4px;
87
+ }
88
+ `
69
89
 
70
90
  const Page = ({ template }) => {
71
91
  const dispatch = useDispatch()
@@ -123,13 +143,13 @@ const Page = ({ template }) => {
123
143
  render: (_: any, record: any) => {
124
144
  return (
125
145
  <Space size="small">
126
- <Button type="primary" size="small" onClick={() => {
146
+ <RoundedButton type="primary" size="small" onClick={() => {
127
147
  updateTemplate(record)
128
- }} style={{ borderRadius: '4px' }}>修改</Button>
129
- <Button danger size="small" onClick={() => {
148
+ }}>修改</RoundedButton>
149
+ <RoundedButton danger size="small" onClick={() => {
130
150
  const { id } = record
131
151
  deleteTemplate(id)
132
- }} style={{ borderRadius: '4px' }}>删除</Button>
152
+ }}>删除</RoundedButton>
133
153
  </Space>
134
154
  )
135
155
  }
@@ -281,13 +301,14 @@ const Page = ({ template }) => {
281
301
 
282
302
  return (
283
303
  <Container>
284
- <div className="page-title">模板管理</div>
304
+ <GlobalStyle />
305
+ <div className="page-title">Template 管理</div>
285
306
  <ConfigProvider locale={locale}>
286
307
  <SearchRow>
287
308
  <Space size="middle" wrap>
288
309
  <Space size="small">
289
310
  <StyledButton type="primary" onClick={createTemplate} $primary>
290
- <i className="fa fa-plus" style={{ marginRight: '5px' }}></i>
311
+ <IconWrapper className="fa fa-plus"></IconWrapper>
291
312
  新增
292
313
  </StyledButton>
293
314
  <StyledInput
@@ -298,7 +319,7 @@ const Page = ({ template }) => {
298
319
  onPressEnter={doSearch}
299
320
  />
300
321
  <StyledButton type="primary" onClick={doSearch} $primary>
301
- <i className="fa fa-search" style={{ marginRight: '5px' }}></i>
322
+ <IconWrapper className="fa fa-search"></IconWrapper>
302
323
  搜索
303
324
  </StyledButton>
304
325
  </Space>
@@ -335,11 +356,11 @@ const Page = ({ template }) => {
335
356
  onChange: (page, pageSize) => {
336
357
  dispatch(searchTemplate(page - 1, pageSize, { name: handleXSS(searchName) }))
337
358
  },
338
- style: { marginTop: '16px', marginBottom: '16px' }
359
+ className: "styled-pagination"
339
360
  }}
340
361
  />
341
362
  <Modal
342
- title={<ModalTitle>{(modalId == 0 ? "新增" : "修改") + " 模板"}</ModalTitle>}
363
+ title={<ModalTitle>{(modalId == 0 ? "新增" : "修改") + " Template"}</ModalTitle>}
343
364
  open={isModalVisiable}
344
365
  onOk={handleOk}
345
366
  onCancel={handleCancel}
@@ -348,8 +369,8 @@ const Page = ({ template }) => {
348
369
  centered
349
370
  maskClosable={false}
350
371
  destroyOnClose
351
- okButtonProps={{ style: { borderRadius: '4px' } }}
352
- cancelButtonProps={{ style: { borderRadius: '4px' } }}
372
+ okButtonProps={{ className: 'rounded-button' }}
373
+ cancelButtonProps={{ className: 'rounded-button' }}
353
374
  >
354
375
  <ModalContainer>
355
376
  <div className="line">
package/babel.config.js DELETED
@@ -1,18 +0,0 @@
1
- module.exports = {
2
- presets: [
3
- ['next/babel', {
4
- 'preset-env': {
5
- targets: {
6
- node: '18'
7
- }
8
- }
9
- }]
10
- ],
11
- plugins: [
12
- ['styled-components', {
13
- ssr: true,
14
- displayName: true,
15
- preprocess: false
16
- }]
17
- ]
18
- }