web-component-gallery 2.3.5 → 2.3.7
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/dist/js.umd.js +1 -1
- package/lib/browse/index.jsx +48 -21
- package/lib/descriptions-list/index.jsx +109 -66
- package/lib/descriptions-list/style/index.less +7 -0
- package/lib/form-comp/ASelectCustom.vue +3 -5
- package/lib/form-comp/style/ARangePicker.less +2 -2
- package/lib/form-comp/style/ASelectCustom.less +32 -8
- package/lib/model/Model.js +1 -4
- package/lib/model/style/index.less +4 -7
- package/lib/model/utils/render.js +2 -2
- package/lib/search/index.vue +1 -1
- package/lib/search/style/index.less +25 -25
- package/package.json +1 -1
- package/utils/Filter.js +1 -1
- package/utils/Utils.js +41 -11
package/lib/browse/index.jsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
|
2
2
|
import { Base64 } from '../../utils/Base64'
|
|
3
|
+
import { transferData } from '../../utils/Filter'
|
|
3
4
|
import { IconFont } from '../index'
|
|
4
5
|
|
|
5
6
|
const BrowseProps = {
|
|
@@ -21,41 +22,67 @@ const FILE_TYPES = {
|
|
|
21
22
|
|
|
22
23
|
// 初始化数据
|
|
23
24
|
const setInnerData = (data, https) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
25
|
+
// 处理Base64图片数据
|
|
26
|
+
if (typeof data === 'string' && data.startsWith('data:image')) {
|
|
27
|
+
return [{
|
|
28
|
+
url: data,
|
|
29
|
+
contentType: 'image',
|
|
30
|
+
name: 'base64_image'
|
|
31
|
+
}]
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
// 解析数据
|
|
35
|
+
let innerData = transferData(data, 'Array')
|
|
36
|
+
|
|
37
|
+
// 确保返回数组格式
|
|
38
|
+
const dataArray = Array.isArray(innerData) ? innerData : [innerData]
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
const { FILEURL, KKFILEURL, OVERVIEWFILEURL } = https
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
// URL前缀配置检查
|
|
43
|
+
if (!FILEURL || !KKFILEURL || !OVERVIEWFILEURL) {
|
|
44
|
+
console.warn('缺少必要的URL配置')
|
|
45
|
+
return dataArray
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 处理URL
|
|
49
|
+
return dataArray.map(dataItem => {
|
|
50
|
+
if (!dataItem || typeof dataItem !== 'object') {
|
|
51
|
+
return dataItem
|
|
43
52
|
}
|
|
44
|
-
})
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
// 如果已经是完整URL,直接返回
|
|
55
|
+
if (dataItem.url && (dataItem.url.startsWith('http') || dataItem.url.startsWith('data:image'))) {
|
|
56
|
+
return dataItem
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 构造完整URL
|
|
60
|
+
const baseUrl = getCustomTag(dataItem.url) === 'iframe' && KKFILEURL && OVERVIEWFILEURL
|
|
61
|
+
? `${KKFILEURL}${encodeURIComponent(Base64.encode(`${OVERVIEWFILEURL}${dataItem.url}`))}`
|
|
62
|
+
: `${FILEURL}${dataItem.url || ''}`;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...dataItem,
|
|
66
|
+
url: baseUrl
|
|
67
|
+
}
|
|
68
|
+
})
|
|
47
69
|
}
|
|
48
70
|
|
|
49
71
|
// 不同类型不同容器承载
|
|
50
72
|
const getCustomTag = (url) => {
|
|
73
|
+
// base64 图片处理
|
|
74
|
+
if (url.startsWith('data:image')) return 'img'
|
|
75
|
+
|
|
76
|
+
// 文件扩展名处理
|
|
51
77
|
const ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return 'iframe'
|
|
78
|
+
return FILE_TYPES.PICTURE.includes(ext) ? 'img' :
|
|
79
|
+
FILE_TYPES.AUDIO.includes(ext) ? 'audio' :
|
|
80
|
+
FILE_TYPES.VIDEO.includes(ext) ? 'video' : 'iframe'
|
|
56
81
|
}
|
|
57
82
|
|
|
58
83
|
function renderContent(h, {url, name}, images) {
|
|
84
|
+
if (!url) return
|
|
85
|
+
|
|
59
86
|
const { isThumb, astrictH, $viewerApi, $postM } = this
|
|
60
87
|
|
|
61
88
|
const MEDIA_TYPES = {
|
|
@@ -5,24 +5,51 @@ import { transferData } from '../../utils/Filter.js'
|
|
|
5
5
|
|
|
6
6
|
const { Item: DescriptionsItem } = Descriptions
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// 默认属性配置
|
|
9
|
+
const DESC_DEFAULT_ATTRS = {
|
|
9
10
|
size: 'middle',
|
|
10
11
|
bordered: true
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
// 属性定义
|
|
13
15
|
const DescriptionsProps = {
|
|
14
16
|
title: PropTypes.string,
|
|
15
17
|
column: PropTypes.oneOfType([PropTypes.number, PropTypes.object]).def(4),
|
|
18
|
+
labelWidth: PropTypes.number.def(160),
|
|
16
19
|
descDetails: PropTypes.object,
|
|
17
20
|
descSettings: PropTypes.array,
|
|
18
21
|
descAttrs: PropTypes.object,
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
// 渲染内容组件
|
|
21
25
|
const renderContent = (h, item, details) => {
|
|
22
26
|
const CustomTag = item.type === 'file' ? Browse : 'span'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
|
|
28
|
+
// 统一处理内容值获取逻辑
|
|
29
|
+
const getContentValue = () => {
|
|
30
|
+
return item.customRender
|
|
31
|
+
? item.customRender(details[item.props], details)
|
|
32
|
+
: details[item.props]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const contentValue = getContentValue()
|
|
36
|
+
|
|
37
|
+
// 处理文件类型的数据
|
|
38
|
+
const processData = () => {
|
|
39
|
+
if (item.type !== 'file') return contentValue
|
|
40
|
+
|
|
41
|
+
if (item.customRender) return contentValue
|
|
42
|
+
|
|
43
|
+
if (item.hasOwnProperty('multiProps')) {
|
|
44
|
+
return item.multiProps
|
|
45
|
+
.map(propsItem => transferData(details[propsItem], 'Array'))
|
|
46
|
+
.flat()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return contentValue
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const data = processData()
|
|
26
53
|
|
|
27
54
|
const props = {
|
|
28
55
|
data,
|
|
@@ -30,16 +57,22 @@ const renderContent = (h, item, details) => {
|
|
|
30
57
|
astrictH: 78
|
|
31
58
|
}
|
|
32
59
|
|
|
33
|
-
const contentValue = item.customRender ?
|
|
34
|
-
item.customRender(details[item.props], details) :
|
|
35
|
-
details[item.props]
|
|
36
|
-
|
|
37
60
|
return (
|
|
38
61
|
<CustomTag {...{ props }}>
|
|
39
62
|
{contentValue ?? '暂无'}
|
|
40
63
|
</CustomTag>
|
|
41
64
|
)
|
|
42
65
|
}
|
|
66
|
+
// ... existing code ...
|
|
67
|
+
|
|
68
|
+
// 响应式列数配置
|
|
69
|
+
const COLUMN_CONFIG = [
|
|
70
|
+
{ minWidth: 1600, getColumn: (column) => column || 4 },
|
|
71
|
+
{ minWidth: 1200, getColumn: (column) => Math.min(4, column) },
|
|
72
|
+
{ minWidth: 992, getColumn: (column) => Math.min(3, column) },
|
|
73
|
+
{ minWidth: 576, getColumn: (column) => Math.min(2, column) },
|
|
74
|
+
{ minWidth: 0, getColumn: () => 1 }
|
|
75
|
+
]
|
|
43
76
|
|
|
44
77
|
const DescriptionsList = {
|
|
45
78
|
name: 'DescriptionsList',
|
|
@@ -47,30 +80,38 @@ const DescriptionsList = {
|
|
|
47
80
|
data() {
|
|
48
81
|
return {
|
|
49
82
|
responsiveColumn: 1,
|
|
50
|
-
// 添加新属性:父级剩余高度
|
|
51
83
|
parentRemainingHeight: 'auto'
|
|
52
84
|
}
|
|
53
85
|
},
|
|
86
|
+
|
|
54
87
|
mounted() {
|
|
55
|
-
this.
|
|
56
|
-
this.$bus.$onWindow(this, 'resize', this.setDescContentWidth)
|
|
57
|
-
// 初始化父级剩余高度
|
|
58
|
-
// this.setParentRemainingHeight()
|
|
88
|
+
this.initComponent()
|
|
59
89
|
},
|
|
90
|
+
|
|
91
|
+
beforeDestroy() {
|
|
92
|
+
this.$bus.$offWindow(this, 'resize', this.setDescContentWidth)
|
|
93
|
+
},
|
|
94
|
+
|
|
60
95
|
methods: {
|
|
96
|
+
// 初始化组件
|
|
97
|
+
initComponent() {
|
|
98
|
+
this.setDescContentWidth()
|
|
99
|
+
this.$bus.$onWindow(this, 'resize', this.setDescContentWidth)
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
// 获取响应式列数
|
|
61
103
|
getCurrentColumn(width) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (width >= 992) return Math.min(3, this.column)
|
|
65
|
-
if (width >= 576) return Math.min(2, this.column)
|
|
66
|
-
return 1
|
|
104
|
+
const config = COLUMN_CONFIG.find(item => width >= item.minWidth)
|
|
105
|
+
return config ? config.getColumn(this.column) : 1
|
|
67
106
|
},
|
|
68
107
|
|
|
108
|
+
// 计算项目宽度
|
|
69
109
|
calculateItemWidth(totalWidth, itemSpan) {
|
|
70
110
|
const effectiveSpan = itemSpan && this.responsiveColumn > itemSpan ? itemSpan : 1
|
|
71
111
|
return totalWidth * (effectiveSpan / this.responsiveColumn)
|
|
72
112
|
},
|
|
73
113
|
|
|
114
|
+
// 设置描述内容宽度
|
|
74
115
|
setDescContentWidth() {
|
|
75
116
|
const retry = () => {
|
|
76
117
|
const container = this.$refs.Descriptions
|
|
@@ -86,74 +127,76 @@ const DescriptionsList = {
|
|
|
86
127
|
}
|
|
87
128
|
|
|
88
129
|
this.responsiveColumn = this.getCurrentColumn(width)
|
|
89
|
-
|
|
90
|
-
setTimeout(() => {
|
|
91
|
-
const rowElements = container.querySelectorAll('.ant-descriptions-row')
|
|
92
|
-
// 记录数量
|
|
93
|
-
let count = 0
|
|
94
|
-
|
|
95
|
-
for (let i = 0; i < rowElements.length; i++) {
|
|
96
|
-
const labelElements = rowElements[i].querySelectorAll('.ant-descriptions-item-label')
|
|
97
|
-
const contentElements = rowElements[i].querySelectorAll('.ant-descriptions-item-content')
|
|
98
|
-
|
|
99
|
-
for (let j = 0; j < labelElements.length; j++) {
|
|
100
|
-
const itemSpan = this.descSettings[count]?.span || 1
|
|
101
|
-
const eachWidth = width / this.responsiveColumn * itemSpan
|
|
102
|
-
|
|
103
|
-
// 设置标签固定宽度
|
|
104
|
-
labelElements[j].style = `
|
|
105
|
-
width: 160px;
|
|
106
|
-
min-width: 160px;
|
|
107
|
-
max-width: 160px;
|
|
108
|
-
`
|
|
109
|
-
|
|
110
|
-
// 设置内容区域默认宽度
|
|
111
|
-
contentElements[j].style = `
|
|
112
|
-
width: ${eachWidth - 160}px;
|
|
113
|
-
min-width: ${eachWidth - 160}px;
|
|
114
|
-
max-width: ${eachWidth - 160}px;
|
|
115
|
-
`
|
|
116
|
-
|
|
117
|
-
count++
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}, 0)
|
|
121
|
-
|
|
130
|
+
this.updateItemStyles(container, width)
|
|
122
131
|
}
|
|
132
|
+
|
|
123
133
|
retry()
|
|
124
134
|
},
|
|
125
|
-
|
|
135
|
+
|
|
136
|
+
// 更新项目样式
|
|
137
|
+
updateItemStyles(container, totalWidth) {
|
|
138
|
+
this.$nextTick(() => {
|
|
139
|
+
const rowElements = container.querySelectorAll('.ant-descriptions-row')
|
|
140
|
+
let itemCount = 0
|
|
141
|
+
|
|
142
|
+
rowElements.forEach(rowElement => {
|
|
143
|
+
const labelElements = rowElement.querySelectorAll('.ant-descriptions-item-label')
|
|
144
|
+
const contentElements = rowElement.querySelectorAll('.ant-descriptions-item-content')
|
|
145
|
+
|
|
146
|
+
labelElements.forEach((labelEl, index) => {
|
|
147
|
+
const itemConfig = this.descSettings[itemCount]
|
|
148
|
+
const itemSpan = itemConfig?.span || 1
|
|
149
|
+
const eachWidth = totalWidth / this.responsiveColumn * itemSpan
|
|
150
|
+
|
|
151
|
+
// 设置标签样式
|
|
152
|
+
this.setStyle(labelEl, {
|
|
153
|
+
width: `${this.labelWidth}px`,
|
|
154
|
+
minWidth: `${this.labelWidth}px`,
|
|
155
|
+
maxWidth: `${this.labelWidth}px`
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// 设置内容样式
|
|
159
|
+
this.setStyle(contentElements[index], {
|
|
160
|
+
width: `${eachWidth - this.labelWidth}px`,
|
|
161
|
+
minWidth: `${eachWidth - this.labelWidth}px`,
|
|
162
|
+
maxWidth: `${eachWidth - this.labelWidth}px`
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
itemCount++
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// 设置元素样式工具方法
|
|
172
|
+
setStyle(element, styles) {
|
|
173
|
+
if (element) {
|
|
174
|
+
Object.assign(element.style, styles)
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
126
178
|
// 设置父级剩余高度
|
|
127
179
|
setParentRemainingHeight() {
|
|
128
180
|
const parent = this.$el.parentElement
|
|
129
181
|
if (parent) {
|
|
130
|
-
// 获取父级高度
|
|
131
182
|
const parentHeight = parent.offsetHeight
|
|
132
|
-
// 获取当前组件在父级中的位置
|
|
133
183
|
const rect = this.$el.getBoundingClientRect()
|
|
134
184
|
const parentRect = parent.getBoundingClientRect()
|
|
135
|
-
|
|
136
|
-
// 计算父级剩余高度(从当前组件顶部到父级底部)
|
|
137
185
|
const remainingHeight = parentHeight - (rect.top - parentRect.top)
|
|
138
|
-
|
|
139
|
-
// 设置高度
|
|
140
186
|
this.parentRemainingHeight = `${remainingHeight}px`
|
|
141
187
|
}
|
|
142
188
|
}
|
|
143
189
|
},
|
|
190
|
+
|
|
144
191
|
render(h) {
|
|
145
192
|
const { title, descAttrs, descDetails, descSettings, $slots, $scopedSlots } = this
|
|
146
193
|
|
|
147
194
|
return (
|
|
148
|
-
// style={{
|
|
149
|
-
// // 动态设置高度
|
|
150
|
-
// height: this.parentRemainingHeight
|
|
151
|
-
// }}
|
|
152
195
|
<div class="Descriptions" ref="Descriptions">
|
|
153
196
|
<Descriptions
|
|
154
197
|
title={title}
|
|
155
198
|
column={this.responsiveColumn}
|
|
156
|
-
{...{ attrs: { ...
|
|
199
|
+
{...{ attrs: { ...DESC_DEFAULT_ATTRS, ...descAttrs } }}
|
|
157
200
|
>
|
|
158
201
|
{descSettings.map((descItem, key) => (
|
|
159
202
|
<DescriptionsItem
|
|
@@ -163,9 +206,9 @@ const DescriptionsList = {
|
|
|
163
206
|
<span slot="label">
|
|
164
207
|
{$slots[`${descItem.props}Label`] ?? descItem.label}
|
|
165
208
|
</span>
|
|
166
|
-
{$scopedSlots[descItem.props]
|
|
167
|
-
$scopedSlots[descItem.props](descDetails)
|
|
168
|
-
renderContent(h, descItem, descDetails)
|
|
209
|
+
{$scopedSlots[descItem.props]
|
|
210
|
+
? $scopedSlots[descItem.props](descDetails)
|
|
211
|
+
: renderContent(h, descItem, descDetails)
|
|
169
212
|
}
|
|
170
213
|
</DescriptionsItem>
|
|
171
214
|
))}
|
|
@@ -497,11 +497,9 @@ export default {
|
|
|
497
497
|
})
|
|
498
498
|
|
|
499
499
|
let newInnerOptions = []
|
|
500
|
-
|
|
501
|
-
newInnerOptions = [...records]
|
|
502
|
-
|
|
503
|
-
newInnerOptions = [...this.innerOptions, ...this.handleFilter(records)]
|
|
504
|
-
}
|
|
500
|
+
this.pagination.current === 1 && isReset
|
|
501
|
+
? newInnerOptions = [...records]
|
|
502
|
+
: newInnerOptions = [...this.innerOptions, ...this.handleFilter(records)]
|
|
505
503
|
|
|
506
504
|
// 对合并后的数据进行去重
|
|
507
505
|
this.innerOptions = this.deduplicateOptions(newInnerOptions)
|
|
@@ -1,18 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
// 添加flex属性解决css中div莫名高度
|
|
3
1
|
.ASelectCustom {
|
|
4
|
-
|
|
2
|
+
align-items: center;
|
|
3
|
+
.flex-layout();
|
|
5
4
|
|
|
6
5
|
.loading-more {
|
|
7
6
|
font-size: @font-size-base;
|
|
8
7
|
text-align: center;
|
|
9
8
|
padding: @padding-xs 0;
|
|
10
9
|
box-sizing: border-box;
|
|
11
|
-
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.ant-select {
|
|
13
|
+
&-selection {
|
|
14
|
+
.layout(100%, @input-height-base);
|
|
15
|
+
|
|
16
|
+
&--multiple {
|
|
17
|
+
padding-bottom: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&__rendered {
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
white-space: nowrap;
|
|
23
|
+
text-overflow: ellipsis;
|
|
24
|
+
// 2px为上下边框兼容
|
|
25
|
+
height: @input-height-base - 2px;
|
|
26
|
+
|
|
27
|
+
ul {
|
|
28
|
+
width: auto;
|
|
29
|
+
display: flex;
|
|
30
|
+
|
|
31
|
+
li { min-width: 70px; }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
12
35
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
36
|
+
&-dropdown-menu {
|
|
37
|
+
max-height: 300px;
|
|
38
|
+
overflow-y: auto;
|
|
39
|
+
.scrollbarStyle();
|
|
40
|
+
}
|
|
17
41
|
}
|
|
18
42
|
}
|
package/lib/model/Model.js
CHANGED
|
@@ -9,13 +9,6 @@
|
|
|
9
9
|
width: 100%;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// 统一设置表单控件宽度
|
|
13
|
-
.ant-select,
|
|
14
|
-
.ant-input-number,
|
|
15
|
-
.ant-calendar-picker {
|
|
16
|
-
width: 100%;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
12
|
.ant-radio-group {
|
|
20
13
|
line-height: @input-height-lg;
|
|
21
14
|
}
|
|
@@ -23,6 +16,10 @@
|
|
|
23
16
|
.ant-form-item-children {
|
|
24
17
|
display: flex;
|
|
25
18
|
align-items: center;
|
|
19
|
+
|
|
20
|
+
& > * {
|
|
21
|
+
width: 100%;
|
|
22
|
+
}
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
.FormLine {
|
|
@@ -13,9 +13,9 @@ const FormModelItem = FormModel.Item
|
|
|
13
13
|
export function getFormWidth(child, layoutSize, gap = 24) {
|
|
14
14
|
const width = (100 / layoutSize) * (child.size ?? 1)
|
|
15
15
|
if (this.layout === 'vertical') {
|
|
16
|
-
return `
|
|
16
|
+
return `width: calc(${width}% - ${gap}px); margin-right: ${gap}px;`
|
|
17
17
|
}
|
|
18
|
-
return `
|
|
18
|
+
return `width: ${width}%;`
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
package/lib/search/index.vue
CHANGED
|
@@ -132,7 +132,7 @@ export default {
|
|
|
132
132
|
middle: '16px',
|
|
133
133
|
default: '24px'
|
|
134
134
|
}
|
|
135
|
-
return `
|
|
135
|
+
return `width: calc((${(100 / this.matchMediaSize) * (e.size ?? 1)}% - ${
|
|
136
136
|
gap[this.searchStyle]
|
|
137
137
|
})); margin-right: ${gap[this.searchStyle]};`
|
|
138
138
|
},
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
@import '../../form-comp/style/index.less';
|
|
2
2
|
|
|
3
3
|
.WebComponentFormSearch {
|
|
4
|
-
|
|
5
|
-
.flex-mixins(@justify: flex-start);
|
|
6
|
-
|
|
7
|
-
.ant-form-item {
|
|
8
|
-
display: inline-flex;
|
|
9
|
-
margin-right: unset;
|
|
10
|
-
|
|
11
|
-
.ant-form-item-label {
|
|
12
|
-
min-width: 70px;
|
|
13
|
-
max-width: 100px;
|
|
14
|
-
text-align: right;
|
|
15
|
-
}
|
|
4
|
+
.flex-mixins(@justify: flex-start, @gap: 16px 0);
|
|
16
5
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
6
|
+
.ant-form-item {
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
margin-right: 0;
|
|
9
|
+
|
|
10
|
+
.ant-form-item-label {
|
|
11
|
+
min-width: 70px;
|
|
12
|
+
max-width: 100px;
|
|
13
|
+
text-align: right;
|
|
26
14
|
}
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
|
|
16
|
+
.ant-form-item-control-wrapper {
|
|
29
17
|
flex: 1;
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
min-width: 0;
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
32
21
|
}
|
|
22
|
+
|
|
23
|
+
&-control,
|
|
24
|
+
&-children > * {
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&__Actions {
|
|
30
|
+
flex: 1;
|
|
31
|
+
text-align: right;
|
|
32
|
+
}
|
|
33
33
|
}
|
package/package.json
CHANGED
package/utils/Filter.js
CHANGED
package/utils/Utils.js
CHANGED
|
@@ -17,35 +17,65 @@ export function chunkArray(arr, size) {
|
|
|
17
17
|
return result
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
|
|
20
21
|
/**
|
|
21
22
|
* 下载文件
|
|
22
|
-
* @param {Blob} response -
|
|
23
|
+
* @param {Blob|Object} response - 文档流或包含data和headers的对象
|
|
23
24
|
* @param {string} name - 文件名称
|
|
24
25
|
* @param {string} type - 文件类型
|
|
25
26
|
* @returns {void}
|
|
26
27
|
*/
|
|
27
|
-
export function downLoadFn(
|
|
28
|
-
|
|
28
|
+
export function downLoadFn(response, name, type = "application/vnd.ms-excel") {
|
|
29
|
+
// 兼容新写法:从response对象中解析data和headers
|
|
30
|
+
let fileData = response
|
|
31
|
+
let fileName = name
|
|
32
|
+
let fileType = type
|
|
33
|
+
|
|
34
|
+
// 如果response是对象且包含data属性,则使用新写法
|
|
35
|
+
if (response && typeof response === 'object' && response.data) {
|
|
36
|
+
fileData = response.data
|
|
37
|
+
|
|
38
|
+
// 从headers中解析文件名和类型
|
|
39
|
+
if (response.headers) {
|
|
40
|
+
const headers = response.headers
|
|
41
|
+
|
|
42
|
+
// 解析文件类型
|
|
43
|
+
if (headers['content-type']) {
|
|
44
|
+
fileType = headers['content-type']
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 解析文件名
|
|
48
|
+
if (headers['content-disposition']) {
|
|
49
|
+
const contentDisposition = headers['content-disposition']
|
|
50
|
+
const match = contentDisposition.match(/filename=([^;]+)/)
|
|
51
|
+
if (match && match[1]) {
|
|
52
|
+
fileName = decodeURIComponent(match[1].replace(/['"]/g, ''))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
29
58
|
let reader = new FileReader()
|
|
30
59
|
|
|
31
|
-
reader.readAsText(
|
|
60
|
+
reader.readAsText(fileData, "utf-8")
|
|
32
61
|
|
|
33
62
|
reader.onload = function () {
|
|
34
63
|
try {
|
|
35
|
-
message.error(
|
|
64
|
+
message.error(JSON.parse(reader.result).msg)
|
|
36
65
|
} catch (err) {
|
|
37
|
-
message.success(
|
|
38
|
-
let blob = new Blob(
|
|
39
|
-
let url = window.URL.createObjectURL(
|
|
40
|
-
const link = document.createElement(
|
|
66
|
+
message.success("下载中...")
|
|
67
|
+
let blob = new Blob([fileData], { type: fileType })
|
|
68
|
+
let url = window.URL.createObjectURL(blob)
|
|
69
|
+
const link = document.createElement("a")
|
|
41
70
|
link.href = url
|
|
42
|
-
link.download =
|
|
71
|
+
link.download = fileName
|
|
43
72
|
link.click()
|
|
44
|
-
window.URL.revokeObjectURL(
|
|
73
|
+
window.URL.revokeObjectURL(url)
|
|
45
74
|
}
|
|
46
75
|
}
|
|
47
76
|
}
|
|
48
77
|
|
|
78
|
+
|
|
49
79
|
/**
|
|
50
80
|
* 获取图片宽高 (如超出限制高度,则根据高度比计算出对应的宽度比)
|
|
51
81
|
* @param {string} url - 图片地址
|