@jiangood/open-admin 3.1.7 → 3.1.9

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 (45) hide show
  1. package/package.json +1 -1
  2. package/src/framework/GlobalData.ts +2 -0
  3. package/src/framework/biz/OrgTree.tsx +4 -0
  4. package/src/framework/biz/PermActions.tsx +1 -1
  5. package/src/framework/biz/RoleTree.tsx +4 -0
  6. package/src/framework/components/DownloadModal/index.tsx +10 -3
  7. package/src/framework/components/FormModal/index.tsx +4 -4
  8. package/src/framework/components/LogViewer/index.tsx +249 -0
  9. package/src/framework/components/NamedIcon/index.tsx +1 -1
  10. package/src/framework/components/Page/index.less +2 -0
  11. package/src/framework/components/Page/index.tsx +21 -13
  12. package/src/framework/components/PageLoading/index.tsx +2 -2
  13. package/src/framework/components/ProTable/index.less +44 -0
  14. package/src/framework/components/ProTable/index.tsx +54 -13
  15. package/src/framework/components/index.ts +1 -0
  16. package/src/framework/config/themeConfig.ts +30 -6
  17. package/src/framework/fields/BaseRemoteSelect/index.tsx +4 -4
  18. package/src/framework/fields/FieldDateRange/index.tsx +1 -1
  19. package/src/framework/fields/FieldDictSelect/index.tsx +1 -1
  20. package/src/framework/fields/FieldNumberRange/index.tsx +1 -1
  21. package/src/framework/fields/FieldTable/styles.less +3 -3
  22. package/src/framework/fields/FieldUploadImage/index.tsx +4 -4
  23. package/src/framework/utils/HttpClient.ts +63 -25
  24. package/src/framework/utils/UrlUtils.ts +1 -1
  25. package/src/layouts/admin/AdminTabs.jsx +35 -1
  26. package/src/layouts/admin/AdminTabs.less +28 -7
  27. package/src/layouts/admin/index.jsx +1 -1
  28. package/src/layouts/admin/index.less +25 -1
  29. package/src/layouts/index.tsx +47 -10
  30. package/src/pages/article/$code.jsx +2 -2
  31. package/src/pages/index.jsx +1 -1
  32. package/src/pages/system/article/index.jsx +13 -15
  33. package/src/pages/system/codegen/index.jsx +1 -3
  34. package/src/pages/system/dict/index.jsx +2 -2
  35. package/src/pages/system/file/index.jsx +3 -3
  36. package/src/pages/system/job/index.jsx +151 -40
  37. package/src/pages/system/log/index.jsx +2 -2
  38. package/src/pages/system/org/index.jsx +5 -5
  39. package/src/pages/system/role/index.jsx +12 -13
  40. package/src/pages/system/role/rolePerm.jsx +1 -1
  41. package/src/pages/system/user/index.jsx +7 -7
  42. package/src/pages/system/user/userPerm.jsx +2 -2
  43. package/src/pages/userCenter/index.jsx +1 -1
  44. package/src/pages/userCenter/permView.jsx +2 -2
  45. package/src/style/global.less +2 -2
@@ -4,7 +4,7 @@ import {Page} from "../framework";
4
4
 
5
5
  export default class HomePage extends React.Component {
6
6
  render() {
7
- return <Page title="首页" description="欢迎使用本系统">
7
+ return <Page>
8
8
  <Card>欢迎使用本系统</Card>
9
9
  </Page>
10
10
  }
@@ -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
  )}
@@ -96,9 +96,7 @@ export default class CodegenPage extends React.Component {
96
96
 
97
97
  render() {
98
98
  const selected = this.selectedOption()
99
- return <Page title='代码生成'
100
- description='扫描实体,生成 Repository / Service / Controller / 前端页面 / 菜单 代码并写入项目源码目录'
101
- actions={
99
+ return <Page actions={
102
100
  <Space>
103
101
  <Perm code='sys-codegen:generate'>
104
102
  <Button type='primary' loading={this.state.loading} onClick={this.handlePreview}>预览</Button>
@@ -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/>
@@ -2,18 +2,18 @@ import React from 'react'
2
2
  import {
3
3
  Alert,
4
4
  AutoComplete,
5
- Button,
6
5
  Divider,
7
6
  Form,
8
7
  Input,
9
8
  Modal,
9
+ Progress,
10
10
  Select,
11
- Spin,
12
11
  Switch,
13
- Tag
12
+ Tag,
13
+ Tooltip
14
14
  } from 'antd'
15
- import {PlusOutlined} from "@ant-design/icons";
16
- import {FormModal, getMessageApi, HttpClient, Page, PermActions, ProTable, UrlUtils, ValueType} from "../../../framework";
15
+ import {PlusOutlined, SearchOutlined} from "@ant-design/icons";
16
+ import {FormModal, DictUtils, FieldDictSelect, getMessageApi, HttpClient, LogViewer, Page, PermActions, ProTable, UrlUtils, ValueType} from "../../../framework";
17
17
 
18
18
 
19
19
  const cronOptions = [
@@ -55,11 +55,12 @@ export default class JobPage extends React.Component {
55
55
  executeRecordOpen: false,
56
56
 
57
57
  logOpen: false,
58
- logLoading: false,
59
- logContent: '',
58
+
59
+ progressMap: {},
60
60
  }
61
61
  tableRef = React.createRef()
62
62
  modalRef = React.createRef()
63
+ progressTimer = null
63
64
 
64
65
  componentDidMount() {
65
66
  HttpClient.get('admin/job/job-class-options', null, {toastError: false}).then(rs => {
@@ -67,6 +68,39 @@ export default class JobPage extends React.Component {
67
68
  }).catch(e => {
68
69
  console.error('[Job] 加载任务类选项失败:', e);
69
70
  })
71
+ this.startProgressPolling()
72
+ }
73
+
74
+ componentWillUnmount() {
75
+ this.stopProgressPolling()
76
+ }
77
+
78
+ startProgressPolling = () => {
79
+ this.loadProgress()
80
+ this.progressTimer = setInterval(() => {
81
+ if (!document.hidden) {
82
+ this.loadProgress()
83
+ }
84
+ }, 3000)
85
+ }
86
+
87
+ stopProgressPolling = () => {
88
+ if (this.progressTimer) {
89
+ clearInterval(this.progressTimer)
90
+ this.progressTimer = null
91
+ }
92
+ }
93
+
94
+ loadProgress = () => {
95
+ HttpClient.get('admin/job/progress', null, {toastError: false}).then(rs => {
96
+ const progressMap = {}
97
+ ;(rs.data || []).forEach(p => {
98
+ progressMap[p.jobId] = p
99
+ })
100
+ this.setState({progressMap})
101
+ }).catch(e => {
102
+ console.error('[Job] 加载任务进度失败:', e);
103
+ })
70
104
  }
71
105
 
72
106
  handleAdd = () => {
@@ -108,6 +142,7 @@ export default class JobPage extends React.Component {
108
142
  handleTriggerJob = row => {
109
143
  HttpClient.post('admin/job/trigger-job', {id: row.id}, null, {toastError: false}).then(() => {
110
144
  this.tableRef.current.reload();
145
+ this.loadProgress()
111
146
  }).catch(e => {
112
147
  console.error('[Job] 触发任务失败:', e);
113
148
  })
@@ -148,6 +183,38 @@ export default class JobPage extends React.Component {
148
183
  },
149
184
  },
150
185
 
186
+ {
187
+ title: '日志聚合',
188
+ dataIndex: 'logAggregation',
189
+ render: v => DictUtils.dictTag('jobLogAggregation', v) || '每次执行',
190
+ },
191
+
192
+ {
193
+ title: '运行状态',
194
+ dataIndex: 'progress',
195
+ width: 220,
196
+ render: (_, record) => {
197
+ const p = this.state.progressMap[record.id]
198
+ if (!p) {
199
+ return <Tag>未运行</Tag>
200
+ }
201
+ return <div>
202
+ <Tag color={p.stateColor || 'default'}>{p.stateLabel}</Tag>
203
+ {p.percent != null && <Progress percent={p.percent} size='small'/>}
204
+ {p.message && <Tooltip title={p.message}>
205
+ <div style={{
206
+ fontSize: 12,
207
+ color: 'var(--oa-color-text-secondary, rgba(0, 0, 0, 0.65))',
208
+ overflow: 'hidden',
209
+ textOverflow: 'ellipsis',
210
+ whiteSpace: 'nowrap',
211
+ maxWidth: 200
212
+ }}>{p.message}</div>
213
+ </Tooltip>}
214
+ </div>
215
+ },
216
+ },
217
+
151
218
  {
152
219
  title: '操作',
153
220
  dataIndex: 'option',
@@ -180,19 +247,43 @@ export default class JobPage extends React.Component {
180
247
 
181
248
  showExecuteRecord(record) {
182
249
  this.setState({executeRecordOpen: true, selectedRecord: record})
250
+ this.loadProgress()
251
+ }
252
+
253
+ /**
254
+ * 执行记录弹窗顶部:当前任务的运行中进度(内存态)
255
+ */
256
+ renderRunningProgress() {
257
+ const {selectedRecord, progressMap} = this.state
258
+ const p = selectedRecord ? progressMap[selectedRecord.id] : null
259
+ if (!p || p.state !== 'RUNNING') {
260
+ return null
261
+ }
262
+ return <Alert
263
+ type='info'
264
+ showIcon
265
+ style={{marginBottom: 12}}
266
+ title={<div>
267
+ <div style={{marginBottom: 6}}>{p.message || '任务运行中'}</div>
268
+ {p.percent != null && <Progress percent={p.percent} size='small'/>}
269
+ </div>}
270
+ />
183
271
  }
184
272
 
185
273
  showLog = (record) => {
186
- this.setState({logOpen: true, logLoading: true, logContent: '', selectedLogRecord: record})
187
- HttpClient.get('admin/sys/log/job/' + record.id, null, {toastError: false}).then(content => {
188
- this.setState({
189
- logContent: typeof content === 'string' ? content : JSON.stringify(content),
190
- logLoading: false
191
- })
192
- }).catch(e => {
193
- console.error('[Job] 加载任务日志失败:', e)
194
- this.setState({logContent: '日志加载失败:' + (e?.message || ''), logLoading: false})
195
- })
274
+ this.setState({logOpen: true, selectedLogRecord: record})
275
+ }
276
+
277
+ /**
278
+ * 该执行记录对应的日志是否仍在写入:用进度快照里的 logId 精确匹配
279
+ */
280
+ isLogRunning = () => {
281
+ const {selectedLogRecord, progressMap} = this.state
282
+ if (!selectedLogRecord) {
283
+ return false
284
+ }
285
+ return Object.values(progressMap).some(p =>
286
+ p.logId === selectedLogRecord.id && p.state === 'RUNNING')
196
287
  }
197
288
 
198
289
 
@@ -200,21 +291,22 @@ export default class JobPage extends React.Component {
200
291
  return <Page>
201
292
  <ProTable
202
293
  actionRef={this.tableRef}
203
- toolBarRender={() => ( // NOSONAR: AntD 渲染函数惯例
204
- <PermActions>
205
- <Button type='primary' perm='job:create' icon={<PlusOutlined/>} onClick={() => this.handleAdd()}>新增</Button>
206
- <Button perm='job:read' onClick={this.showStatus}>查看状态</Button>
207
- </PermActions>
294
+ searchInline
295
+ toolBarRightRender={() => (
296
+ <PermActions actions={[
297
+ {label: '新增', type: 'primary', icon: <PlusOutlined/>, perm: 'job:create', onClick: () => this.handleAdd()},
298
+ {label: '查看状态', perm: 'job:read', onClick: this.showStatus},
299
+ ]}/>
208
300
  )}
209
301
  request={(params) => HttpClient.get('admin/job/page', params)}
210
302
  columns={this.columns}
211
- searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
303
+ searchFormRender={() => (
212
304
  <>
213
- <Form.Item label='名称' name='name'>
214
- <Input/>
305
+ <Form.Item name='name' noStyle>
306
+ <Input prefix={<SearchOutlined/>} placeholder='任务名称' allowClear/>
215
307
  </Form.Item>
216
- <Form.Item label='执行类' name='jobClass'>
217
- <Input/>
308
+ <Form.Item name='jobClass' noStyle>
309
+ <Input placeholder='执行类' allowClear/>
218
310
  </Form.Item>
219
311
  </>
220
312
  )}
@@ -241,6 +333,11 @@ export default class JobPage extends React.Component {
241
333
  <Switch/>
242
334
  </Form.Item>
243
335
 
336
+ <Form.Item label='日志聚合' name='logAggregation' initialValue='PER_RUN'
337
+ help='高频任务建议按天聚合:一天只保留一条执行记录,日志文件按天合并'>
338
+ <FieldDictSelect typeCode='jobLogAggregation'/>
339
+ </Form.Item>
340
+
244
341
  {this.state.paramList?.map(p => (
245
342
  <div key={p.name}>
246
343
  <Divider>任务参数</Divider>
@@ -276,6 +373,7 @@ export default class JobPage extends React.Component {
276
373
  width={1024}
277
374
  destroyOnHidden
278
375
  >
376
+ {this.renderRunningProgress()}
279
377
  <ProTable columns={[{
280
378
  title: '开始时间',
281
379
  dataIndex: 'beginTime',
@@ -289,6 +387,24 @@ export default class JobPage extends React.Component {
289
387
  dataIndex: 'jobRunTimeLabel',
290
388
 
291
389
  },
390
+ {
391
+ title: '执行次数',
392
+ dataIndex: 'executeCount',
393
+ width: 90,
394
+ render: v => v == null ? 1 : v,
395
+ },
396
+ {
397
+ title: '失败次数',
398
+ dataIndex: 'failCount',
399
+ width: 90,
400
+ render: v => (v == null || v === 0) ? '-' : <span style={{color: 'var(--oa-color-error, #ff4d4f)'}}>{v}</span>,
401
+ },
402
+ {
403
+ title: '累计耗时',
404
+ dataIndex: 'totalRunTimeLabel',
405
+ width: 100,
406
+ render: v => v || '-',
407
+ },
292
408
  {
293
409
  title: '是否成功',
294
410
  dataIndex: 'success',
@@ -323,21 +439,16 @@ export default class JobPage extends React.Component {
323
439
  width={1024}
324
440
  destroyOnHidden
325
441
  footer={this.state.selectedLogRecord ? (
326
- <a href={UrlUtils.contextPath('/admin/sys/log/job/' + this.state.selectedLogRecord.id)}
442
+ <a href={UrlUtils.contextPath('/admin/sys/log/raw/job/' + this.state.selectedLogRecord.id)}
327
443
  target='_blank' rel='noreferrer'>在新窗口打开</a>
328
444
  ) : null}
329
445
  >
330
- <Spin spinning={this.state.logLoading}>
331
- <pre style={{
332
- margin: 0,
333
- maxHeight: '60vh',
334
- overflow: 'auto',
335
- whiteSpace: 'pre-wrap',
336
- wordBreak: 'break-all',
337
- fontSize: 12,
338
- lineHeight: 1.6
339
- }}>{this.state.logContent}</pre>
340
- </Spin>
446
+ {this.state.selectedLogRecord && (
447
+ <LogViewer key={this.state.selectedLogRecord.id}
448
+ logKey={'job/' + this.state.selectedLogRecord.id}
449
+ running={this.isLogRunning()}
450
+ height={480}/>
451
+ )}
341
452
  </Modal>
342
453
  </Page>
343
454
  }
@@ -348,7 +459,7 @@ export default class JobPage extends React.Component {
348
459
  const option = this.state.jobClassOptions.find(o => o.value === changed.jobClass)
349
460
  if (option) {
350
461
  const {label} = option;
351
- const match = label.match(/[((](.*?)[))]/); // NOSONAR: 匹配中英文括号内内容,已最简
462
+ const match = label.match(/[((](.*?)[))]/);
352
463
  if (match) { // 取括号内中文描述设置为name
353
464
  this.modalRef.current.formInstance.setFieldValue("name", match[1])
354
465
  }
@@ -53,11 +53,11 @@ export default class LogPage extends React.Component {
53
53
 
54
54
 
55
55
  render() {
56
- return <Page title="操作日志" description="查看系统操作日志">
56
+ return <Page>
57
57
  <ProTable
58
58
  request={(params) => HttpClient.get('admin/sysLog/page', params)}
59
59
  columns={this.columns}
60
- searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
60
+ searchFormRender={() => (
61
61
  <>
62
62
  <Form.Item label='操作' name='operation'>
63
63
  <Input/>
@@ -94,13 +94,13 @@ export default class OrgPage extends React.Component {
94
94
  const params = this.state.params
95
95
  const canSort = PermUtils.hasPermission('sys-org:update')
96
96
 
97
- return <Page title="组织机构" description="管理组织机构树" actions={
98
- <Button type='primary' perm='sys-org:create' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>
99
- }>
97
+ return <Page>
100
98
  <Splitter>
101
99
  <Splitter.Panel defaultSize={400} style={{paddingRight: 8}}>
102
100
 
103
- <Card size='small' >
101
+
102
+ <Card title="机构树" extra={<Button type='primary' perm='sys-org:create'
103
+ icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>}>
104
104
  <div style={{display: 'flex', alignItems: 'center', gap: 4}}>
105
105
  <Input.Search placeholder='搜索' value={params.searchText} onChange={e => {
106
106
  params.searchText = e.target.value
@@ -140,7 +140,7 @@ export default class OrgPage extends React.Component {
140
140
  onSelect={this.onSelect}
141
141
  showIcon
142
142
  blockNode
143
- icon={item => <NamedIcon name={item.data.iconName}/>} // NOSONAR: AntD 渲染函数惯例
143
+ icon={item => <NamedIcon name={item.data.iconName}/>}
144
144
  draggable={this.state.draggable}
145
145
  onDrop={this.onDrop}
146
146
  showLine
@@ -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 {FieldBoolean, FormModal, HttpClient, Page, PageUtils, PermActions, ProTable, UserPicker, ViewText} from "../../../framework";
5
5
 
@@ -133,25 +133,24 @@ export default class RolePage extends React.Component {
133
133
 
134
134
  render() {
135
135
  return <Page
136
- title="角色管理"
137
- description="管理系统角色,包括角色权限分配、用户设置等"
138
136
  >
139
137
  <ProTable
140
138
  actionRef={this.tableRef}
141
- toolBarRender={() => ( // NOSONAR: AntD 渲染函数惯例
142
- <PermActions>
143
- <Button perm='sys-role:create' type='primary' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>
144
- </PermActions>
139
+ toolBarRightRender={() => (
140
+ <PermActions actions={[
141
+ {label: '新增', type: 'primary', icon: <PlusOutlined/>, perm: 'sys-role:create', onClick: this.handleAdd},
142
+ ]}/>
145
143
  )}
146
144
  request={(params) => HttpClient.get('admin/sysRole/page', params)}
147
145
  columns={this.columns}
148
- searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
146
+ searchInline
147
+ searchFormRender={() => (
149
148
  <>
150
- <Form.Item label='角色名称' name='name'>
151
- <Input/>
149
+ <Form.Item name='name' noStyle>
150
+ <Input prefix={<SearchOutlined/>} placeholder='角色名称' allowClear/>
152
151
  </Form.Item>
153
- <Form.Item label='角色编码' name='code'>
154
- <Input/>
152
+ <Form.Item name='code' noStyle>
153
+ <Input placeholder='角色编码' allowClear/>
155
154
  </Form.Item>
156
155
  </>
157
156
  )}
@@ -93,7 +93,7 @@ export default class RolePermPage extends React.Component {
93
93
 
94
94
 
95
95
  render() {
96
- return <Page title="角色权限设置" description="设置角色的菜单和权限">
96
+ return <Page>
97
97
  <Card title='角色权限设置' loading={this.state.loading}
98
98
  variant={"borderless"}
99
99
  extra={<Button type='primary' icon={<SaveOutlined/>} onClick={this.savePerms}>保存权限</Button>}>
@@ -152,9 +152,9 @@ export default class UserPage extends React.Component {
152
152
 
153
153
  render() {
154
154
 
155
- return <Page title="用户管理" description="管理系统用户">
155
+ return <Page >
156
156
  <Splitter>
157
- <Splitter.Panel defaultSize={240} style={{paddingRight: 8}}>
157
+ <Splitter.Panel defaultSize={340} style={{paddingRight: 8}}>
158
158
  <Card size='small'>
159
159
  <OrgTree onChange={this.onSelectOrg}/>
160
160
  </Card>
@@ -163,17 +163,17 @@ export default class UserPage extends React.Component {
163
163
  <ProTable
164
164
  searchFormCols={3}
165
165
  actionRef={this.tableRef}
166
- toolBarRender={() => ( // NOSONAR: AntD 渲染函数惯例
167
- <PermActions>
168
- <Button perm='sys-user:create' type='primary' icon={<PlusOutlined/>} onClick={this.handleAdd}>新增</Button>
169
- </PermActions>
166
+ toolBarRightRender={() => (
167
+ <PermActions actions={[
168
+ {label: '新增', type: 'primary', icon: <PlusOutlined/>, perm: 'sys-user:create', onClick: this.handleAdd},
169
+ ]}/>
170
170
  )}
171
171
  request={(params) => {
172
172
  params.orgId = this.state.currentOrgId
173
173
  return HttpClient.get('admin/sysUser/page', params)
174
174
  }}
175
175
  columns={this.columns}
176
- searchFormRender={() => ( // NOSONAR: AntD 渲染函数惯例
176
+ searchFormRender={() => (
177
177
  <>
178
178
  <Form.Item label='姓名' name='name'>
179
179
  <Input/>
@@ -15,9 +15,9 @@ export default class UserPerm extends React.Component {
15
15
  dataPermType: null
16
16
  },
17
17
  }
18
- formRef = React.createRef() // NOSONAR: React ref,内部通过 this.formRef 使用
18
+ formRef = React.createRef()
19
19
 
20
- show(item) { // NOSONAR: ref 暴露给父组件调用的公共 API
20
+ show(item) {
21
21
  this.setState({visible: true})
22
22
 
23
23
  HttpClient.get('admin/sysUser/get-perm-info', {id: item.id}).then(rs => {
@@ -32,7 +32,7 @@ export default class UserCenterPage extends React.Component {
32
32
 
33
33
  render() {
34
34
  const {info, changePwdOpen, changePwdSuccess} = this.state;
35
- return <Page backgroundGray>
35
+ return <Page>
36
36
 
37
37
  <Card title="个人信息"
38
38
  style={{marginBottom: 16}}
@@ -26,7 +26,7 @@ export default class PermView extends React.Component {
26
26
  },
27
27
  {
28
28
  title: '状态', dataIndex: 'status', key: 'status', width: 140,
29
- render: (status) => { // NOSONAR: 返回元素或占位文本,类型不同属预期
29
+ render: (status) => {
30
30
  if (status === 'mine') {
31
31
  return <Tag color='blue'>我的机构</Tag>;
32
32
  }
@@ -48,7 +48,7 @@ export default class PermView extends React.Component {
48
48
  },
49
49
  {
50
50
  title: '状态', dataIndex: 'status', key: 'status', width: 140,
51
- render: (status) => { // NOSONAR: 返回元素或占位文本,类型不同属预期
51
+ render: (status) => {
52
52
  if (status === 'all') {
53
53
  return <Tag color='green'>已授权</Tag>;
54
54
  }
@@ -26,9 +26,9 @@ table.oa-table {
26
26
  background-color: var(--oa-color-fill, #f5f5f5); /* 悬停背景色 */
27
27
  }
28
28
 
29
- /* 斑马纹效果 - 交替行颜色 */
29
+ /* 斑马纹效果 - 用最浅一档填充色;若用页面底色,暗色下会在容器上形成纯黑条 */
30
30
  tr:nth-child(even) {
31
- background-color: var(--oa-color-bg-layout, #f9f9f9);
31
+ background-color: var(--oa-color-fill-quaternary, #f9f9f9);
32
32
  }
33
33
 
34
34
  /* 响应式表格 - 在小屏幕上添加水平滚动 */