@jiangood/open-admin 3.1.6 → 3.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.
Files changed (60) hide show
  1. package/package.json +2 -5
  2. package/src/framework/biz/PermActions.tsx +1 -1
  3. package/src/framework/biz/UserPicker.less +17 -0
  4. package/src/framework/biz/UserPicker.tsx +296 -0
  5. package/src/framework/biz/index.tsx +2 -0
  6. package/src/framework/biz/pickerUser.ts +19 -0
  7. package/src/framework/components/ContextMenu/index.tsx +11 -8
  8. package/src/framework/components/DownloadModal/index.tsx +7 -7
  9. package/src/framework/components/ErrorBoundary/index.tsx +1 -1
  10. package/src/framework/components/FormModal/index.tsx +4 -4
  11. package/src/framework/components/NamedIcon/index.tsx +1 -1
  12. package/src/framework/components/OrgSwitcher/index.tsx +1 -1
  13. package/src/framework/components/Page/index.tsx +18 -4
  14. package/src/framework/components/PageLoading/index.tsx +2 -2
  15. package/src/framework/components/ProTable/index.less +70 -8
  16. package/src/framework/components/ProTable/index.tsx +63 -16
  17. package/src/framework/components/ThemeSettings/index.tsx +173 -0
  18. package/src/framework/components/index.ts +1 -0
  19. package/src/framework/config/index.ts +44 -2
  20. package/src/framework/config/layoutConfig.ts +52 -0
  21. package/src/framework/config/themeConfig.ts +449 -14
  22. package/src/framework/fields/BaseRemoteSelect/index.tsx +4 -4
  23. package/src/framework/fields/FieldDateRange/index.tsx +1 -1
  24. package/src/framework/fields/FieldDictSelect/index.tsx +1 -1
  25. package/src/framework/fields/FieldEditor/index.tsx +2 -2
  26. package/src/framework/fields/FieldNumberRange/index.tsx +1 -1
  27. package/src/framework/fields/FieldUploadFile/index.tsx +3 -3
  28. package/src/framework/fields/FieldUploadImage/index.tsx +19 -19
  29. package/src/framework/fields/FieldUserPicker/index.tsx +124 -0
  30. package/src/framework/fields/index.ts +1 -0
  31. package/src/framework/utils/HttpClient.ts +15 -4
  32. package/src/framework/utils/MessageApi.ts +16 -3
  33. package/src/framework/utils/UrlUtils.ts +1 -1
  34. package/src/framework/views/ViewText/index.tsx +1 -1
  35. package/src/layouts/admin/AdminTabs.less +11 -11
  36. package/src/layouts/admin/HeaderRight.jsx +23 -12
  37. package/src/layouts/admin/SinglePageLayout.jsx +36 -0
  38. package/src/layouts/admin/TabLayout.jsx +21 -1
  39. package/src/layouts/admin/index.jsx +46 -26
  40. package/src/layouts/admin/index.less +68 -24
  41. package/src/layouts/index.tsx +29 -4
  42. package/src/pages/article/$code.jsx +2 -2
  43. package/src/pages/article/article.less +13 -13
  44. package/src/pages/index.jsx +1 -1
  45. package/src/pages/public/login.jsx +29 -15
  46. package/src/pages/public/login.less +243 -22
  47. package/src/pages/standalone/forceUpdatePwd.jsx +8 -7
  48. package/src/pages/system/article/index.jsx +13 -15
  49. package/src/pages/system/codegen/index.jsx +54 -51
  50. package/src/pages/system/dict/index.jsx +2 -2
  51. package/src/pages/system/file/index.jsx +3 -3
  52. package/src/pages/system/job/index.jsx +57 -20
  53. package/src/pages/system/log/index.jsx +2 -2
  54. package/src/pages/system/org/index.jsx +5 -5
  55. package/src/pages/system/role/index.jsx +28 -55
  56. package/src/pages/system/role/rolePerm.jsx +1 -1
  57. package/src/pages/system/user/index.jsx +7 -11
  58. package/src/pages/system/user/userPerm.jsx +5 -5
  59. package/src/pages/userCenter/permView.jsx +2 -2
  60. package/src/style/global.less +6 -6
@@ -1,4 +1,6 @@
1
1
  .login-page {
2
+ /* 背景图加载前的兜底底色,保证白色文字始终可读 */
3
+ background-color: #16233f;
2
4
  background-size: cover;
3
5
  background-repeat: no-repeat;
4
6
  background-position: bottom;
@@ -6,47 +8,266 @@
6
8
  width: 100vw;
7
9
  height: 100vh;
8
10
 
9
-
10
11
  .login-content {
11
- padding: 40px;
12
- background: #15184b44;
13
- width: 350px;
12
+ /* 面板内复用的局部变量,统一玻璃质感与文字层级 */
13
+ --login-text: rgba(255, 255, 255, 0.94);
14
+ --login-text-dim: rgba(255, 255, 255, 0.6);
15
+ --login-hairline: rgba(255, 255, 255, 0.16);
16
+ --login-field-bg: rgba(255, 255, 255, 0.08);
17
+ --login-radius: calc(var(--oa-border-radius, 6px) + 10px);
18
+ --login-field-radius: calc(var(--oa-border-radius, 6px) + 2px);
19
+
20
+ box-sizing: border-box;
21
+ width: 384px;
22
+ max-width: calc(100vw - 48px);
23
+ max-height: calc(100vh - 48px);
24
+ overflow: auto;
14
25
  position: fixed;
15
26
  right: 15%;
16
- top: 20%;
27
+ /* 垂直居中,矮屏下不再溢出 */
28
+ top: 50%;
29
+ transform: translateY(-50%);
30
+ padding: 40px 36px 30px;
31
+
32
+ /* 深色磨砂玻璃:主题深色底(保证层次)+ 顶部主色微光 + backdrop-filter 虚化 */
33
+ background-color: color-mix(in srgb, var(--oa-sider-bg, #0b1220) 55%, transparent);
34
+ background-image: linear-gradient(
35
+ 180deg,
36
+ color-mix(in srgb, var(--primary-color, #1677ff) 16%, transparent) 0%,
37
+ transparent 140px
38
+ );
39
+ backdrop-filter: blur(20px) saturate(140%);
40
+ -webkit-backdrop-filter: blur(20px) saturate(140%);
41
+ /* 细描边沿用主题主色;顶边内高光模拟玻璃反光 */
42
+ border: 1px solid color-mix(in srgb, var(--primary-color, #1677ff) 26%, var(--login-hairline));
43
+ border-radius: var(--login-radius);
44
+ box-shadow: 0 24px 64px -20px rgba(0, 0, 0, 0.6),
45
+ 0 4px 16px rgba(0, 0, 0, 0.25),
46
+ inset 0 1px 0 rgba(255, 255, 255, 0.14);
17
47
 
18
- .ant-form-item-label > label{
19
- color: white;
48
+ animation: login-panel-in 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
49
+
50
+ .ant-form-item-label > label {
51
+ color: var(--login-text);
52
+ /* 玻璃更透明后,浅色文字加轻微阴影保证可读性 */
53
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
20
54
  }
21
55
  }
22
56
  }
23
57
 
24
- @media screen and (max-width: 768px) {
25
- .login-page {
26
- padding-top: 30%;
58
+ /* 面板入场:轻微上浮淡入 */
59
+ @keyframes login-panel-in {
60
+ from {
61
+ opacity: 0;
62
+ transform: translateY(calc(-50% + 16px));
63
+ }
64
+ to {
65
+ opacity: 1;
66
+ transform: translateY(-50%);
67
+ }
68
+ }
27
69
 
28
- .login-content {
29
- width: calc(100% - 100px);
30
- padding: 24px;
31
- position: static;
32
- margin: 0 auto;
70
+ /* 不支持 backdrop-filter 的浏览器:提高底色不透明度,保证白字对比度 */
71
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
72
+ .login-page .login-content {
73
+ background-color: color-mix(in srgb, var(--oa-sider-bg, #0b1220) 92%, transparent);
74
+ }
75
+ }
76
+
77
+ /* 品牌区:logo + 站点标题,与后台侧栏保持同一品牌识别 */
78
+ .login-brand {
79
+ margin-bottom: 26px;
80
+ text-align: center;
81
+
82
+ .login-brand-logo {
83
+ display: grid;
84
+ place-items: center;
85
+ width: 56px;
86
+ height: 56px;
87
+ margin: 0 auto 14px;
88
+ border-radius: var(--login-radius);
89
+ background: color-mix(in srgb, var(--primary-color, #1677ff) 16%, rgba(255, 255, 255, 0.06));
90
+ border: 1px solid var(--login-hairline);
91
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
92
+
93
+ img {
94
+ width: 38px;
95
+ height: 38px;
96
+ object-fit: contain;
97
+ }
98
+
99
+ /* logo 加载失败时回退到此矢量标记 */
100
+ .anticon {
101
+ color: var(--login-text);
102
+ font-size: 26px;
33
103
  }
34
104
  }
35
105
  }
36
106
 
107
+ .login-page.login-page h1 {
108
+ margin: 0;
109
+ text-align: center;
110
+ color: var(--login-text);
111
+ font-size: 22px;
112
+ font-weight: 600;
113
+ letter-spacing: 0.5px;
114
+ line-height: 1.4;
115
+ text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
116
+ }
37
117
 
118
+ /* 表单:占满面板,输入框改为玻璃质感并跟随主题主色聚焦 */
38
119
  .login-form {
39
- max-width: 300px;
40
- margin: 0 auto;
41
- }
120
+ width: 100%;
121
+ margin: 0;
42
122
 
123
+ .ant-form-item {
124
+ margin-bottom: 18px;
125
+ }
43
126
 
127
+ .ant-input-affix-wrapper {
128
+ height: 46px;
129
+ padding: 0 14px;
130
+ border-radius: var(--login-field-radius);
131
+ background-color: var(--login-field-bg);
132
+ border: 1px solid var(--login-hairline);
133
+ box-shadow: none;
134
+ transition: background-color 0.2s, border-color 0.2s, box-shadow 0.2s;
44
135
 
136
+ &:hover {
137
+ background-color: rgba(255, 255, 255, 0.12);
138
+ border-color: rgba(255, 255, 255, 0.28);
139
+ }
45
140
 
46
- .login-page.login-page h1 {
47
- margin-bottom: 50px;
141
+ &:focus-within,
142
+ &.ant-input-affix-wrapper-focused {
143
+ background-color: rgba(255, 255, 255, 0.14);
144
+ border-color: var(--primary-color, #1677ff);
145
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color, #1677ff) 28%, transparent);
146
+ }
147
+
148
+ .ant-input-prefix {
149
+ margin-inline-end: 10px;
150
+ color: rgba(255, 255, 255, 0.55);
151
+ font-size: 16px;
152
+ }
153
+
154
+ /* 密码可见性切换按钮 */
155
+ .ant-input-suffix {
156
+ color: rgba(255, 255, 255, 0.55);
157
+ }
158
+ }
159
+
160
+ .ant-input {
161
+ color: var(--login-text);
162
+ font-size: 15px;
163
+ background: transparent;
164
+
165
+ &::placeholder {
166
+ color: var(--login-text-dim);
167
+ }
168
+
169
+ /* 浏览器自动填充时保持玻璃底与浅色文字 */
170
+ &:-webkit-autofill {
171
+ -webkit-text-fill-color: var(--login-text);
172
+ caret-color: var(--login-text);
173
+ transition: background-color 9999s ease-out;
174
+ }
175
+ }
176
+
177
+ .ant-form-item-explain-error {
178
+ margin-top: 4px;
179
+ color: color-mix(in srgb, var(--oa-color-error, #ff4d4f) 55%, #fff);
180
+ font-size: 13px;
181
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
182
+ }
183
+
184
+ /* 提交按钮:主色渐变 + 悬浮辉光,作为面板唯一强视觉锚点 */
185
+ .login-submit {
186
+ margin-bottom: 0;
187
+
188
+ .ant-btn-primary {
189
+ height: 46px;
190
+ border: none;
191
+ border-radius: var(--login-field-radius);
192
+ font-size: 16px;
193
+ font-weight: 600;
194
+ letter-spacing: 0.3em;
195
+ text-indent: 0.3em;
196
+ background: linear-gradient(
197
+ 135deg,
198
+ var(--primary-color, #1677ff),
199
+ var(--primary-color-hover, #4096ff)
200
+ );
201
+ box-shadow: 0 12px 26px -12px color-mix(in srgb, var(--primary-color, #1677ff) 85%, transparent);
202
+ transition: filter 0.2s, box-shadow 0.2s, transform 0.16s;
203
+
204
+ &:hover:not(:disabled) {
205
+ filter: brightness(1.07);
206
+ box-shadow: 0 16px 32px -12px color-mix(in srgb, var(--primary-color, #1677ff) 95%, transparent);
207
+ }
208
+
209
+ &:active:not(:disabled) {
210
+ transform: translateY(1px);
211
+ filter: brightness(0.98);
212
+ }
213
+ }
214
+ }
215
+ }
216
+
217
+ /* 校验失败态:描边与文案提亮到深色玻璃上仍可读。
218
+ 多加 .login-page 提升特异性,盖过 antd 聚焦态注入的白底 */
219
+ .login-page .login-form .ant-form-item-has-error {
220
+ .ant-input-affix-wrapper,
221
+ .ant-input-affix-wrapper:hover,
222
+ .ant-input-affix-wrapper:focus,
223
+ .ant-input-affix-wrapper:focus-within {
224
+ background-color: color-mix(in srgb, var(--oa-color-error, #ff4d4f) 12%, transparent);
225
+ border-color: color-mix(in srgb, var(--oa-color-error, #ff4d4f) 70%, transparent);
226
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--oa-color-error, #ff4d4f) 24%, transparent);
227
+ }
228
+
229
+ .ant-input {
230
+ background-color: transparent;
231
+ }
232
+ }
233
+
234
+ /* 登录框底部提示:与表单之间用分隔线区隔,保持次要文字层级 */
235
+ .login-bottom-tip {
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ gap: 8px;
240
+ margin-top: 22px;
241
+ padding-top: 18px;
242
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
243
+ color: var(--login-text-dim);
244
+ font-size: 13px;
245
+ line-height: 1.5;
48
246
  text-align: center;
49
- color: white;
50
- font-size: x-large;
247
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
248
+
249
+ .anticon {
250
+ flex: none;
251
+ }
51
252
  }
52
253
 
254
+ @media (prefers-reduced-motion: reduce) {
255
+ .login-page .login-content {
256
+ animation: none;
257
+ }
258
+ }
259
+
260
+ @media screen and (max-width: 768px) {
261
+ .login-page {
262
+ padding-top: 20%;
263
+
264
+ .login-content {
265
+ width: calc(100% - 64px);
266
+ padding: 28px 22px;
267
+ position: static;
268
+ margin: 0 auto;
269
+ transform: none;
270
+ animation: none;
271
+ }
272
+ }
273
+ }
@@ -1,12 +1,12 @@
1
1
  import React from "react";
2
- import {Button, Form, Input, message} from "antd";
3
- import {HttpClient, history} from "../../framework";
2
+ import {Button, Form, Input} from "antd";
3
+ import {getMessageApi, getToken, HttpClient, history} from "../../framework";
4
4
 
5
5
  export default class ForceUpdatePwdPage extends React.Component {
6
6
 
7
7
  onFinish = (values) => {
8
8
  HttpClient.post('admin/userCenter/update-pwd', values, null).then(() => {
9
- message.success('修改密码成功,请重新登录');
9
+ getMessageApi().success('修改密码成功,请重新登录');
10
10
  history.push('/public/login');
11
11
  })
12
12
  }
@@ -17,24 +17,25 @@ export default class ForceUpdatePwdPage extends React.Component {
17
17
  })
18
18
 
19
19
  render() {
20
+ const token = getToken();
20
21
  return (
21
22
  <div style={{
22
23
  display: 'flex',
23
24
  justifyContent: 'center',
24
25
  alignItems: 'center',
25
26
  minHeight: '100vh',
26
- background: '#f0f2f5'
27
+ background: String(token.colorBgLayout)
27
28
  }}>
28
29
  <div style={{
29
- background: '#fff',
30
+ background: String(token.colorBgContainer),
30
31
  padding: '40px',
31
32
  borderRadius: '8px',
32
- boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
33
+ boxShadow: String(token.boxShadowSecondary ?? '0 2px 8px rgba(0,0,0,0.1)'),
33
34
  maxWidth: 400,
34
35
  width: '100%'
35
36
  }}>
36
37
  <h2 style={{textAlign: 'center', marginBottom: 24}}>修改密码</h2>
37
- <p style={{textAlign: 'center', color: '#999', marginBottom: 24}}>
38
+ <p style={{textAlign: 'center', color: String(token.colorTextTertiary), marginBottom: 24}}>
38
39
  首次登录或密码已被重置,请修改密码后重新登录
39
40
  </p>
40
41
  <Form onFinish={this.onFinish}>
@@ -1,5 +1,5 @@
1
- import {PlusOutlined} from '@ant-design/icons'
2
- import {Button, Form, Input, InputNumber} from 'antd'
1
+ import {PlusOutlined, SearchOutlined} from '@ant-design/icons'
2
+ import {Form, Input, InputNumber} from 'antd'
3
3
  import React from 'react'
4
4
  import {
5
5
  DictUtils,
@@ -106,26 +106,24 @@ export default class ArticleListPage extends React.Component {
106
106
  ]
107
107
 
108
108
  render() {
109
- return <Page
110
- title="文章管理"
111
- description="管理系统文章,如关于、帮助等页面"
112
- >
109
+ return <Page>
113
110
  <ProTable
114
111
  actionRef={this.tableRef}
115
- toolBarRender={() => ( // NOSONAR: AntD 渲染函数惯例
116
- <PermActions>
117
- <Button perm='article:create' type='primary' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>
118
- </PermActions>
112
+ searchInline
113
+ toolBarRightRender={() => (
114
+ <PermActions actions={[
115
+ {label: '新增', type: 'primary', icon: <PlusOutlined/>, perm: 'article:create', onClick: this.handleAdd},
116
+ ]}/>
119
117
  )}
120
118
  request={(params) => HttpClient.get('admin/article/page', params)}
121
119
  columns={this.columns}
122
- searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
120
+ searchFormRender={() => (
123
121
  <>
124
- <Form.Item label='编码' name='code'>
125
- <Input/>
122
+ <Form.Item name='code' noStyle>
123
+ <Input prefix={<SearchOutlined/>} placeholder='文章编码' allowClear/>
126
124
  </Form.Item>
127
- <Form.Item label='标题' name='title'>
128
- <Input/>
125
+ <Form.Item name='title' noStyle>
126
+ <Input placeholder='文章标题' allowClear/>
129
127
  </Form.Item>
130
128
  </>
131
129
  )}
@@ -1,6 +1,6 @@
1
- import {Button, Collapse, Drawer, Form, Input, message, Modal, Select, Space, Switch, Tag, Typography} from 'antd'
1
+ import {Button, Card, Collapse, Drawer, Form, Input, Modal, Select, Space, Switch, Tag, Typography} from 'antd'
2
2
  import React from 'react'
3
- import {HttpClient, Page, Perm} from '../../../framework'
3
+ import {HttpClient, getMessageApi, getToken, Page, Perm} from '../../../framework'
4
4
 
5
5
  /**
6
6
  * 代码生成:动态扫描实体,按实体生成常见 CRUD 代码并写入项目源码目录。
@@ -52,7 +52,7 @@ export default class CodegenPage extends React.Component {
52
52
 
53
53
  handlePreview = () => {
54
54
  if (!this.state.className) {
55
- message.warning('请先选择实体')
55
+ getMessageApi().warning('请先选择实体')
56
56
  return
57
57
  }
58
58
  this.setState({loading: true})
@@ -60,13 +60,13 @@ export default class CodegenPage extends React.Component {
60
60
  this.setState({files: rs.data || [], previewOpen: true})
61
61
  }).catch(e => {
62
62
  console.error('[Codegen] 预览失败:', e)
63
- message.error(e?.message || '预览失败')
63
+ getMessageApi().error(e?.message || '预览失败')
64
64
  }).finally(() => this.setState({loading: false}))
65
65
  }
66
66
 
67
67
  handleGenerate = () => {
68
68
  if (!this.state.className) {
69
- message.warning('请先选择实体')
69
+ getMessageApi().warning('请先选择实体')
70
70
  return
71
71
  }
72
72
  this.setState({confirmOpen: true})
@@ -78,17 +78,17 @@ export default class CodegenPage extends React.Component {
78
78
  this.setState({result: rs.data, resultOpen: true, previewOpen: false})
79
79
  }).catch(e => {
80
80
  console.error('[Codegen] 生成失败:', e)
81
- message.error(e?.message || '生成失败')
81
+ getMessageApi().error(e?.message || '生成失败')
82
82
  }).finally(() => this.setState({loading: false}))
83
83
  }
84
84
 
85
85
  copy = (text) => {
86
86
  if (navigator.clipboard) {
87
87
  navigator.clipboard.writeText(text)
88
- .then(() => message.success('已复制'))
89
- .catch(() => message.error('复制失败'))
88
+ .then(() => getMessageApi().success('已复制'))
89
+ .catch(() => getMessageApi().error('复制失败'))
90
90
  } else {
91
- message.warning('当前浏览器不支持剪贴板')
91
+ getMessageApi().warning('当前浏览器不支持剪贴板')
92
92
  }
93
93
  }
94
94
 
@@ -96,47 +96,50 @@ export default class CodegenPage extends React.Component {
96
96
 
97
97
  render() {
98
98
  const selected = this.selectedOption()
99
- return <Page title='代码生成' description='扫描实体,生成 Repository / Service / Controller / 前端页面 / 菜单 代码并写入项目源码目录'>
100
- <Form layout='vertical' style={{maxWidth: 720}}>
101
- <Form.Item label='实体' required>
102
- <Select
103
- showSearch
104
- optionFilterProp='label'
105
- placeholder='请选择实体'
106
- options={this.state.entities}
107
- value={this.state.className}
108
- onChange={this.handleEntityChange}
109
- />
110
- </Form.Item>
111
- {selected?.data?.frameworkEntity &&
112
- <Typography.Text type='warning'>
113
- 该实体属于框架内置包({selected.data.packageName}),生成的文件会写入同一包路径,请确认输出位置后再生成。
114
- </Typography.Text>
115
- }
116
- <Form.Item label='模块名(请求前缀 / 前端目录)'>
117
- <Input placeholder='如 customer'
118
- value={this.state.module}
119
- onChange={e => this.setState({module: e.target.value})}/>
120
- </Form.Item>
121
- <Form.Item label='中文名'>
122
- <Input value={this.state.label}
123
- onChange={e => this.setState({label: e.target.value})}/>
124
- </Form.Item>
125
- <Form.Item label='父菜单 id' tooltip='默认挂在系统管理(sys)下'>
126
- <Input value={this.state.parentMenu}
127
- onChange={e => this.setState({parentMenu: e.target.value})}/>
128
- </Form.Item>
129
- <Form.Item label='覆盖已存在文件'>
130
- <Switch checked={this.state.overwrite}
131
- onChange={checked => this.setState({overwrite: checked})}/>
132
- </Form.Item>
133
- <Space>
134
- <Perm code='sys-codegen:generate'>
135
- <Button type='primary' loading={this.state.loading} onClick={this.handlePreview}>预览</Button>
136
- </Perm>
137
- <Button onClick={this.loadEntities}>刷新实体</Button>
138
- </Space>
139
- </Form>
99
+ return <Page actions={
100
+ <Space>
101
+ <Perm code='sys-codegen:generate'>
102
+ <Button type='primary' loading={this.state.loading} onClick={this.handlePreview}>预览</Button>
103
+ </Perm>
104
+ <Button onClick={this.loadEntities}>刷新实体</Button>
105
+ </Space>
106
+ }>
107
+ <Card size='small'>
108
+ <Form layout='vertical' style={{maxWidth: 720}}>
109
+ <Form.Item label='实体' required>
110
+ <Select
111
+ showSearch
112
+ optionFilterProp='label'
113
+ placeholder='请选择实体'
114
+ options={this.state.entities}
115
+ value={this.state.className}
116
+ onChange={this.handleEntityChange}
117
+ />
118
+ </Form.Item>
119
+ {selected?.data?.frameworkEntity &&
120
+ <Typography.Text type='warning'>
121
+ 该实体属于框架内置包({selected.data.packageName}),生成的文件会写入同一包路径,请确认输出位置后再生成。
122
+ </Typography.Text>
123
+ }
124
+ <Form.Item label='模块名(请求前缀 / 前端目录)'>
125
+ <Input placeholder='如 customer'
126
+ value={this.state.module}
127
+ onChange={e => this.setState({module: e.target.value})}/>
128
+ </Form.Item>
129
+ <Form.Item label='中文名'>
130
+ <Input value={this.state.label}
131
+ onChange={e => this.setState({label: e.target.value})}/>
132
+ </Form.Item>
133
+ <Form.Item label='父菜单 id' tooltip='默认挂在系统管理(sys)下'>
134
+ <Input value={this.state.parentMenu}
135
+ onChange={e => this.setState({parentMenu: e.target.value})}/>
136
+ </Form.Item>
137
+ <Form.Item label='覆盖已存在文件'>
138
+ <Switch checked={this.state.overwrite}
139
+ onChange={checked => this.setState({overwrite: checked})}/>
140
+ </Form.Item>
141
+ </Form>
142
+ </Card>
140
143
 
141
144
  <Drawer title='生成预览' width={960}
142
145
  open={this.state.previewOpen}
@@ -164,7 +167,7 @@ export default class CodegenPage extends React.Component {
164
167
  <pre style={{
165
168
  maxHeight: 420,
166
169
  overflow: 'auto',
167
- background: '#f6f8fa',
170
+ background: String(getToken().colorFillTertiary ?? '#f6f8fa'),
168
171
  padding: 12,
169
172
  borderRadius: 4,
170
173
  }}>{file.content}</pre>
@@ -164,7 +164,7 @@ export default class DictPage extends React.Component {
164
164
  const {selectedType, selectedTypeCode} = this.state
165
165
  const hasTypeSelected = selectedType != null && selectedTypeCode != null
166
166
 
167
- return <Page title="数据字典" description="管理数据字典类型和字典项">
167
+ return <Page>
168
168
  <Splitter>
169
169
  <Splitter.Panel defaultSize={300} style={{paddingRight: 8}}>
170
170
  <Card loading={this.state.treeLoading}
@@ -269,7 +269,7 @@ export default class DictPage extends React.Component {
269
269
  allowClear
270
270
  maxLength={20}
271
271
  options={COLOR_OPTIONS}
272
- filterOption={(input, option) => // NOSONAR: AntD AutoComplete 过滤回调惯例
272
+ filterOption={(input, option) =>
273
273
  (option.value + option.label).toLowerCase().includes(input.toLowerCase())
274
274
  }
275
275
  placeholder='如 SUCCESS、#ff0000'
@@ -32,7 +32,7 @@ export default class FilePage extends React.Component {
32
32
  title: '缩略图',
33
33
  dataIndex: 'objectName',
34
34
  width: 80,
35
- render: (objectName, record) => { // NOSONAR: 返回元素或占位文本,类型不同属预期
35
+ render: (objectName, record) => {
36
36
  if (record.type !== 'image') {
37
37
  return '-'
38
38
  }
@@ -151,7 +151,7 @@ export default class FilePage extends React.Component {
151
151
  <ProTable
152
152
  actionRef={this.tableRef}
153
153
  rowSelection={{}}
154
- toolBarRender={(params, selection) => ( // NOSONAR: AntD 渲染函数惯例
154
+ toolBarRightRender={(params, selection) => (
155
155
  <Space>
156
156
  <Button type='primary' icon={<CloudUploadOutlined/>} onClick={() => this.setState({formOpen: true})}>上传文件</Button>
157
157
  <PermActions
@@ -171,7 +171,7 @@ export default class FilePage extends React.Component {
171
171
  }}
172
172
 
173
173
  columns={this.columns}
174
- searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
174
+ searchFormRender={() => (
175
175
  <>
176
176
  <Form.Item label='文件名' name='originName'>
177
177
  <Input/>