@jiangood/open-admin 3.0.12 → 3.0.13
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/components/ProTable/index.tsx +3 -1
- package/src/framework/fields/FieldEditor/index.tsx +56 -10
- package/src/framework/fields/FieldUploadFile/index.tsx +6 -6
- package/src/framework/fields/FieldUploadImage/index.tsx +494 -233
- package/src/framework/views/ViewImage/index.tsx +56 -50
- package/src/layouts/admin/index.less +1 -1
- package/src/pages/article/$code.jsx +20 -6
- package/src/pages/article/article.less +124 -0
- package/src/pages/system/article/index.jsx +12 -22
- package/src/pages/system/file/index.jsx +77 -93
- package/src/pages/system/job/index.jsx +1 -1
|
@@ -1,71 +1,77 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import {Image} from 'antd';
|
|
3
3
|
import {UrlUtils} from '../../utils';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 图片展示组件
|
|
7
|
+
*
|
|
8
|
+
* 支持的属性:
|
|
9
|
+
* - value: 图片地址,支持多个(逗号分隔或数组)。objectName(public/、private/ 开头)自动拼 /file/ 前缀
|
|
10
|
+
* - size: 缩略图尺寸(正方形边长),默认 60
|
|
11
|
+
* - borderRadius: 圆角,默认 4
|
|
12
|
+
* - preview: 是否可点击放大预览,默认 true
|
|
13
|
+
* - previewTitle: 预览弹窗标题,默认「预览图片」
|
|
14
|
+
* - placeholder: value 为空时展示的内容,默认不渲染
|
|
15
|
+
* - style: 附加到 img 的样式
|
|
16
|
+
*/
|
|
6
17
|
export class ViewImage extends React.Component {
|
|
7
18
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
static previewGroupProps = {
|
|
20
|
+
preview: {
|
|
21
|
+
scaleStep: 0.3,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
resolveUrl = (v) => {
|
|
26
|
+
const isAbsUrl = v.startsWith('http');
|
|
27
|
+
const isDataUrl = v.startsWith('data:');
|
|
28
|
+
const isObjectName = v.startsWith('public/') || v.startsWith('private/');
|
|
29
|
+
if (isAbsUrl || isDataUrl) {
|
|
30
|
+
return {url: v, thumb: v};
|
|
31
|
+
}
|
|
32
|
+
if (isObjectName) {
|
|
33
|
+
return {
|
|
34
|
+
url: UrlUtils.contextPath('/file/' + v),
|
|
35
|
+
thumb: UrlUtils.contextPath('/file/' + v + '?thumb=1'),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {url: UrlUtils.contextPath(v), thumb: UrlUtils.contextPath(v)};
|
|
11
39
|
};
|
|
12
40
|
|
|
13
41
|
render() {
|
|
14
|
-
|
|
42
|
+
const {value, size = 60, borderRadius = 4, preview = true, previewTitle = '预览图片',
|
|
43
|
+
placeholder, style} = this.props;
|
|
15
44
|
|
|
16
|
-
if (!
|
|
17
|
-
return;
|
|
45
|
+
if (!value) {
|
|
46
|
+
return placeholder || null;
|
|
18
47
|
}
|
|
19
48
|
|
|
49
|
+
let vs = value;
|
|
20
50
|
if (typeof vs === 'string') {
|
|
21
51
|
vs = vs.split(',');
|
|
22
52
|
}
|
|
23
53
|
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (isAbsUrl || isDataUrl) {
|
|
31
|
-
urlList.push(v);
|
|
32
|
-
thumbList.push(v);
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (isObjectName) {
|
|
37
|
-
urlList.push(UrlUtils.contextPath('/file/' + v));
|
|
38
|
-
thumbList.push(UrlUtils.contextPath('/file/' + v + '?thumb=1'));
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
urlList.push(UrlUtils.contextPath(v));
|
|
43
|
-
thumbList.push(UrlUtils.contextPath(v));
|
|
54
|
+
const items = vs.map(this.resolveUrl);
|
|
55
|
+
const previewConfig = {
|
|
56
|
+
scaleStep: 0.3,
|
|
57
|
+
};
|
|
58
|
+
if (previewTitle) {
|
|
59
|
+
previewConfig.title = previewTitle;
|
|
44
60
|
}
|
|
45
61
|
|
|
46
|
-
const closeModal = () => this.setState({modalOpen: false});
|
|
47
|
-
|
|
48
|
-
const imgs = thumbList.map((thumb, i) => (
|
|
49
|
-
<img
|
|
50
|
-
style={{ display: 'inline-block' }}
|
|
51
|
-
key={urlList[i]}
|
|
52
|
-
src={thumb}
|
|
53
|
-
onClick={() => this.setState({modalOpen: true, previewUrl: urlList[i]})}
|
|
54
|
-
width={60}
|
|
55
|
-
height={60}
|
|
56
|
-
/>
|
|
57
|
-
));
|
|
58
|
-
|
|
59
62
|
return (
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
<Image.PreviewGroup preview={previewConfig}>
|
|
64
|
+
{items.map((item, i) => (
|
|
65
|
+
<Image
|
|
66
|
+
key={item.url}
|
|
67
|
+
src={item.thumb}
|
|
68
|
+
width={size}
|
|
69
|
+
height={size}
|
|
70
|
+
style={{display: 'inline-block', objectFit: 'cover', borderRadius, cursor: preview ? 'pointer' : undefined, ...style}}
|
|
71
|
+
preview={preview ? {src: item.url} : false}
|
|
72
|
+
/>
|
|
73
|
+
))}
|
|
74
|
+
</Image.PreviewGroup>
|
|
69
75
|
);
|
|
70
76
|
}
|
|
71
77
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import {HttpUtils, Page, UrlUtils} from "../../framework";
|
|
3
|
+
import "./article.less";
|
|
3
4
|
|
|
4
5
|
export default class extends React.Component {
|
|
5
6
|
|
|
@@ -36,13 +37,26 @@ export default class extends React.Component {
|
|
|
36
37
|
</Page>
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
return <Page
|
|
40
|
-
|
|
41
|
-
<div
|
|
42
|
-
<
|
|
40
|
+
return <Page>
|
|
41
|
+
<div className="oa-article">
|
|
42
|
+
<div className="oa-article-title">
|
|
43
|
+
<h1>{article.title}</h1>
|
|
44
|
+
<div className="oa-article-meta">
|
|
45
|
+
{article.createUserLabel && <span>发布人:{article.createUserLabel}</span>}
|
|
46
|
+
{article.createTime && <span>发布时间:{article.createTime}</span>}
|
|
47
|
+
</div>
|
|
43
48
|
</div>
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
{article.mainImage && (
|
|
50
|
+
<div style={{marginBottom: 16, textAlign: 'center'}}>
|
|
51
|
+
<img
|
|
52
|
+
src={UrlUtils.contextPath('/file/' + article.mainImage)}
|
|
53
|
+
style={{maxWidth: '100%', maxHeight: 400, borderRadius: 4}}
|
|
54
|
+
alt='主图'
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
)}
|
|
58
|
+
<div dangerouslySetInnerHTML={{__html: article.content}}/>
|
|
59
|
+
</div>
|
|
46
60
|
</Page>
|
|
47
61
|
}
|
|
48
62
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
.oa-article {
|
|
2
|
+
max-width: 800px;
|
|
3
|
+
margin: 0 auto;
|
|
4
|
+
background: #fff;
|
|
5
|
+
padding: 24px 32px;
|
|
6
|
+
border-radius: 4px;
|
|
7
|
+
font-size: 15px;
|
|
8
|
+
line-height: 1.8;
|
|
9
|
+
color: rgba(0, 0, 0, 0.88);
|
|
10
|
+
word-wrap: break-word;
|
|
11
|
+
|
|
12
|
+
.oa-article-title {
|
|
13
|
+
text-align: center;
|
|
14
|
+
padding-bottom: 16px;
|
|
15
|
+
margin-bottom: 16px;
|
|
16
|
+
border-bottom: 1px solid #eee;
|
|
17
|
+
|
|
18
|
+
h1 {
|
|
19
|
+
font-size: 26px;
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
line-height: 1.4;
|
|
22
|
+
margin: 0 0 8px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.oa-article-meta {
|
|
26
|
+
color: #999;
|
|
27
|
+
font-size: 13px;
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
gap: 16px;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
p {
|
|
35
|
+
margin: 0 0 16px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
h1, h2, h3, h4, h5, h6 {
|
|
39
|
+
margin: 24px 0 12px;
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
line-height: 1.4;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
h1 { font-size: 24px; }
|
|
45
|
+
h2 { font-size: 21px; }
|
|
46
|
+
h3 { font-size: 18px; }
|
|
47
|
+
h4 { font-size: 16px; }
|
|
48
|
+
h5, h6 { font-size: 15px; }
|
|
49
|
+
|
|
50
|
+
ul, ol {
|
|
51
|
+
margin: 0 0 16px;
|
|
52
|
+
padding-left: 24px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
li {
|
|
56
|
+
margin-bottom: 4px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
img {
|
|
60
|
+
max-width: 100%;
|
|
61
|
+
height: auto;
|
|
62
|
+
display: block;
|
|
63
|
+
margin: 0 auto 16px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
a {
|
|
67
|
+
color: #1677ff;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
blockquote {
|
|
71
|
+
margin: 0 0 16px;
|
|
72
|
+
padding: 8px 16px;
|
|
73
|
+
border-left: 4px solid #e8e8e8;
|
|
74
|
+
background: #fafafa;
|
|
75
|
+
color: #666;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pre {
|
|
79
|
+
background: #f6f8fa;
|
|
80
|
+
padding: 12px 16px;
|
|
81
|
+
border-radius: 4px;
|
|
82
|
+
overflow-x: auto;
|
|
83
|
+
margin: 0 0 16px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
code {
|
|
87
|
+
background: #f6f8fa;
|
|
88
|
+
padding: 2px 4px;
|
|
89
|
+
border-radius: 3px;
|
|
90
|
+
font-size: 90%;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
pre code {
|
|
94
|
+
padding: 0;
|
|
95
|
+
background: none;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
table {
|
|
99
|
+
border-collapse: collapse;
|
|
100
|
+
margin: 0 0 16px;
|
|
101
|
+
width: 100%;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
th, td {
|
|
105
|
+
border: 1px solid #e0e0e0;
|
|
106
|
+
padding: 8px 12px;
|
|
107
|
+
text-align: left;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
th {
|
|
111
|
+
background: #f5f5f5;
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
hr {
|
|
116
|
+
border: none;
|
|
117
|
+
border-top: 1px solid #eee;
|
|
118
|
+
margin: 24px 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@media screen and (max-width: 600px) {
|
|
122
|
+
padding: 16px;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {PlusOutlined} from '@ant-design/icons'
|
|
2
|
-
import {Button, Form, Input, InputNumber
|
|
2
|
+
import {Button, Form, Input, InputNumber} from 'antd'
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import {
|
|
5
5
|
DictUtils,
|
|
@@ -10,18 +10,16 @@ import {
|
|
|
10
10
|
FormModal,
|
|
11
11
|
HttpUtils,
|
|
12
12
|
Page,
|
|
13
|
+
PageUtils,
|
|
13
14
|
PermActions,
|
|
14
15
|
ProTable,
|
|
15
|
-
|
|
16
|
+
ViewImage
|
|
16
17
|
} from "../../../framework";
|
|
17
18
|
|
|
18
|
-
const {TextArea} = Input;
|
|
19
|
-
|
|
20
19
|
export default class extends React.Component {
|
|
21
20
|
|
|
22
21
|
state = {
|
|
23
22
|
editing: false,
|
|
24
|
-
previewArticle: null,
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
modalRef = React.createRef()
|
|
@@ -38,7 +36,7 @@ export default class extends React.Component {
|
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
handlePreview = record => {
|
|
41
|
-
|
|
39
|
+
PageUtils.open('/article/' + record.code, record.title)
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
onFinish = async values => {
|
|
@@ -63,6 +61,14 @@ export default class extends React.Component {
|
|
|
63
61
|
title: '标题',
|
|
64
62
|
dataIndex: 'title',
|
|
65
63
|
},
|
|
64
|
+
{
|
|
65
|
+
title: '主图',
|
|
66
|
+
dataIndex: 'mainImage',
|
|
67
|
+
width: 80,
|
|
68
|
+
render(v) {
|
|
69
|
+
return <ViewImage value={v} size={48}/>
|
|
70
|
+
},
|
|
71
|
+
},
|
|
66
72
|
{
|
|
67
73
|
title: '显示位置',
|
|
68
74
|
dataIndex: 'position',
|
|
@@ -99,7 +105,6 @@ export default class extends React.Component {
|
|
|
99
105
|
]
|
|
100
106
|
|
|
101
107
|
render() {
|
|
102
|
-
const {previewArticle} = this.state
|
|
103
108
|
return <Page
|
|
104
109
|
title="文章管理"
|
|
105
110
|
description="管理系统文章,如关于、帮助等页面"
|
|
@@ -155,21 +160,6 @@ export default class extends React.Component {
|
|
|
155
160
|
<FieldBoolean/>
|
|
156
161
|
</Form.Item>
|
|
157
162
|
</FormModal>
|
|
158
|
-
|
|
159
|
-
<Modal
|
|
160
|
-
open={!!previewArticle}
|
|
161
|
-
title={previewArticle?.title}
|
|
162
|
-
width={800}
|
|
163
|
-
footer={null}
|
|
164
|
-
onCancel={() => this.setState({previewArticle: null})}
|
|
165
|
-
>
|
|
166
|
-
{previewArticle?.mainImage && (
|
|
167
|
-
<div style={{marginBottom: 16}}>
|
|
168
|
-
<img src={UrlUtils.contextPath('/file/' + previewArticle.mainImage)} style={{maxWidth: '100%'}} alt='主图'/>
|
|
169
|
-
</div>
|
|
170
|
-
)}
|
|
171
|
-
<div dangerouslySetInnerHTML={{__html: previewArticle?.content || ''}}/>
|
|
172
|
-
</Modal>
|
|
173
163
|
</Page>
|
|
174
164
|
}
|
|
175
165
|
}
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {Button,
|
|
2
|
+
import {Button, Form, Input, Modal, Space} from 'antd'
|
|
3
3
|
import {CloudUploadOutlined} from "@ant-design/icons";
|
|
4
4
|
|
|
5
|
-
import {PermActions, DictUtils, FieldDateRange, FieldDictSelect, FieldUploadFile, HttpUtils, Page, ProTable, UrlUtils} from "../../../framework";
|
|
5
|
+
import {PermActions, DictUtils, FieldDateRange, FieldDictSelect, FieldUploadFile, HttpUtils, Page, ProTable, UrlUtils, ViewImage} from "../../../framework";
|
|
6
6
|
|
|
7
7
|
export default class extends React.Component {
|
|
8
8
|
|
|
9
9
|
state = {
|
|
10
10
|
formOpen: false,
|
|
11
11
|
formValues: {},
|
|
12
|
-
gridPage: 1,
|
|
13
|
-
gridList: [],
|
|
14
|
-
gridTotal: 0,
|
|
15
|
-
gridLoading: false,
|
|
16
|
-
previewUrl: undefined,
|
|
17
12
|
}
|
|
18
13
|
|
|
19
14
|
tableRef = React.createRef()
|
|
@@ -25,74 +20,105 @@ export default class extends React.Component {
|
|
|
25
20
|
})
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.setState({gridList: rs.content || [], gridTotal: Number(rs.totalElements || 0), gridPage: p})
|
|
33
|
-
}).finally(() => {
|
|
34
|
-
this.setState({gridLoading: false})
|
|
23
|
+
handleBatchDelete = ids => {
|
|
24
|
+
HttpUtils.post('admin/sysFile/deleteBatch', ids).then(rs => {
|
|
25
|
+
this.tableRef.current.reload()
|
|
26
|
+
this.tableRef.current.clearSelection()
|
|
35
27
|
})
|
|
36
28
|
}
|
|
37
29
|
|
|
38
30
|
columns = [
|
|
31
|
+
{
|
|
32
|
+
title: '缩略图',
|
|
33
|
+
dataIndex: 'objectName',
|
|
34
|
+
width: 80,
|
|
35
|
+
render: (objectName, record) => {
|
|
36
|
+
if (record.type !== 'image') {
|
|
37
|
+
return '-'
|
|
38
|
+
}
|
|
39
|
+
return <ViewImage value={objectName} size={48}/>
|
|
40
|
+
},
|
|
41
|
+
},
|
|
39
42
|
{
|
|
40
43
|
title: '原始名称',
|
|
41
44
|
tooltip: '上传时候的文件名',
|
|
42
45
|
dataIndex: 'originName',
|
|
43
46
|
width: 200,
|
|
44
47
|
},
|
|
45
|
-
{
|
|
46
|
-
title: '状态',
|
|
47
|
-
dataIndex: 'status',
|
|
48
|
-
width: 120,
|
|
49
|
-
render(status) {
|
|
50
|
-
return DictUtils.dictTag('fileStatus', status) || (status || '-')
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
48
|
{
|
|
54
49
|
title: '存储名称',
|
|
55
50
|
dataIndex: 'objectName',
|
|
56
|
-
tooltip: '文件唯一标识id'
|
|
51
|
+
tooltip: '文件唯一标识id',
|
|
52
|
+
width: 200,
|
|
57
53
|
},
|
|
58
|
-
|
|
59
54
|
{
|
|
60
55
|
title: '文件大小',
|
|
61
56
|
dataIndex: 'sizeInfo',
|
|
57
|
+
width: 100,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: '扩展名',
|
|
61
|
+
dataIndex: 'suffix',
|
|
62
|
+
width: 90,
|
|
62
63
|
},
|
|
63
|
-
|
|
64
64
|
{
|
|
65
|
-
title: '
|
|
65
|
+
title: 'MIME',
|
|
66
66
|
dataIndex: 'mimeType',
|
|
67
|
+
width: 130,
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
|
-
title: '
|
|
70
|
-
dataIndex: '
|
|
70
|
+
title: '类型',
|
|
71
|
+
dataIndex: 'type',
|
|
72
|
+
width: 80,
|
|
73
|
+
render(v) {
|
|
74
|
+
return v || '-'
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: '状态',
|
|
79
|
+
dataIndex: 'status',
|
|
80
|
+
width: 100,
|
|
81
|
+
render(status) {
|
|
82
|
+
return DictUtils.dictTag('fileStatus', status) || (status || '-')
|
|
83
|
+
},
|
|
71
84
|
},
|
|
72
|
-
|
|
73
85
|
{
|
|
74
86
|
title: '上传时间',
|
|
75
87
|
dataIndex: 'createTime',
|
|
88
|
+
width: 160,
|
|
76
89
|
},
|
|
77
90
|
{
|
|
78
91
|
title: '上传者',
|
|
79
92
|
dataIndex: 'createUserLabel',
|
|
93
|
+
width: 100,
|
|
80
94
|
},
|
|
81
95
|
{
|
|
82
|
-
title: '
|
|
83
|
-
dataIndex: '
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
title: '关联表',
|
|
97
|
+
dataIndex: 'joinTable',
|
|
98
|
+
width: 120,
|
|
99
|
+
render(v) {
|
|
100
|
+
return v || '-'
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
title: '关联ID',
|
|
105
|
+
dataIndex: 'joinId',
|
|
106
|
+
width: 160,
|
|
107
|
+
render(v) {
|
|
108
|
+
return v || '-'
|
|
109
|
+
},
|
|
87
110
|
},
|
|
88
111
|
{
|
|
89
112
|
title: '操作',
|
|
90
113
|
dataIndex: 'option',
|
|
114
|
+
fixed: 'right',
|
|
115
|
+
width: 120,
|
|
91
116
|
render: (_, record) => (
|
|
92
117
|
<PermActions
|
|
93
118
|
more
|
|
94
119
|
size="small"
|
|
95
120
|
actions={[
|
|
121
|
+
{label: '预览', onClick: () => window.open(UrlUtils.contextPath('/file/' + record.objectName), '_blank')},
|
|
96
122
|
{label: '删除', perm: 'sys-file:delete', confirm: '是否确定删除文件信息', onClick: () => this.handleDelete(record)},
|
|
97
123
|
]}
|
|
98
124
|
/>
|
|
@@ -120,12 +146,25 @@ export default class extends React.Component {
|
|
|
120
146
|
</Modal>
|
|
121
147
|
)
|
|
122
148
|
|
|
123
|
-
|
|
124
|
-
|
|
149
|
+
render() {
|
|
150
|
+
return <Page>
|
|
125
151
|
<ProTable
|
|
126
152
|
actionRef={this.tableRef}
|
|
127
|
-
|
|
128
|
-
|
|
153
|
+
rowSelection={{}}
|
|
154
|
+
toolBarRender={(params, selection) => (
|
|
155
|
+
<Space>
|
|
156
|
+
<Button type='primary' icon={<CloudUploadOutlined/>} onClick={() => this.setState({formOpen: true})}>上传文件</Button>
|
|
157
|
+
<PermActions
|
|
158
|
+
actions={[{
|
|
159
|
+
label: `批量删除${selection.selectedRowKeys.length ? `(${selection.selectedRowKeys.length})` : ''}`,
|
|
160
|
+
perm: 'sys-file:delete',
|
|
161
|
+
danger: true,
|
|
162
|
+
disabled: !selection.selectedRowKeys.length,
|
|
163
|
+
confirm: `是否确定删除选中的 ${selection.selectedRowKeys.length} 个文件?`,
|
|
164
|
+
onClick: () => this.handleBatchDelete(selection.selectedRowKeys),
|
|
165
|
+
}]}
|
|
166
|
+
/>
|
|
167
|
+
</Space>
|
|
129
168
|
)}
|
|
130
169
|
request={(params) => {
|
|
131
170
|
return HttpUtils.get('admin/sysFile/page', params);
|
|
@@ -150,61 +189,6 @@ export default class extends React.Component {
|
|
|
150
189
|
)}
|
|
151
190
|
/>
|
|
152
191
|
{this.renderUploadModal()}
|
|
153
|
-
</>
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
renderImageGrid = () => {
|
|
157
|
-
const {gridList, gridTotal, gridPage, gridLoading, previewUrl} = this.state
|
|
158
|
-
return (
|
|
159
|
-
<div style={{minHeight: 200, position: 'relative'}}>
|
|
160
|
-
{gridList.length === 0 && !gridLoading && <Empty style={{marginTop: 80}} description="暂无图片"/>}
|
|
161
|
-
<div style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))', gap: 8}}>
|
|
162
|
-
{gridList.map(item => (
|
|
163
|
-
<div key={item.objectName}
|
|
164
|
-
style={{borderRadius: 4, overflow: 'hidden', cursor: 'pointer', border: '1px solid #eee'}}
|
|
165
|
-
onClick={() => this.setState({previewUrl: UrlUtils.contextPath('/file/' + item.objectName)})}>
|
|
166
|
-
<img
|
|
167
|
-
src={UrlUtils.contextPath('/file/' + item.objectName + '?thumb=1')}
|
|
168
|
-
style={{width: '100%', height: 120, objectFit: 'cover', display: 'block'}}
|
|
169
|
-
alt={item.originName || item.objectName}
|
|
170
|
-
/>
|
|
171
|
-
</div>
|
|
172
|
-
))}
|
|
173
|
-
</div>
|
|
174
|
-
{gridTotal > 0 && (
|
|
175
|
-
<div style={{display: 'flex', justifyContent: 'flex-end', marginTop: 16}}>
|
|
176
|
-
<Pagination
|
|
177
|
-
current={gridPage}
|
|
178
|
-
pageSize={50}
|
|
179
|
-
total={gridTotal}
|
|
180
|
-
showTotal={(total) => `共 ${total} 张`}
|
|
181
|
-
onChange={(page) => this.loadGrid(page)}
|
|
182
|
-
/>
|
|
183
|
-
</div>
|
|
184
|
-
)}
|
|
185
|
-
|
|
186
|
-
<Modal open={!!previewUrl} title="图片预览" width="70vw" footer={null}
|
|
187
|
-
onCancel={() => this.setState({previewUrl: undefined})}>
|
|
188
|
-
{previewUrl && <img src={previewUrl} style={{maxWidth: '100%'}} alt="预览"/>}
|
|
189
|
-
</Modal>
|
|
190
|
-
</div>
|
|
191
|
-
)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
render() {
|
|
195
|
-
return <Page title="文件管理" description="管理系统上传文件">
|
|
196
|
-
<Tabs
|
|
197
|
-
defaultActiveKey="table"
|
|
198
|
-
onChange={(key) => {
|
|
199
|
-
if (key === 'image' && this.state.gridList.length === 0) {
|
|
200
|
-
this.loadGrid(1)
|
|
201
|
-
}
|
|
202
|
-
}}
|
|
203
|
-
items={[
|
|
204
|
-
{key: 'table', label: '全部', children: this.renderTable()},
|
|
205
|
-
{key: 'image', label: '图片', children: this.renderImageGrid()},
|
|
206
|
-
]}
|
|
207
|
-
/>
|
|
208
192
|
</Page>
|
|
209
193
|
}
|
|
210
194
|
}
|