@jiangood/springboot-admin-starter 0.1.2 → 0.1.4
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/package.json +1 -1
- package/src/framework/field-components/FieldDate.d.ts +6 -4
- package/src/framework/field-components/FieldDate.jsx +5 -0
- package/src/framework/field-components/FieldDateRange.jsx +2 -1
- package/src/framework/pages/LoginPage.d.ts +5 -1
- package/src/framework/pages/LoginPage.jsx +49 -40
- package/src/framework/utils/DateUtils.ts +26 -12
- package/src/framework/utils/EventBusUtils.ts +1 -0
- package/src/framework/utils/MessageUtils.tsx +7 -5
- package/src/framework/utils/ObjectUtils.ts +76 -71
- package/src/framework/utils/TreeUtils.ts +5 -2
- package/src/layouts/admin/index.jsx +2 -2
- package/src/pages/flowable/design/index.jsx +2 -0
- package/src/pages/flowable/index.jsx +2 -2
- package/src/pages/flowable/task/form.jsx +105 -18
- package/src/pages/flowable/task/index.jsx +6 -21
- package/src/pages/flowable/task/instance/view.jsx +85 -0
- package/src/pages/login.jsx +4 -2
- package/src/pages/flowable/InstanceInfo.jsx +0 -138
- package/src/pages/flowable/instance/view.jsx +0 -15
package/package.json
CHANGED
|
@@ -2,14 +2,14 @@ import React from 'react';
|
|
|
2
2
|
|
|
3
3
|
export interface FieldDateProps {
|
|
4
4
|
|
|
5
|
-
type: 'YYYY-MM-DD' |
|
|
5
|
+
type: 'YYYY-MM-DD' | 'DAY'|
|
|
6
6
|
'YYYY-MM-DD HH:mm:ss' |
|
|
7
7
|
// 年
|
|
8
|
-
'YYYY' |
|
|
8
|
+
'YYYY' | 'YEAR' |
|
|
9
9
|
// 年月
|
|
10
|
-
'YYYY-MM' |
|
|
10
|
+
'YYYY-MM' | 'YEAR_MONTH'|
|
|
11
11
|
// 季度
|
|
12
|
-
'YYYY-QQ' |
|
|
12
|
+
'YYYY-QQ' | 'YEAR_QUARTER'|
|
|
13
13
|
|
|
14
14
|
'YYYY-MM-DD HH:mm' |
|
|
15
15
|
|
|
@@ -21,5 +21,7 @@ export interface FieldDateProps {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class FieldDate extends React.Component<FieldDateProps, any> {
|
|
24
|
+
|
|
25
|
+
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import React from "react";
|
|
5
5
|
import dayjs from "dayjs";
|
|
6
6
|
import {DatePicker, TimePicker} from "antd";
|
|
7
|
+
import {DateUtils} from "../utils";
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
export class FieldDate extends React.Component {
|
|
@@ -11,8 +12,12 @@ export class FieldDate extends React.Component {
|
|
|
11
12
|
type: 'YYYY-MM-DD'
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
|
|
16
|
+
|
|
14
17
|
render() {
|
|
15
18
|
let {type, value, onChange, ...rest} = this.props;
|
|
19
|
+
type = DateUtils.convertTypeToFormat(type)
|
|
20
|
+
|
|
16
21
|
switch (type) {
|
|
17
22
|
case 'YYYY':
|
|
18
23
|
return <DatePicker
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import React from "react";
|
|
5
5
|
import dayjs from "dayjs";
|
|
6
6
|
import {DatePicker, TimePicker} from "antd";
|
|
7
|
-
import {StringUtils} from "../utils";
|
|
7
|
+
import {DateUtils, StringUtils} from "../utils";
|
|
8
8
|
|
|
9
9
|
const SP = StringUtils.ISO_SPLITTER;
|
|
10
10
|
|
|
@@ -15,6 +15,7 @@ export class FieldDateRange extends React.Component {
|
|
|
15
15
|
|
|
16
16
|
render() {
|
|
17
17
|
let {type, value, onChange, ...rest} = this.props;
|
|
18
|
+
type = DateUtils.convertTypeToFormat(type)
|
|
18
19
|
switch (type) {
|
|
19
20
|
case 'YYYY':
|
|
20
21
|
return <DatePicker.RangePicker
|
|
@@ -3,7 +3,7 @@ import {Button, Form, Input, message, Space} from 'antd';
|
|
|
3
3
|
import {LockOutlined, SafetyCertificateOutlined, UserOutlined, WarningOutlined} from '@ant-design/icons';
|
|
4
4
|
import "./LoginPage.less"
|
|
5
5
|
import {history} from 'umi';
|
|
6
|
-
import {HttpUtils, MessageUtils, PageUtils, SysUtils} from "../utils";
|
|
6
|
+
import {EventBusUtils, HttpUtils, MessageUtils, PageUtils, SysUtils} from "../utils";
|
|
7
7
|
import {JSEncrypt} from "jsencrypt";
|
|
8
8
|
|
|
9
9
|
|
|
@@ -53,6 +53,7 @@ export class LoginPage extends React.Component {
|
|
|
53
53
|
|
|
54
54
|
HttpUtils.postForm('/admin/auth/login', values).then(rs => {
|
|
55
55
|
console.log('登录结果', rs)
|
|
56
|
+
EventBusUtils.emit('loginSuccess')
|
|
56
57
|
history.push(this.redirect)
|
|
57
58
|
}).catch(e => {
|
|
58
59
|
console.log('登录错误', e)
|
|
@@ -76,45 +77,7 @@ export class LoginPage extends React.Component {
|
|
|
76
77
|
<section className='login-page' style={pageStyle}>
|
|
77
78
|
<div className="login-content">
|
|
78
79
|
<h1>{siteInfo.title}</h1>
|
|
79
|
-
|
|
80
|
-
name="normal_login"
|
|
81
|
-
className="login-form"
|
|
82
|
-
initialValues={{remember: true}}
|
|
83
|
-
onFinish={this.submit}
|
|
84
|
-
requiredMark={false}
|
|
85
|
-
colon={false}
|
|
86
|
-
>
|
|
87
|
-
|
|
88
|
-
<Form.Item name="username" rules={[{required: true, message: '请输入用户名!'}]}>
|
|
89
|
-
<Input size='large' prefix={<UserOutlined/>} placeholder="用户名" autoComplete="off"/>
|
|
90
|
-
</Form.Item>
|
|
91
|
-
<Form.Item name="password" rules={[{required: true, message: '请输入密码!'}]}>
|
|
92
|
-
<Input autoComplete="off" prefix={<LockOutlined/>} type="password" placeholder="密码"
|
|
93
|
-
size='large'
|
|
94
|
-
/>
|
|
95
|
-
</Form.Item>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
{siteInfo.captcha && <Form.Item name='captchaCode' rules={[{required: true}]}>
|
|
99
|
-
<Space style={{alignItems: 'center'}}>
|
|
100
|
-
<Input size='large' placeholder='验证码' prefix={<SafetyCertificateOutlined/>}/>
|
|
101
|
-
<img height={36}
|
|
102
|
-
width={100}
|
|
103
|
-
src={"/admin/auth/captchaImage?_random=" + this.state.random}
|
|
104
|
-
onClick={() => {
|
|
105
|
-
this.setState({random: Math.random()})
|
|
106
|
-
}}></img>
|
|
107
|
-
</Space>
|
|
108
|
-
</Form.Item>}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<Form.Item style={{marginTop: 10}}>
|
|
112
|
-
<Button loading={this.state.logging} type="primary" htmlType="submit"
|
|
113
|
-
block size='large'>
|
|
114
|
-
登录
|
|
115
|
-
</Button>
|
|
116
|
-
</Form.Item>
|
|
117
|
-
</Form>
|
|
80
|
+
{this.getForm(siteInfo)}
|
|
118
81
|
|
|
119
82
|
{this.renderFormBottom()}
|
|
120
83
|
|
|
@@ -124,6 +87,52 @@ export class LoginPage extends React.Component {
|
|
|
124
87
|
}
|
|
125
88
|
|
|
126
89
|
|
|
90
|
+
getForm(siteInfo) {
|
|
91
|
+
if(this.props.form){
|
|
92
|
+
return this.props.form;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return <Form
|
|
96
|
+
name="normal_login"
|
|
97
|
+
className="login-form"
|
|
98
|
+
initialValues={{remember: true}}
|
|
99
|
+
onFinish={this.submit}
|
|
100
|
+
requiredMark={false}
|
|
101
|
+
colon={false}
|
|
102
|
+
>
|
|
103
|
+
|
|
104
|
+
<Form.Item name="username" rules={[{required: true, message: '请输入用户名!'}]}>
|
|
105
|
+
<Input size='large' prefix={<UserOutlined/>} placeholder="用户名" autoComplete="off"/>
|
|
106
|
+
</Form.Item>
|
|
107
|
+
<Form.Item name="password" rules={[{required: true, message: '请输入密码!'}]}>
|
|
108
|
+
<Input autoComplete="off" prefix={<LockOutlined/>} type="password" placeholder="密码"
|
|
109
|
+
size='large'
|
|
110
|
+
/>
|
|
111
|
+
</Form.Item>
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
{siteInfo.captcha && <Form.Item name='captchaCode' rules={[{required: true}]}>
|
|
115
|
+
<Space style={{alignItems: 'center'}}>
|
|
116
|
+
<Input size='large' placeholder='验证码' prefix={<SafetyCertificateOutlined/>}/>
|
|
117
|
+
<img height={36}
|
|
118
|
+
width={100}
|
|
119
|
+
src={"/admin/auth/captchaImage?_random=" + this.state.random}
|
|
120
|
+
onClick={() => {
|
|
121
|
+
this.setState({random: Math.random()})
|
|
122
|
+
}}></img>
|
|
123
|
+
</Space>
|
|
124
|
+
</Form.Item>}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
<Form.Item style={{marginTop: 10}}>
|
|
128
|
+
<Button loading={this.state.logging} type="primary" htmlType="submit"
|
|
129
|
+
block size='large'>
|
|
130
|
+
登录
|
|
131
|
+
</Button>
|
|
132
|
+
</Form.Item>
|
|
133
|
+
</Form>;
|
|
134
|
+
}
|
|
135
|
+
|
|
127
136
|
renderFormBottom() {
|
|
128
137
|
let siteInfo = this.state.siteInfo;
|
|
129
138
|
if (siteInfo.loginBoxBottomTip) {
|
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {StringUtils} from './StringUtils';
|
|
2
|
+
|
|
3
|
+
export class DateUtils {
|
|
4
|
+
|
|
5
|
+
public static convertTypeToFormat(type) {
|
|
6
|
+
if (type === 'YEAR') {
|
|
7
|
+
type = 'YYYY'
|
|
8
|
+
} else if (type === 'YEAR_MONTH') {
|
|
9
|
+
type = 'YYYY-MM'
|
|
10
|
+
} else if (type === 'YEAR_QUARTER') {
|
|
11
|
+
type = 'YYYY-QQ'
|
|
12
|
+
} else if (type === 'DAY') {
|
|
13
|
+
type = 'YYYY-MM-DD'
|
|
14
|
+
}
|
|
15
|
+
return type;
|
|
16
|
+
}
|
|
2
17
|
|
|
3
|
-
|
|
4
|
-
public static year(date: Date): number {
|
|
18
|
+
public static year(date: Date): number {
|
|
5
19
|
return date.getFullYear();
|
|
6
20
|
}
|
|
7
21
|
|
|
@@ -28,19 +42,19 @@ export class DateUtils {
|
|
|
28
42
|
* @param date
|
|
29
43
|
* @returns {string}
|
|
30
44
|
*/
|
|
31
|
-
public static
|
|
45
|
+
public static hour(date: Date): string {
|
|
32
46
|
return StringUtils.pad(date.getHours(), 2);
|
|
33
47
|
}
|
|
34
48
|
|
|
35
|
-
public static
|
|
49
|
+
public static minute(date: Date): string {
|
|
36
50
|
return StringUtils.pad(date.getMinutes(), 2);
|
|
37
51
|
}
|
|
38
52
|
|
|
39
|
-
public static
|
|
53
|
+
public static second(date: Date): string {
|
|
40
54
|
return StringUtils.pad(date.getSeconds(), 2);
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
public static
|
|
57
|
+
public static formatDate(d: Date): string {
|
|
44
58
|
return this.year(d) + '-' + this.month(d) + '-' + this.date(d);
|
|
45
59
|
}
|
|
46
60
|
|
|
@@ -57,7 +71,7 @@ export class DateUtils {
|
|
|
57
71
|
* @param d
|
|
58
72
|
* @returns {string} 2020年1月30日
|
|
59
73
|
*/
|
|
60
|
-
public static
|
|
74
|
+
public static formatDateCn(d: Date): string {
|
|
61
75
|
return this.year(d) + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
|
|
62
76
|
}
|
|
63
77
|
|
|
@@ -76,11 +90,11 @@ export class DateUtils {
|
|
|
76
90
|
return this.formatDate(new Date());
|
|
77
91
|
}
|
|
78
92
|
|
|
79
|
-
public static
|
|
93
|
+
public static thisYear(): number {
|
|
80
94
|
return this.year(new Date());
|
|
81
95
|
}
|
|
82
96
|
|
|
83
|
-
public static
|
|
97
|
+
public static thisMonth(): string {
|
|
84
98
|
return this.month(new Date());
|
|
85
99
|
}
|
|
86
100
|
|
|
@@ -88,7 +102,7 @@ export class DateUtils {
|
|
|
88
102
|
* 显示友好时间,如 2小时前,1周前
|
|
89
103
|
* @param pastDate 日期, 支持Date,String,Number
|
|
90
104
|
*/
|
|
91
|
-
public static
|
|
105
|
+
public static friendlyTime(pastDate: Date | string | number): string | undefined {
|
|
92
106
|
if (pastDate == null) {
|
|
93
107
|
return undefined;
|
|
94
108
|
}
|
|
@@ -165,7 +179,7 @@ export class DateUtils {
|
|
|
165
179
|
return min + '分' + seconds + '秒';
|
|
166
180
|
}
|
|
167
181
|
|
|
168
|
-
public static
|
|
182
|
+
public static beginOfMonth(): string {
|
|
169
183
|
const d = new Date();
|
|
170
184
|
d.setDate(1);
|
|
171
185
|
return this.formatDate(d);
|
|
@@ -88,21 +88,21 @@ export class MessageUtils {
|
|
|
88
88
|
/**
|
|
89
89
|
* 成功消息
|
|
90
90
|
*/
|
|
91
|
-
static success(content:
|
|
91
|
+
static success(content: String, duration: number = 3) {
|
|
92
92
|
this.messageApi.success(content, duration);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* 错误消息
|
|
97
97
|
*/
|
|
98
|
-
static error(content:
|
|
98
|
+
static error(content: String, duration: number = 3) {
|
|
99
99
|
this.messageApi.error(content, duration);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
103
|
* 警告消息
|
|
104
104
|
*/
|
|
105
|
-
static warning(content:
|
|
105
|
+
static warning(content: String, duration: number = 3) {
|
|
106
106
|
this.messageApi.warning(content, duration);
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -116,13 +116,15 @@ export class MessageUtils {
|
|
|
116
116
|
/**
|
|
117
117
|
* 弹出 Loading 提示
|
|
118
118
|
*/
|
|
119
|
-
static loading(content:
|
|
120
|
-
|
|
119
|
+
static loading(content: string = '正在加载...', duration?: number) {
|
|
120
|
+
duration = duration === undefined ? 0 : duration;
|
|
121
|
+
return this.messageApi.loading(content, duration);
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
static config(messageApi: MessageInstance, modalApi: HookAPI) {
|
|
124
125
|
this.messageApi = messageApi;
|
|
125
126
|
this.modalApi = modalApi;
|
|
127
|
+
console.log('MessageUtils.config', messageApi, modalApi)
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
private static modalApi:HookAPI = null;
|
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export class ObjectUtils {
|
|
5
5
|
|
|
6
|
+
static clone(obj:any){
|
|
7
|
+
return JSON.parse(JSON.stringify(obj));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
6
11
|
/**
|
|
7
12
|
* 🎯 安全地获取深度嵌套的对象属性的值。
|
|
8
13
|
* 如果属性链中的任何一级为 undefined 或 null,getDefinition 函数会返回一个默认值,而不是抛出错误。
|
|
@@ -21,93 +26,93 @@ export class ObjectUtils {
|
|
|
21
26
|
*/
|
|
22
27
|
static get<TObj extends object, TDefault = unknown>(
|
|
23
28
|
obj: TObj | null | undefined,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
): unknown | TDefault {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
29
|
+
path: string | (keyof TObj)[],
|
|
30
|
+
defaultValue: TDefault | undefined = undefined
|
|
31
|
+
): unknown | TDefault {
|
|
32
|
+
|
|
33
|
+
// 路径处理:将 'a[0].b.c' 转换为 ['a', '0', 'b', 'c'] 以支持数组索引
|
|
34
|
+
// 注意:这里简化处理,只处理点分隔符,如果需要完整的 lodash getDefinition 行为,需要更复杂的正则解析。
|
|
35
|
+
const pathArray: string[] = Array.isArray(path)
|
|
36
|
+
? path.map(String) // 确保路径段都是字符串
|
|
37
|
+
: path.split('.');
|
|
38
|
+
|
|
39
|
+
let result: any = obj;
|
|
40
|
+
|
|
41
|
+
// 遍历路径
|
|
42
|
+
for (const segment of pathArray) {
|
|
43
|
+
// 如果当前结果是 null 或 undefined,则后续路径无法访问,返回默认值
|
|
44
|
+
if (result == null) {
|
|
45
|
+
return defaultValue;
|
|
46
|
+
}
|
|
42
47
|
|
|
43
48
|
// 尝试访问属性
|
|
44
49
|
// 使用 segment 作为索引,TypeScript 默认这里是合法的
|
|
45
|
-
result = result[segment];
|
|
46
|
-
}
|
|
50
|
+
result = result[segment];
|
|
51
|
+
}
|
|
47
52
|
|
|
48
53
|
// 如果最终结果是 null 或 undefined,则返回默认值;否则返回结果
|
|
49
|
-
return result !== null && result !== undefined ? result : defaultValue;
|
|
50
|
-
}
|
|
54
|
+
return result !== null && result !== undefined ? result : defaultValue;
|
|
55
|
+
}
|
|
51
56
|
|
|
52
57
|
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
static copyPropertyIfPresent<TSource extends object, TTarget extends object>(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
): void {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
58
|
+
/**
|
|
59
|
+
* 📋 复制对象属性,仅复制源对象 (source) 中 **存在** 且目标对象 (target) 中 **也有** 对应属性的那些值。
|
|
60
|
+
* 主要用于根据目标对象的结构来过滤和填充数据。
|
|
61
|
+
*
|
|
62
|
+
* @param source 源对象。
|
|
63
|
+
* @param target 目标对象。
|
|
64
|
+
* @returns void
|
|
65
|
+
*/
|
|
66
|
+
static copyPropertyIfPresent<TSource extends object, TTarget extends object>(
|
|
67
|
+
source: TSource | null | undefined,
|
|
68
|
+
target: TTarget | null | undefined
|
|
69
|
+
): void {
|
|
70
|
+
if (!source || !target || typeof source !== 'object' || typeof target !== 'object') {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
68
73
|
|
|
69
74
|
// 遍历目标对象的键,确保我们只复制目标对象上已有的属性
|
|
70
|
-
const keys = Object.keys(target) as (keyof TTarget)[];
|
|
71
|
-
|
|
72
|
-
for (const key of keys) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
const keys = Object.keys(target) as (keyof TTarget)[];
|
|
76
|
+
|
|
77
|
+
for (const key of keys) {
|
|
78
|
+
// 检查源对象是否有这个属性
|
|
79
|
+
if (Object.hasOwn(source, key)) {
|
|
80
|
+
// 因为目标对象和源对象都被约束为 object,所以这里的类型转换是相对安全的
|
|
81
|
+
const value = (source as any)[key];
|
|
82
|
+
(target as any)[key] = value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
78
85
|
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
86
|
|
|
82
87
|
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
static copyProperty<TSource extends object, TTarget extends object>(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
): void {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
88
|
+
/**
|
|
89
|
+
* 📝 复制对象属性,将源对象 (source) 中 **非 undefined** 的属性值复制到目标对象 (target) 对应的属性上。
|
|
90
|
+
* 仅复制目标对象 (target) 中 **已有** 的属性,如果源对象中的值是 undefined 则不复制。
|
|
91
|
+
*
|
|
92
|
+
* @param source 源对象。
|
|
93
|
+
* @param target 目标对象。
|
|
94
|
+
* @returns void
|
|
95
|
+
*/
|
|
96
|
+
static copyProperty<TSource extends object, TTarget extends object>(
|
|
97
|
+
source: TSource | null | undefined,
|
|
98
|
+
target: TTarget | null | undefined
|
|
99
|
+
): void {
|
|
100
|
+
if (!source || !target || typeof source !== 'object' || typeof target !== 'object') {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
98
103
|
|
|
99
104
|
// 遍历目标对象的键
|
|
100
|
-
const keys = Object.keys(target) as (keyof TTarget)[];
|
|
105
|
+
const keys = Object.keys(target) as (keyof TTarget)[];
|
|
101
106
|
|
|
102
|
-
for (const key of keys) {
|
|
103
|
-
|
|
104
|
-
|
|
107
|
+
for (const key of keys) {
|
|
108
|
+
// 尝试从源对象获取值
|
|
109
|
+
const value = (source as any)[key];
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
// 只有当值明确不是 undefined 时才复制(即允许复制 null 或其他 falsy 值)
|
|
112
|
+
if (value !== undefined) {
|
|
113
|
+
(target as any)[key] = value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
109
116
|
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
117
|
|
|
113
118
|
}
|
|
@@ -113,11 +113,14 @@ export class TreeUtils {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
|
-
*
|
|
116
|
+
* 深度优先遍历树节点。
|
|
117
117
|
* @param tree 树节点数组
|
|
118
118
|
* @param callback 对每个节点执行的回调函数
|
|
119
119
|
*/
|
|
120
120
|
public static walk<T extends TreeNode>(tree: T[], callback: (node: T) => void): void {
|
|
121
|
+
if(tree == null){
|
|
122
|
+
return
|
|
123
|
+
}
|
|
121
124
|
for (const node of tree) {
|
|
122
125
|
callback(node); // 执行回调函数
|
|
123
126
|
|
|
@@ -129,7 +132,7 @@ export class TreeUtils {
|
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
/**
|
|
132
|
-
*
|
|
135
|
+
* 根据键值深度查找单个节点。
|
|
133
136
|
* @param key 要查找的键值 (例如: 节点的 id)
|
|
134
137
|
* @param list 树节点数组
|
|
135
138
|
* @param keyName 要匹配的字段名,默认为 'id'
|
|
@@ -10,7 +10,7 @@ import {Gap, HttpUtils, NamedIcon, PageUtils, SysUtils, ThemeUtils, TreeUtils} f
|
|
|
10
10
|
import HeaderRight from "./HeaderRight";
|
|
11
11
|
import TabPageRender from "./TabPageRender";
|
|
12
12
|
|
|
13
|
-
const {Header,
|
|
13
|
+
const {Header, Sider, Content} = Layout;
|
|
14
14
|
/**
|
|
15
15
|
* 带菜单的布局,主要处理布局宇框架结构
|
|
16
16
|
*/
|
|
@@ -99,7 +99,7 @@ export default class extends React.Component {
|
|
|
99
99
|
<Header className='header'>
|
|
100
100
|
<div className='header-left'>
|
|
101
101
|
{siteInfo.logoUrl &&
|
|
102
|
-
<img className='logo-img' src=
|
|
102
|
+
<img className='logo-img' src={siteInfo.logoUrl} onClick={() => history.push('/')} alt='logo'/>}
|
|
103
103
|
<h3 className='hide-on-mobile'>
|
|
104
104
|
<Link to="/" style={{color: ThemeUtils.getColor("primary-color")}}>{siteInfo.title} </Link>
|
|
105
105
|
</h3>
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {Button, Card, Form, Input, message, Radio, Spin, Splitter,} from "antd";
|
|
2
|
+
import {Button, Card, Empty, Form, Input, message, Modal, Radio, Spin, Splitter, Table, Tabs, Typography,} from "antd";
|
|
3
3
|
import {history} from "umi";
|
|
4
|
-
import {HttpUtils, Page, PageUtils} from "../../../framework";
|
|
5
|
-
import
|
|
4
|
+
import {FormRegistryUtils, Gap, HttpUtils, Page, PageUtils} from "../../../framework";
|
|
5
|
+
import {FormOutlined, ShareAltOutlined} from "@ant-design/icons";
|
|
6
6
|
|
|
7
7
|
export default class extends React.Component {
|
|
8
8
|
|
|
9
9
|
state = {
|
|
10
10
|
submitLoading: false,
|
|
11
|
-
taskId: null,
|
|
12
|
-
instanceId: null,
|
|
13
|
-
formKey: null,
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
|
|
13
|
+
instanceCommentList: [],
|
|
14
|
+
vars: {},
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
data: {
|
|
18
|
+
taskId: null,
|
|
19
|
+
commentList: [],
|
|
20
|
+
img: null
|
|
21
|
+
},
|
|
22
|
+
loading: true,
|
|
23
|
+
|
|
24
|
+
errorMsg: null
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
|
|
@@ -20,16 +29,31 @@ export default class extends React.Component {
|
|
|
20
29
|
externalFormRef = React.createRef()
|
|
21
30
|
|
|
22
31
|
componentDidMount() {
|
|
23
|
-
const {taskId
|
|
24
|
-
this.setState({taskId, instanceId, formKey})
|
|
32
|
+
const {taskId} = PageUtils.currentParams()
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.setState({
|
|
34
|
+
|
|
35
|
+
HttpUtils.get("admin/flowable/my/getInstanceInfoByTaskId", {taskId}).then(rs => {
|
|
36
|
+
this.setState({data: rs})
|
|
37
|
+
}).catch(e => {
|
|
38
|
+
this.setState({errorMsg: e})
|
|
39
|
+
}).finally(() => {
|
|
40
|
+
this.setState({loading: false})
|
|
29
41
|
})
|
|
30
42
|
|
|
43
|
+
|
|
31
44
|
}
|
|
32
45
|
|
|
46
|
+
onImgClick = () => {
|
|
47
|
+
Modal.info({
|
|
48
|
+
title: '流程图',
|
|
49
|
+
width: '70vw',
|
|
50
|
+
content: <div style={{width: '100%', overflow: 'auto', maxHeight: '80vh'}}>
|
|
51
|
+
<img src={this.state.data.img}/>
|
|
52
|
+
</div>
|
|
53
|
+
})
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
|
|
33
57
|
handleTask = async value => {
|
|
34
58
|
this.setState({submitLoading: true});
|
|
35
59
|
try {
|
|
@@ -40,8 +64,8 @@ export default class extends React.Component {
|
|
|
40
64
|
}
|
|
41
65
|
}
|
|
42
66
|
|
|
43
|
-
value.taskId = this.state.taskId
|
|
44
|
-
await HttpUtils.post("admin
|
|
67
|
+
value.taskId = this.state.data.taskId
|
|
68
|
+
await HttpUtils.post("admin/flowable/my/handleTask", value)
|
|
45
69
|
history.replace('/flowable/task')
|
|
46
70
|
} catch (error) {
|
|
47
71
|
message.error(error)
|
|
@@ -52,16 +76,37 @@ export default class extends React.Component {
|
|
|
52
76
|
}
|
|
53
77
|
|
|
54
78
|
render() {
|
|
55
|
-
const {submitLoading
|
|
56
|
-
|
|
57
|
-
|
|
79
|
+
const {submitLoading} = this.state
|
|
80
|
+
|
|
81
|
+
const {data, loading} = this.state
|
|
82
|
+
const {commentList, img} = data
|
|
83
|
+
if(loading){
|
|
58
84
|
return <Spin/>
|
|
59
85
|
}
|
|
60
86
|
return <Page padding>
|
|
61
87
|
|
|
62
88
|
<Splitter>
|
|
63
89
|
<Splitter.Panel>
|
|
64
|
-
<
|
|
90
|
+
<Typography.Title level={4}>{data.name}</Typography.Title>
|
|
91
|
+
<Typography.Text type="secondary">{data.starter} {data.startTime}</Typography.Text>
|
|
92
|
+
<Gap></Gap>
|
|
93
|
+
<Tabs
|
|
94
|
+
items={[
|
|
95
|
+
{
|
|
96
|
+
key: '1',
|
|
97
|
+
label: '表单',
|
|
98
|
+
icon: <FormOutlined/>,
|
|
99
|
+
children: this.renderForm()
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: '2',
|
|
103
|
+
label: '流程',
|
|
104
|
+
icon: <ShareAltOutlined/>,
|
|
105
|
+
children: this.renderProcess(img, commentList)
|
|
106
|
+
}
|
|
107
|
+
]}>
|
|
108
|
+
|
|
109
|
+
</Tabs>
|
|
65
110
|
</Splitter.Panel>
|
|
66
111
|
<Splitter.Panel defaultSize={400}>
|
|
67
112
|
<Card title='审批意见'>
|
|
@@ -70,6 +115,7 @@ export default class extends React.Component {
|
|
|
70
115
|
onFinish={this.handleTask}
|
|
71
116
|
disabled={submitLoading}
|
|
72
117
|
>
|
|
118
|
+
|
|
73
119
|
<Form.Item label='审批结果' name='result' rules={[{required: true, message: '请选择'}]}
|
|
74
120
|
initialValue={'APPROVE'}>
|
|
75
121
|
<Radio.Group>
|
|
@@ -96,4 +142,45 @@ export default class extends React.Component {
|
|
|
96
142
|
|
|
97
143
|
|
|
98
144
|
}
|
|
145
|
+
|
|
146
|
+
renderProcess = (img, commentList) => <Card title='处理记录'>
|
|
147
|
+
<img src={img} style={{maxWidth: '100%'}}
|
|
148
|
+
onClick={this.onImgClick}/>
|
|
149
|
+
<Gap></Gap>
|
|
150
|
+
<Table dataSource={commentList}
|
|
151
|
+
|
|
152
|
+
size='small'
|
|
153
|
+
pagination={false}
|
|
154
|
+
rowKey='id'
|
|
155
|
+
columns={[
|
|
156
|
+
{
|
|
157
|
+
dataIndex: 'content',
|
|
158
|
+
title: '操作'
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
dataIndex: 'user',
|
|
162
|
+
title: '处理人'
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
dataIndex: 'time',
|
|
166
|
+
title: '处理时间'
|
|
167
|
+
},
|
|
168
|
+
]}
|
|
169
|
+
/>
|
|
170
|
+
</Card>;
|
|
171
|
+
|
|
172
|
+
renderForm = () => {
|
|
173
|
+
const {data} = this.state
|
|
174
|
+
const {businessKey} = data
|
|
175
|
+
const formKey = data.formKey;
|
|
176
|
+
const formName = data.formKey + 'Form'
|
|
177
|
+
|
|
178
|
+
let ExForm = FormRegistryUtils.get(formName);
|
|
179
|
+
if (!ExForm) {
|
|
180
|
+
console.error(" 表单不存在: "+formName+"。 请检查表单源代码:src/forms/"+formName+".jsx")
|
|
181
|
+
return <Empty description={"表单不存在: " + formName}></Empty>
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return <ExForm id={businessKey} formKey={formKey} ref={this.externalFormRef} ></ExForm>
|
|
185
|
+
}
|
|
99
186
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {Button,
|
|
3
|
-
import {HttpUtils, LinkButton,
|
|
4
|
-
import InstanceInfo from "../InstanceInfo";
|
|
2
|
+
import {Button, Tabs} from "antd";
|
|
3
|
+
import {HttpUtils, LinkButton, Page, PageLoading, PageUtils, ProTable} from "../../../framework";
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
export default class extends React.Component {
|
|
@@ -66,10 +65,7 @@ export default class extends React.Component {
|
|
|
66
65
|
title: '操作',
|
|
67
66
|
dataIndex: 'option',
|
|
68
67
|
render: (_, record) => {
|
|
69
|
-
let path = '/flowable/task/form?taskId=' + record.id
|
|
70
|
-
if (record.formKey) {
|
|
71
|
-
path += "&formKey=" + record.formKey
|
|
72
|
-
}
|
|
68
|
+
let path = '/flowable/task/form?taskId=' + record.id;
|
|
73
69
|
return (
|
|
74
70
|
<LinkButton
|
|
75
71
|
type='primary'
|
|
@@ -124,13 +120,7 @@ export default class extends React.Component {
|
|
|
124
120
|
title: '操作',
|
|
125
121
|
dataIndex: 'option',
|
|
126
122
|
render: (_, record) => (
|
|
127
|
-
|
|
128
|
-
Modal.info({
|
|
129
|
-
title: '流程信息',
|
|
130
|
-
width: '800vw',
|
|
131
|
-
content: <InstanceInfo id={record.instanceId}/>
|
|
132
|
-
})
|
|
133
|
-
}}> 查看 </Button>
|
|
123
|
+
<Button size='small' onClick={() => PageUtils.open('/flowable/task/instance/view?id='+record.id, '流程信息') }> 查看 </Button>
|
|
134
124
|
),
|
|
135
125
|
},
|
|
136
126
|
]}
|
|
@@ -185,14 +175,9 @@ export default class extends React.Component {
|
|
|
185
175
|
title: '操作',
|
|
186
176
|
dataIndex: 'option',
|
|
187
177
|
render: (_, record) => (
|
|
188
|
-
|
|
189
|
-
MessageUtils.alert(<InstanceInfo id={record.id}/>, {
|
|
190
|
-
width: '80vw',
|
|
191
|
-
title: '流程信息'
|
|
192
|
-
})
|
|
178
|
+
<Button size='small' onClick={() => PageUtils.open('/flowable/task/instance/view?id='+record.id, '流程信息') }> 查看 </Button>
|
|
193
179
|
|
|
194
|
-
|
|
195
|
-
),
|
|
180
|
+
),
|
|
196
181
|
},
|
|
197
182
|
]}
|
|
198
183
|
/>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {Gap, HttpUtils, Page, PageUtils, ProTable} from "../../../../framework";
|
|
3
|
+
import {Card, Empty, Skeleton, Table} from "antd";
|
|
4
|
+
|
|
5
|
+
export default class extends React.Component {
|
|
6
|
+
state = {
|
|
7
|
+
instanceCommentList: [],
|
|
8
|
+
vars: {},
|
|
9
|
+
|
|
10
|
+
id: null,
|
|
11
|
+
starter: null,
|
|
12
|
+
startTime: null,
|
|
13
|
+
name: null,
|
|
14
|
+
|
|
15
|
+
data: {
|
|
16
|
+
commentList: [],
|
|
17
|
+
img: null
|
|
18
|
+
},
|
|
19
|
+
loading: true,
|
|
20
|
+
|
|
21
|
+
errorMsg: null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
componentDidMount() {
|
|
26
|
+
const { id} = PageUtils.currentParams()
|
|
27
|
+
|
|
28
|
+
HttpUtils.get("admin/flowable/my/getInstanceInfo", {id}).then(rs => {
|
|
29
|
+
this.setState(rs)
|
|
30
|
+
this.setState({data: rs})
|
|
31
|
+
}).catch(e => {
|
|
32
|
+
this.setState({errorMsg: e})
|
|
33
|
+
}).finally(() => {
|
|
34
|
+
this.setState({loading: false})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
render() {
|
|
41
|
+
|
|
42
|
+
if (this.state.errorMsg) {
|
|
43
|
+
return <Empty description={this.state.errorMsg}></Empty>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const {data, loading} = this.state
|
|
47
|
+
const {commentList, img} = data
|
|
48
|
+
if (loading) {
|
|
49
|
+
return <Skeleton/>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
return <Page padding>
|
|
54
|
+
<Card title='流程图'>
|
|
55
|
+
<img src={img} style={{maxWidth: '100%'}}/>
|
|
56
|
+
</Card>
|
|
57
|
+
<Gap/>
|
|
58
|
+
<Card title='审批记录'>
|
|
59
|
+
<Table dataSource={commentList}
|
|
60
|
+
size='small'
|
|
61
|
+
pagination={false}
|
|
62
|
+
rowKey='id'
|
|
63
|
+
columns={[
|
|
64
|
+
{
|
|
65
|
+
dataIndex: 'content',
|
|
66
|
+
title: '操作'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
dataIndex: 'user',
|
|
70
|
+
title: '处理人'
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
dataIndex: 'time',
|
|
74
|
+
title: '处理时间'
|
|
75
|
+
},
|
|
76
|
+
]}
|
|
77
|
+
/>
|
|
78
|
+
</Card>
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
</Page>
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
}
|
package/src/pages/login.jsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
3
|
import {LoginPage} from "../framework/pages/LoginPage";
|
|
4
|
+
import {Button} from "antd";
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
export default class extends React.Component {
|
|
@@ -9,8 +10,9 @@ export default class extends React.Component {
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
render() {
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
return <LoginPage />
|
|
14
|
+
// 支持自定义
|
|
15
|
+
// return <LoginPage form={<Button type={"primary"} size='large'>xx登录</Button>} />
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import {Card, Empty, Modal, Skeleton, Table, Tabs, Typography} from "antd";
|
|
3
|
-
|
|
4
|
-
import {FormOutlined, ShareAltOutlined} from "@ant-design/icons";
|
|
5
|
-
import {FormRegistryUtils, Gap, HttpUtils} from "../../framework";
|
|
6
|
-
|
|
7
|
-
export default class InstanceInfo extends React.Component {
|
|
8
|
-
|
|
9
|
-
state = {
|
|
10
|
-
instanceCommentList: [],
|
|
11
|
-
vars: {},
|
|
12
|
-
|
|
13
|
-
id: null,
|
|
14
|
-
starter: null,
|
|
15
|
-
startTime: null,
|
|
16
|
-
name: null,
|
|
17
|
-
|
|
18
|
-
data: {
|
|
19
|
-
commentList: [],
|
|
20
|
-
img: null
|
|
21
|
-
},
|
|
22
|
-
loading: true,
|
|
23
|
-
|
|
24
|
-
errorMsg: null
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
componentDidMount() {
|
|
29
|
-
const {id, businessKey} = this.props;
|
|
30
|
-
HttpUtils.get("admin/flowable/my/getInstanceInfo", {id, businessKey}).then(rs => {
|
|
31
|
-
this.setState(rs)
|
|
32
|
-
this.setState({data: rs})
|
|
33
|
-
}).catch(e => {
|
|
34
|
-
this.setState({errorMsg: e})
|
|
35
|
-
}).finally(() => {
|
|
36
|
-
this.setState({loading: false})
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
onImgClick = () => {
|
|
42
|
-
const {data} = this.state
|
|
43
|
-
|
|
44
|
-
const {img} = data
|
|
45
|
-
Modal.info({
|
|
46
|
-
title: '流程图',
|
|
47
|
-
width: '70vw',
|
|
48
|
-
content: <div style={{width: '100%', overflow: 'auto', maxHeight: '80vh'}}><img src={img}/></div>
|
|
49
|
-
})
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
render() {
|
|
53
|
-
if (this.state.errorMsg) {
|
|
54
|
-
return <Empty description={this.state.errorMsg}></Empty>
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const {data, loading} = this.state
|
|
58
|
-
const {commentList, img} = data
|
|
59
|
-
if (loading) {
|
|
60
|
-
return <Skeleton/>
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return <>
|
|
65
|
-
<Typography.Title level={4}>{data.name}</Typography.Title>
|
|
66
|
-
<Typography.Text type="secondary">{data.starter} {data.startTime}</Typography.Text>
|
|
67
|
-
<Gap></Gap>
|
|
68
|
-
<Tabs
|
|
69
|
-
items={[
|
|
70
|
-
{
|
|
71
|
-
key: '1',
|
|
72
|
-
label: '表单',
|
|
73
|
-
icon: <FormOutlined/>,
|
|
74
|
-
children: this.renderForm()
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
key: '2',
|
|
78
|
-
label: '流程',
|
|
79
|
-
icon: <ShareAltOutlined/>,
|
|
80
|
-
children: this.renderProcess(img, commentList)
|
|
81
|
-
}
|
|
82
|
-
]}>
|
|
83
|
-
|
|
84
|
-
</Tabs>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
</>
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
renderProcess = (img, commentList) => <Card title='处理记录'>
|
|
92
|
-
{img && <img src={img} style={{maxWidth: '100%'}}
|
|
93
|
-
onClick={this.onImgClick}/>}
|
|
94
|
-
<Gap></Gap>
|
|
95
|
-
<Table dataSource={commentList}
|
|
96
|
-
|
|
97
|
-
size='small'
|
|
98
|
-
pagination={false}
|
|
99
|
-
rowKey='id'
|
|
100
|
-
columns={[
|
|
101
|
-
{
|
|
102
|
-
dataIndex: 'content',
|
|
103
|
-
title: '操作'
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
dataIndex: 'user',
|
|
107
|
-
title: '处理人'
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
dataIndex: 'time',
|
|
111
|
-
title: '处理时间'
|
|
112
|
-
},
|
|
113
|
-
]}
|
|
114
|
-
/>
|
|
115
|
-
</Card>;
|
|
116
|
-
|
|
117
|
-
renderForm = () => {
|
|
118
|
-
const {data} = this.state
|
|
119
|
-
const {processDefinitionKey, businessKey} = data
|
|
120
|
-
const formKey = this.props.formKey || processDefinitionKey;
|
|
121
|
-
const formName = formKey + 'Form'
|
|
122
|
-
|
|
123
|
-
// let formKey = this.props.formKey || processDefinitionKey + 'Form';
|
|
124
|
-
let ExForm = FormRegistryUtils.get(formName);
|
|
125
|
-
if (!ExForm) {
|
|
126
|
-
return <div>
|
|
127
|
-
<p>
|
|
128
|
-
未创建表单 {formName}。
|
|
129
|
-
</p>
|
|
130
|
-
<Typography.Text>
|
|
131
|
-
表单路径:src/forms/{formName}.jsx
|
|
132
|
-
</Typography.Text>
|
|
133
|
-
</div>
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return <ExForm id={businessKey} formKey={formKey} ref={this.props.externalFormRef} taskInfo={this.props.taskInfo}></ExForm>
|
|
137
|
-
}
|
|
138
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import InstanceInfo from "../InstanceInfo";
|
|
2
|
-
import {Page, PageUtils} from "../../../framework";
|
|
3
|
-
import React from "react";
|
|
4
|
-
|
|
5
|
-
export default class extends React.Component{
|
|
6
|
-
|
|
7
|
-
render() {
|
|
8
|
-
let params = PageUtils.currentParams();
|
|
9
|
-
const {businessKey} = params
|
|
10
|
-
return <Page padding>
|
|
11
|
-
<InstanceInfo businessKey={businessKey} />
|
|
12
|
-
</Page>
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
}
|