@jiangood/open-admin 2.0.1 → 2.2.5

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 (47) hide show
  1. package/config/common-plugin.js +51 -0
  2. package/config/config.js +1 -56
  3. package/package.json +5 -2
  4. package/src/.umi-production/appData.json +73 -100
  5. package/src/.umi-production/umi.ts +2 -2
  6. package/src/framework/components/DownloadFileButton/index.tsx +1 -1
  7. package/src/framework/components/OrgTree/index.tsx +1 -1
  8. package/src/framework/components/Page/index.less +1 -1
  9. package/src/framework/components/Page/index.tsx +19 -22
  10. package/src/framework/components/PageLoading/index.tsx +5 -3
  11. package/src/framework/components/ProModal/index.tsx +2 -2
  12. package/src/framework/components/ProTable/components/ToolBar/index.tsx +1 -1
  13. package/src/framework/fields/FieldEditor/index.tsx +3 -2
  14. package/src/framework/fields/FieldRemoteTreeSelect/index.tsx +3 -3
  15. package/src/framework/fields/FieldRemoteTreeSelectMultiple/index.tsx +3 -3
  16. package/src/framework/fields/FieldUploadFile/index.tsx +8 -4
  17. package/src/framework/utils/MessageUtils.tsx +21 -99
  18. package/src/framework/utils/system/HttpUtils.ts +5 -1
  19. package/src/framework/utils/system/SysUtils.ts +8 -0
  20. package/src/framework/utils/system/ThemeUtils.ts +37 -12
  21. package/src/framework/views/ViewFile/index.tsx +1 -1
  22. package/src/framework/views/ViewProcessInstanceProgress/index.tsx +1 -0
  23. package/src/layouts/PageRender.tsx +29 -0
  24. package/src/layouts/admin/HeaderRight.jsx +1 -0
  25. package/src/layouts/admin/TabPageRender.jsx +138 -158
  26. package/src/layouts/admin/index.jsx +123 -19
  27. package/src/layouts/admin/index.less +124 -6
  28. package/src/layouts/index.jsx +94 -161
  29. package/src/pages/404.jsx +7 -5
  30. package/src/pages/about.jsx +3 -3
  31. package/src/pages/index.jsx +4 -5
  32. package/src/pages/login.jsx +18 -9
  33. package/src/pages/login.less +0 -1
  34. package/src/pages/system/dict/index.jsx +8 -11
  35. package/src/pages/system/file/index.jsx +6 -6
  36. package/src/pages/system/job/index.jsx +26 -11
  37. package/src/pages/system/log/index.jsx +4 -5
  38. package/src/pages/system/manual/index.jsx +8 -6
  39. package/src/pages/system/org/index.jsx +4 -2
  40. package/src/pages/system/role/index.jsx +16 -14
  41. package/src/pages/system/role/perm.jsx +3 -4
  42. package/src/pages/system/user/UserPerm.jsx +1 -1
  43. package/src/pages/system/user/index.jsx +9 -7
  44. package/src/pages/userCenter/index.jsx +2 -2
  45. package/src/pages/userCenter/message.jsx +4 -2
  46. package/src/layouts/PageRender.d.ts +0 -22
  47. package/src/layouts/PageRender.jsx +0 -90
@@ -1,185 +1,118 @@
1
- import React from "react";
2
- import {ConfigProvider} from "antd";
1
+ import {useState, useEffect} from "react";
2
+ import {App, ConfigProvider} from "antd";
3
3
  import zhCN from 'antd/locale/zh_CN';
4
4
  import dayjs from 'dayjs';
5
5
  import 'dayjs/locale/zh-cn';
6
- import {Outlet, withRouter} from "umi";
6
+ import {Outlet, useLocation} from "umi";
7
7
 
8
8
  import AdminLayout from "./admin"
9
- import {
10
- ArrayUtils,
11
- HttpUtils,
12
- MessageHolder,
13
- PageLoading,
14
- PageUtils, StringUtils,
15
- SysUtils,
16
- ThemeUtils,
17
- } from "../framework";
18
- import {Logger} from "../framework/utils/Logger";
9
+ import {HttpUtils, PageLoading, PageUtils, SysUtils, ThemeUtils} from "../framework";
19
10
 
20
11
  import '../style/global.less'
21
12
  import './index.less'
22
13
 
23
14
  dayjs.locale('zh-cn');
24
15
 
25
- // 不需要登录的页面
26
- const SIMPLE_URLS = ['/login', '/test']
27
-
28
- function checkIsSimplePage(pathname) {
29
- if(pathname === '/' || pathname === '/index'){
30
- return false;
31
- }
32
- // 测试页面
33
- if(pathname.startsWith("/test/")){
34
- return true
35
- }
36
- return ArrayUtils.contains(SIMPLE_URLS, pathname) ;
16
+ const configProps = {
17
+ input: {autoComplete: 'off'},
18
+ form: {validateMessages: {required: '必填项'}, colon: false},
19
+ button: {autoInsertSpace: false},
20
+ locale: zhCN,
21
+ theme: {
22
+ token: {
23
+ colorPrimary: ThemeUtils.getColor("primary-color"),
24
+ colorSuccess: ThemeUtils.getColor("success-color"),
25
+ colorWarning: ThemeUtils.getColor("warning-color"),
26
+ colorError: ThemeUtils.getColor("error-color"),
27
+ borderRadius: 4,
28
+ },
29
+ components: {
30
+ Menu: {
31
+ darkItemBg: ThemeUtils.getColor("primary-color"),
32
+ darkPopupBg: ThemeUtils.getColor("primary-color"),
33
+ darkItemSelectedBg: ThemeUtils.getColor("primary-color-click"),
34
+ darkItemHoverBg: ThemeUtils.getColor("primary-color-hover"),
35
+ darkSubMenuItemBg: ThemeUtils.getColor("primary-color"),
36
+ },
37
+ Layout: {
38
+ siderBg: ThemeUtils.getColor("primary-color"),
39
+ triggerBg: ThemeUtils.getColor("primary-color-click"),
40
+ headerBg: 'white',
41
+ triggerHeight: 32,
42
+ },
43
+ },
44
+ },
45
+ };
46
+
47
+ function AppWrapper({children}) {
48
+ return <ConfigProvider {...configProps}><App>{children}</App></ConfigProvider>;
37
49
  }
38
50
 
39
- function checkIsPurePage(pathname){
40
- if(pathname.startsWith("/test/")){
41
- return true
42
- }
43
- return false
44
- }
45
-
46
- class _Layouts extends React.Component {
47
-
48
- log = Logger.getLogger('Layouts')
49
-
50
- state = {
51
- messageHolderInit:false,
52
- siteInfoLoading: true,
53
- loginInfoFinish: false
54
- }
55
-
56
- onMessageHolderFinish = () => {
57
- this.loadSiteInfo()
58
- this.setState({messageHolderInit:true});
59
- }
60
-
51
+ const PUBLIC_PAGES = (() => {
52
+ const raw = typeof OPEN_ADMIN_PUBLIC_PAGES !== 'undefined' && OPEN_ADMIN_PUBLIC_PAGES;
53
+ return raw ? raw.split(',').map(s => s.trim()) : ['/login', '/test'];
54
+ })();
61
55
 
62
- loadSiteInfo = () => {
63
- HttpUtils.get("/admin/public/site-info").then(rs => {
64
- SysUtils.setSiteInfo(rs)
65
- this.setState({siteInfoLoading: false})
66
- this.loadLoginInfo()
67
- })
68
- };
56
+ function isPublicPage(pathname, search) {
57
+ if (pathname === '/' || pathname === '/index') return false;
69
58
 
70
- componentDidUpdate(prevProps, prevState, snapshot) {
71
- const pre = prevProps.location.pathname
72
- const cur = this.props.location.pathname
73
- if (pre !== cur) {
74
- this.loadLoginInfo()
59
+ for (const pattern of PUBLIC_PAGES) {
60
+ if (pattern.endsWith('/**')) {
61
+ if (pathname.startsWith(pattern.slice(0, -3))) return true;
62
+ } else if (pathname === pattern) {
63
+ return true;
75
64
  }
76
65
  }
77
66
 
67
+ if (new URLSearchParams(search).has('_noLayout')) return true;
68
+ return false;
69
+ }
78
70
 
71
+ export function Layouts() {
72
+ const {pathname, search} = useLocation();
73
+ const [siteInfoLoaded, setSiteInfoLoaded] = useState(false);
74
+ const [loginChecked, setLoginChecked] = useState(false);
79
75
 
80
- loadLoginInfo = () => {
81
- const {pathname} = this.props.location;
82
- if (checkIsPurePage(pathname) || checkIsSimplePage(pathname) || this.state.loginInfoFinish) {
83
- return;
84
- }
85
-
86
- HttpUtils.get('/admin/public/check-login')
87
- .then(rs => {
88
- const {needUpdatePwd, dictInfo, loginInfo} = rs
89
- SysUtils.setDictInfo(dictInfo)
90
- SysUtils.setLoginInfo(loginInfo)
91
- if (!needUpdatePwd) {
92
- this.setState({loginInfoFinish: true});
93
- return;
94
- }
95
-
96
- if (needUpdatePwd) {
97
- PageUtils.open('/userCenter/ChangePassword', '修改密码')
98
- return;
99
- }
100
- })
101
- .catch(async () => {
102
- PageUtils.redirectToLogin()
103
- })
104
- }
105
-
106
- render() {
107
- return <ConfigProvider
108
- input={{autoComplete: 'off'}}
109
- form={{
110
- validateMessages: {
111
- required: '必填项'
112
- }, colon: false
113
- }}
114
- button={{
115
- autoInsertSpace: false
116
- }}
117
- locale={zhCN}
118
- theme={{
119
- token: {
120
- colorPrimary: ThemeUtils.getColor("primary-color"),
121
- colorSuccess: ThemeUtils.getColor("success-color"),
122
- colorWarning: ThemeUtils.getColor("warning-color"),
123
- colorError: ThemeUtils.getColor("error-color"),
124
- borderRadius: 4,
125
- },
126
- components: {
127
- Menu: {
128
- darkItemBg: ThemeUtils.getColor("primary-color"),
129
- darkPopupBg: ThemeUtils.getColor("primary-color"),
130
- darkItemSelectedBg: ThemeUtils.getColor("primary-color-click"),
131
- darkItemHoverBg: ThemeUtils.getColor("primary-color-hover"),
132
- darkSubMenuItemBg: ThemeUtils.getColor("primary-color")
133
- },
134
- Layout: {
135
- siderBg: ThemeUtils.getColor("primary-color"),
136
- triggerBg: ThemeUtils.getColor("primary-color-click"),
137
- headerBg: 'white',
138
- triggerHeight: 32
139
- }
140
- }
141
- }}>
142
-
143
- <MessageHolder onFinish={this.onMessageHolderFinish} />
144
- {this.renderContent()}
145
- </ConfigProvider>
146
- }
147
-
148
-
149
- renderContent = () => {
150
- const {pathname} = this.props.location;
151
-
152
- if(checkIsPurePage(pathname)){
153
- return <Outlet/>
154
- }
155
-
156
- if(!this.state.messageHolderInit) {
157
- this.log.info('加载message holder...')
158
- return <PageLoading message='加载消息组件...'/>
159
- }
160
-
161
- const {params = {}} = this.props.location;
162
- if (checkIsSimplePage(pathname) || params.hasOwnProperty('_noLayout')) {
163
- return <Outlet/>
164
- }
165
-
166
-
167
-
168
- if (this.state.siteInfoLoading) {
169
- return <PageLoading message='加载站点信息...'/>
170
- }
171
-
172
-
76
+ const ready = siteInfoLoaded && loginChecked;
77
+ const isPublic = isPublicPage(pathname, search);
173
78
 
174
- if (!this.state.loginInfoFinish) {
175
- return <PageLoading message='加载登录信息...'/>
79
+ useEffect(() => {
80
+ if (isPublic) {
81
+ setSiteInfoLoaded(false);
82
+ setLoginChecked(false);
83
+ return;
176
84
  }
177
-
178
- return <AdminLayout path={this.state.path} logo={this.props.logo}/>
179
- };
85
+ if (ready) return;
86
+
87
+ Promise.all([
88
+ HttpUtils.get("/admin/public/site-info").then(data => {
89
+ SysUtils.setSiteInfo(data);
90
+ setSiteInfoLoaded(true);
91
+ }),
92
+ HttpUtils.get('/admin/public/check-login').then(data => {
93
+ SysUtils.setDictInfo(data.dictInfo);
94
+ SysUtils.setLoginInfo(data.loginInfo);
95
+ setLoginChecked(true);
96
+ }),
97
+ ]).catch(() => {
98
+ console.error('[Layout] 初始化应用失败');
99
+ PageUtils.redirectToLogin();
100
+ });
101
+ }, [pathname]);
102
+
103
+ if (isPublic) return <AppWrapper><Outlet/></AppWrapper>;
104
+
105
+ return (
106
+ <AppWrapper>
107
+ {ready ? <AdminLayout/> : (
108
+ <PageLoading messages={[
109
+ !siteInfoLoaded && '加载站点信息...',
110
+ !loginChecked && '检查登录中...',
111
+ ].filter(Boolean)}/>
112
+ )}
113
+ </AppWrapper>
114
+ );
180
115
  }
181
116
 
182
-
183
- export const Layouts = withRouter(_Layouts);
184
- export default Layouts
185
- export * from './PageRender'
117
+ export default Layouts;
118
+ export * from './PageRender'
package/src/pages/404.jsx CHANGED
@@ -1,13 +1,15 @@
1
1
  import React from "react";
2
2
  import {Result} from "antd";
3
+ import {Page} from "../framework";
3
4
 
4
5
  export default class extends React.Component {
5
6
 
6
7
  render() {
7
- return <Result
8
- status={404}
9
- title='页面不存在'
10
- />
11
-
8
+ return <Page>
9
+ <Result
10
+ status={404}
11
+ title='页面不存在'
12
+ />
13
+ </Page>
12
14
  }
13
15
  }
@@ -1,12 +1,12 @@
1
1
  import React from "react";
2
+ import {Page} from "../framework";
2
3
 
3
4
  export default class extends React.Component {
4
5
 
5
6
 
6
7
  render() {
7
- return <>
8
+ return <Page>
8
9
  <h1>关于</h1>
9
- </>
10
-
10
+ </Page>
11
11
  }
12
12
  }
@@ -1,10 +1,9 @@
1
1
  import React from "react";
2
2
  import {Card} from "antd";
3
-
3
+ import {Page} from "../framework";
4
4
 
5
5
  export default function () {
6
-
7
- return <Card>
8
- 欢迎使用本系统
9
- </Card>
6
+ return <Page>
7
+ <Card>欢迎使用本系统</Card>
8
+ </Page>
10
9
  }
@@ -24,6 +24,7 @@ function postLogin(values) {
24
24
  history.push(getRedirect())
25
25
  resolve(rs)
26
26
  }).catch(e => {
27
+ console.error('[Login] 登录失败:', e);
27
28
  reject(e)
28
29
  })
29
30
  })
@@ -38,14 +39,20 @@ export default class extends React.Component {
38
39
  }
39
40
 
40
41
  async componentDidMount() {
41
- if (localStorage.length === 0) {
42
- MessageUtils.alert('站点数据缺失,刷新当前页面...')
43
- window.location.reload()
42
+ const siteInfo = SysUtils.getSiteInfo()
43
+ if (siteInfo && siteInfo.rsaPublicKey) {
44
+ this.setState({siteInfo})
44
45
  return
45
46
  }
46
-
47
- const siteInfo = SysUtils.getSiteInfo()
48
- this.setState({siteInfo})
47
+ // localStorage 中无站点信息,从服务端重新加载
48
+ try {
49
+ const rs = await HttpUtils.get('/admin/public/site-info')
50
+ SysUtils.setSiteInfo(rs)
51
+ this.setState({siteInfo: rs})
52
+ } catch (e) {
53
+ console.error('[Login] 加载站点信息失败:', e);
54
+ message.error('加载站点信息失败,请刷新页面重试')
55
+ }
49
56
  }
50
57
 
51
58
  submit = values => {
@@ -69,9 +76,11 @@ export default class extends React.Component {
69
76
  render() {
70
77
  const {siteInfo} = this.state
71
78
 
72
- const pageStyle = {}
79
+ const pageStyle = {
80
+ backgroundImage: `url("${SysUtils.contextPath('/admin/public/login_bg.jpg')}")`
81
+ }
73
82
  if (siteInfo.loginBackground) {
74
- const url = 'admin/sysFile/preview/' + siteInfo.loginBackground;
83
+ const url = SysUtils.contextPath('/admin/sysFile/preview/' + siteInfo.loginBackground);
75
84
  pageStyle.backgroundImage = 'url("' + url + '")'
76
85
  }
77
86
 
@@ -110,7 +119,7 @@ export default class extends React.Component {
110
119
  <Space style={{alignItems: 'center'}}>
111
120
  <Input size='large' placeholder='验证码' prefix={<SafetyCertificateOutlined/>}/>
112
121
  <img height={36} width={100}
113
- src={"/admin/auth/captcha-image?_random=" + this.state.random}
122
+ src={SysUtils.contextPath("/admin/auth/captcha-image?_random=" + this.state.random)}
114
123
  onClick={() => this.setState({random: Math.random()})}/>
115
124
  </Space>
116
125
  </Form.Item>
@@ -1,6 +1,5 @@
1
1
  .login-page {
2
2
  background-size: cover;
3
- background-image: url("/admin/public/login_bg.jpg");
4
3
  background-repeat: no-repeat;
5
4
  background-position: bottom;
6
5
 
@@ -33,7 +33,9 @@ export default class extends React.Component {
33
33
  }
34
34
 
35
35
  onFinish = values => {
36
- HttpUtils.post('admin/dict/save', values).then(rs => {
36
+ const isNew = !values.id;
37
+ const url = isNew ? 'admin/dict/create' : 'admin/dict/update';
38
+ HttpUtils.post(url, values).then(rs => {
37
39
  this.setState({formOpen: false})
38
40
  this.tableRef.current.reload()
39
41
  })
@@ -90,15 +92,11 @@ export default class extends React.Component {
90
92
  title: '操作',
91
93
  dataIndex: 'option',
92
94
  render: (_, record) => {
93
- if(!record.id){ // 非数据库定义的不让修改
94
- return
95
- }
96
-
97
95
  return (
98
96
  <ButtonList>
99
- <Button size='small' perm='sysDict:save'
97
+ <Button size='small' perm='sys-dict:update'
100
98
  onClick={() => this.handleEdit(record)}> 编辑 </Button>
101
- <Popconfirm perm='sysDict:delete' title='是否确定删除字典项'
99
+ <Popconfirm perm='sys-dict:delete' title='是否确定删除字典项'
102
100
  onConfirm={() => this.handleDelete(record)}>
103
101
  <Button size='small'>删除</Button>
104
102
  </Popconfirm>
@@ -109,13 +107,13 @@ export default class extends React.Component {
109
107
  ]
110
108
 
111
109
  render() {
112
- return <Page padding>
110
+ return <Page>
113
111
  <ProTable
114
112
  rowKey='uid'
115
113
  actionRef={this.tableRef}
116
114
  toolBarRender={() => {
117
115
  return <ButtonList>
118
- <Button perm='sysDict:save' type='primary' onClick={this.handleAdd} >
116
+ <Button perm='sys-dict:create' type='primary' onClick={this.handleAdd} >
119
117
  <PlusOutlined/> 新增
120
118
  </Button>
121
119
  </ButtonList>
@@ -126,14 +124,13 @@ export default class extends React.Component {
126
124
  }}
127
125
  columns={this.columns}
128
126
  showToolbarSearch={true}
129
- scrollY={500}
130
127
  />
131
128
  <Modal
132
129
  title='编辑数据字典项'
133
130
  open={this.state.formOpen}
134
131
  onOk={() => this.formRef.current.submit()}
135
132
  onCancel={() => this.setState({formOpen: false})}
136
- destroyOnClose
133
+ destroyOnHidden
137
134
  >
138
135
 
139
136
  <Form ref={this.formRef} labelCol={{flex: '100px'}}
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import {Button, Form, Input, Modal, Popconfirm} from 'antd'
3
3
  import {CloudUploadOutlined} from "@ant-design/icons";
4
4
 
5
- import {ButtonList, FieldDateRange, FieldDictSelect, FieldUploadFile, HttpUtils, ProTable} from "../../../framework";
5
+ import {ButtonList, FieldDateRange, FieldDictSelect, FieldUploadFile, HttpUtils, Page, ProTable, SysUtils} from "../../../framework";
6
6
 
7
7
  export default class extends React.Component {
8
8
 
@@ -59,7 +59,7 @@ export default class extends React.Component {
59
59
  title: '预览',
60
60
  dataIndex: 'id',
61
61
  render(id, record) {
62
- const nodes = [<a href={'/admin/sysFile/preview/' + record.id} target='_blank'>预览</a>]
62
+ const nodes = [<a href={SysUtils.contextPath('/admin/sysFile/preview/' + record.id)} target='_blank'>预览</a>]
63
63
 
64
64
 
65
65
  if (record.imageUrls?.length > 0) {
@@ -79,7 +79,7 @@ export default class extends React.Component {
79
79
  dataIndex: 'option',
80
80
  render: (_, record) => (
81
81
  <ButtonList>
82
- <Popconfirm perm='sysFile:delete' title='是否确定删除文件信息'
82
+ <Popconfirm perm='sys-file:delete' title='是否确定删除文件信息'
83
83
  onConfirm={() => this.handleDelete(record)}>
84
84
  <a>删除</a>
85
85
  </Popconfirm>
@@ -89,7 +89,7 @@ export default class extends React.Component {
89
89
  ]
90
90
 
91
91
  render() {
92
- return <>
92
+ return <Page>
93
93
  <ProTable
94
94
  actionRef={this.tableRef}
95
95
  toolBarRender={() => {
@@ -127,7 +127,7 @@ export default class extends React.Component {
127
127
  this.tableRef.current.reload()
128
128
  }}
129
129
  footer={null}
130
- destroyOnClose
130
+ destroyOnHidden
131
131
  >
132
132
  <Form ref={this.formRef}
133
133
  initialValues={this.state.formValues}
@@ -140,7 +140,7 @@ export default class extends React.Component {
140
140
  </Form>
141
141
  </Modal>
142
142
 
143
- </>
143
+ </Page>
144
144
  }
145
145
  }
146
146
 
@@ -16,7 +16,7 @@ import {
16
16
  } from 'antd'
17
17
  import {PlusOutlined} from "@ant-design/icons";
18
18
 
19
- import {ButtonList, HttpUtils, Page, ProTable, StringUtils, ValueType} from "../../../framework";
19
+ import {ButtonList, HttpUtils, Page, ProTable, StringUtils, SysUtils, ValueType} from "../../../framework";
20
20
 
21
21
 
22
22
  const cronOptions = [
@@ -66,6 +66,8 @@ export default class extends React.Component {
66
66
  componentDidMount() {
67
67
  HttpUtils.get('admin/job/job-class-options').then(rs => {
68
68
  this.setState({jobClassOptions: rs})
69
+ }).catch(e => {
70
+ console.error('[Job] 加载作业类选项失败:', e);
69
71
  })
70
72
  }
71
73
 
@@ -81,13 +83,19 @@ export default class extends React.Component {
81
83
  loadJobParamFields(className, jobData) {
82
84
  HttpUtils.post("admin/job/get-job-param-fields", jobData || {}, {className}).then(rs => {
83
85
  this.setState({paramList: rs})
86
+ }).catch(e => {
87
+ console.error('[Job] 加载作业参数字段失败:', e);
84
88
  })
85
89
  }
86
90
 
87
91
  onFinish = (values) => {
88
- HttpUtils.post('admin/job/save', values).then(rs => {
92
+ const isNew = !values.id;
93
+ const url = isNew ? 'admin/job/create' : 'admin/job/update';
94
+ HttpUtils.post(url, values).then(rs => {
89
95
  this.setState({formOpen: false})
90
96
  this.tableRef.current.reload();
97
+ }).catch(e => {
98
+ console.error('[Job] 保存作业失败:', e);
91
99
  })
92
100
  }
93
101
 
@@ -95,12 +103,17 @@ export default class extends React.Component {
95
103
  const hide = message.loading("删除作业中...")
96
104
  HttpUtils.post('admin/job/delete', {id: row.id}).then(rs => {
97
105
  this.tableRef.current.reload();
98
- }).catch(hide)
106
+ }).catch(e => {
107
+ console.error('[Job] 删除作业失败:', e);
108
+ hide();
109
+ })
99
110
  }
100
111
 
101
112
  handleTriggerJob = row => {
102
113
  HttpUtils.get('admin/job/trigger-job', {id: row.id}).then(rs => {
103
114
  this.tableRef.current.reload();
115
+ }).catch(e => {
116
+ console.error('[Job] 触发作业失败:', e);
104
117
  })
105
118
  }
106
119
 
@@ -149,9 +162,9 @@ export default class extends React.Component {
149
162
  return (
150
163
  <Space>
151
164
  <Button size='small' onClick={() => this.showExecuteRecord(record)}>执行记录</Button>
152
- <Button size='small' onClick={() => this.handleTriggerJob(record)}>执行一次</Button>
153
- <Button size='small' onClick={() => this.handleEdit(record)}> 编辑 </Button>
154
- <Popconfirm title='是否确定删除?' onConfirm={() => this.handleDelete(record)}>
165
+ <Button size='small' perm='job:trigger' onClick={() => this.handleTriggerJob(record)}>执行一次</Button>
166
+ <Button size='small' perm='job:update' onClick={() => this.handleEdit(record)}> 编辑 </Button>
167
+ <Popconfirm perm='job:delete' title='是否确定删除?' onConfirm={() => this.handleDelete(record)}>
155
168
  <Button size='small'>删除</Button>
156
169
  </Popconfirm>
157
170
  </Space>
@@ -165,6 +178,8 @@ export default class extends React.Component {
165
178
  this.setState({statusOpen: true})
166
179
  HttpUtils.get('admin/job/status').then(rs => {
167
180
  this.setState({status: rs})
181
+ }).catch(e => {
182
+ console.error('[Job] 加载状态失败:', e);
168
183
  })
169
184
  };
170
185
 
@@ -174,7 +189,7 @@ export default class extends React.Component {
174
189
 
175
190
 
176
191
  render() {
177
- return <Page padding>
192
+ return <Page>
178
193
  <ProTable
179
194
  actionRef={this.tableRef}
180
195
  toolBarRender={() => {
@@ -195,7 +210,7 @@ export default class extends React.Component {
195
210
 
196
211
  <Modal title='作业调度'
197
212
  open={this.state.formOpen}
198
- destroyOnClose
213
+ destroyOnHidden
199
214
  width={800}
200
215
  onOk={() => this.formRef.current.submit()}
201
216
  onCancel={() => this.setState({formOpen: false})}
@@ -245,7 +260,7 @@ export default class extends React.Component {
245
260
  footer={null}
246
261
  width={1024}
247
262
  >
248
- <Alert message={<pre>{this.state.status}</pre>}></Alert>
263
+ <Alert title={<pre>{this.state.status}</pre>}></Alert>
249
264
 
250
265
  </Modal>
251
266
 
@@ -254,7 +269,7 @@ export default class extends React.Component {
254
269
  onCancel={() => this.setState({executeRecordOpen: false})}
255
270
  footer={null}
256
271
  width={1024}
257
- destroyOnClose
272
+ destroyOnHidden
258
273
  >
259
274
  <ProTable columns={[{
260
275
  title: '开始时间',
@@ -289,7 +304,7 @@ export default class extends React.Component {
289
304
  title: '操作',
290
305
  dataIndex: 'option',
291
306
  render: (_, record) => {
292
- const url = '/admin/sys/log/' + record.id;
307
+ const url = SysUtils.contextPath('/admin/sys/log/' + record.id);
293
308
  return <a href={url} target='_blank'>日志</a>;
294
309
  },
295
310
  }
@@ -1,6 +1,6 @@
1
- import React, {Fragment} from 'react';
1
+ import React from 'react';
2
2
  import {Form, Input, Tag} from "antd";
3
- import {ViewText, FieldDateRange, HttpUtils, ProTable} from "../../../framework";
3
+ import {ViewText, FieldDateRange, HttpUtils, Page, ProTable} from "../../../framework";
4
4
 
5
5
  export default class extends React.Component {
6
6
 
@@ -54,7 +54,7 @@ export default class extends React.Component {
54
54
 
55
55
 
56
56
  render() {
57
- return <>
57
+ return <Page>
58
58
  <ProTable
59
59
  request={(params) => HttpUtils.get('admin/sysLog/page', params)}
60
60
  columns={this.columns}
@@ -66,8 +66,7 @@ export default class extends React.Component {
66
66
  <FieldDateRange/>
67
67
  </Form.Item>
68
68
  </ProTable>
69
-
70
- </>
69
+ </Page>
71
70
  }
72
71
 
73
72