web-component-gallery 2.3.6 → 2.3.8
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/index.umd.js +1 -1
- package/dist/js.umd.js +1 -1
- package/lib/browse/index.jsx +75 -132
- package/lib/browse/style/index.less +9 -0
- package/lib/form-comp/ASelectCustom.vue +5 -5
- package/lib/form-comp/AUpload.vue +146 -85
- package/lib/form-comp/style/ARangePicker.less +2 -2
- package/lib/form-comp/style/ASelectCustom.less +32 -8
- package/lib/form-comp/style/AUpload.less +14 -11
- 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/Axios.js +1 -1
- package/utils/File.js +146 -0
- package/utils/Filter.js +590 -133
- package/utils/Tree.js +13 -12
- package/utils/Utils.js +41 -11
package/lib/browse/index.jsx
CHANGED
|
@@ -1,162 +1,105 @@
|
|
|
1
1
|
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
|
2
|
-
|
|
3
|
-
import { transferData } from '../../utils/Filter'
|
|
2
|
+
// 引入自定义图标组件
|
|
4
3
|
import { IconFont } from '../index'
|
|
4
|
+
// 引入文件处理工具函数:格式化数据、获取文件类型、预览文件
|
|
5
|
+
import { formatFileData, getFileType, previewFile } from '../../utils/File'
|
|
5
6
|
|
|
6
7
|
const BrowseProps = {
|
|
8
|
+
// 数据源,支持字符串、数组或对象,默认为空数组
|
|
7
9
|
data: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]).def([]),
|
|
8
|
-
|
|
10
|
+
// 是否以缩略图模式展示
|
|
9
11
|
isThumb: PropTypes.bool,
|
|
10
|
-
|
|
12
|
+
// HTTPS 相关的配置对象,默认为空对象
|
|
11
13
|
httpsUrl: PropTypes.object.def({}),
|
|
12
|
-
|
|
14
|
+
// 限制高度,支持字符串或数字类型
|
|
13
15
|
astrictH: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// 定义默认图标类型
|
|
19
|
+
const ICON_TYPE = 'file_thumb'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 根据 URL 和内容类型获取预览所需的标签类型
|
|
23
|
+
* @param {string} url - 文件 URL
|
|
24
|
+
* @param {string} contentType - 内容类型
|
|
25
|
+
* @returns {string} 返回 'img', 'audio', 'video' 或 'iframe'
|
|
26
|
+
*/
|
|
27
|
+
const getPreviewType = (url, contentType = '') => {
|
|
28
|
+
const type = getFileType(url, contentType)
|
|
29
|
+
switch (type) {
|
|
30
|
+
case 'PICTURE': return 'img'
|
|
31
|
+
case 'AUDIO': return 'audio'
|
|
32
|
+
case 'VIDEO': return 'video'
|
|
33
|
+
default: return 'iframe'
|
|
34
|
+
}
|
|
14
35
|
}
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
/**
|
|
38
|
+
* 渲染单个文件内容的函数
|
|
39
|
+
* @param {function} h - Vue 的渲染函数
|
|
40
|
+
* @param {object} param1 - 包含 url 和 name 的对象
|
|
41
|
+
* @param {array} images - 图片列表,用于预览
|
|
42
|
+
* @returns {VNode} 返回渲染的虚拟 DOM 节点
|
|
43
|
+
*/
|
|
44
|
+
const renderContent = function (h, { url, name }, images) {
|
|
45
|
+
if (!url) return
|
|
46
|
+
|
|
47
|
+
const { isThumb, astrictH } = this
|
|
48
|
+
const tag = getPreviewType(url)
|
|
49
|
+
const isImage = tag === 'img'
|
|
50
|
+
const isMedia = ['audio', 'video'].includes(tag)
|
|
51
|
+
|
|
52
|
+
// 点击处理函数:如果是图片或缩略图模式,则触发预览
|
|
53
|
+
const handleClick = () => {
|
|
54
|
+
if (isImage || isThumb) previewFile(url, images, this)
|
|
32
55
|
}
|
|
33
56
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// URL前缀配置检查
|
|
43
|
-
if (!FILEURL || !KKFILEURL || !OVERVIEWFILEURL) {
|
|
44
|
-
console.warn('缺少必要的URL配置')
|
|
45
|
-
return dataArray
|
|
57
|
+
// 如果是非图片且处于缩略图模式,渲染带图标的占位符
|
|
58
|
+
if (!isImage && isThumb) {
|
|
59
|
+
return (
|
|
60
|
+
<div class="Browse__FileThumb" onClick={handleClick}>
|
|
61
|
+
<IconFont type={ICON_TYPE} />
|
|
62
|
+
<span>{name}</span>
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
46
65
|
}
|
|
47
66
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// 不同类型不同容器承载
|
|
72
|
-
const getCustomTag = (url) => {
|
|
73
|
-
// base64 图片处理
|
|
74
|
-
if (url.startsWith('data:image')) return 'img'
|
|
75
|
-
|
|
76
|
-
// 文件扩展名处理
|
|
77
|
-
const ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
|
|
78
|
-
return FILE_TYPES.PICTURE.includes(ext) ? 'img' :
|
|
79
|
-
FILE_TYPES.AUDIO.includes(ext) ? 'audio' :
|
|
80
|
-
FILE_TYPES.VIDEO.includes(ext) ? 'video' : 'iframe'
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function renderContent(h, {url, name}, images) {
|
|
84
|
-
if (!url) return
|
|
85
|
-
|
|
86
|
-
const { isThumb, astrictH, $viewerApi, $postM } = this
|
|
87
|
-
|
|
88
|
-
const MEDIA_TYPES = {
|
|
89
|
-
IFRAME: 'iframe',
|
|
90
|
-
IMAGE: 'img'
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const ICON_TYPE = "file_thumb"
|
|
94
|
-
|
|
95
|
-
const CustomTag = getCustomTag(url)
|
|
96
|
-
|
|
97
|
-
const attrs = {
|
|
98
|
-
src: url,
|
|
99
|
-
...(astrictH && { style: `width: auto; height: ${astrictH}px; objectFit: contain;` })
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const handleClick = () => {
|
|
103
|
-
if (CustomTag !== MEDIA_TYPES.IMAGE && !isThumb) return
|
|
104
|
-
|
|
105
|
-
if (CustomTag === MEDIA_TYPES.IFRAME && isThumb) {
|
|
106
|
-
$postM({
|
|
107
|
-
type: 'customModal',
|
|
108
|
-
name: 'browse',
|
|
109
|
-
params: { data: { url } }
|
|
110
|
-
})
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
$viewerApi({
|
|
116
|
-
options: {
|
|
117
|
-
url: 'url',
|
|
118
|
-
toolbar: true,
|
|
119
|
-
initialViewIndex: images.findIndex(file => file.url == url)
|
|
120
|
-
},
|
|
121
|
-
images
|
|
122
|
-
})
|
|
123
|
-
} catch(error){ console.error('未安装v-viewer@1.6.4组件库') }
|
|
124
|
-
}
|
|
67
|
+
// 构建基础标签属性
|
|
68
|
+
const attrs = {
|
|
69
|
+
src: url,
|
|
70
|
+
// 音视频和 iframe 显示控制条
|
|
71
|
+
...((isMedia || tag === 'iframe') && { controls: true }),
|
|
72
|
+
// 音视频自动播放配置
|
|
73
|
+
...(isMedia && { autoplay: true, muted: true, playsinline: true })
|
|
74
|
+
}
|
|
125
75
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
<span>{name}</span>
|
|
131
|
-
</div>
|
|
132
|
-
}
|
|
133
|
-
attrs['controls'] = true
|
|
134
|
-
}
|
|
76
|
+
// 构建基础标签样式
|
|
77
|
+
const style = {
|
|
78
|
+
...(astrictH && { width: 'auto', height: `${astrictH}px` })
|
|
79
|
+
}
|
|
135
80
|
|
|
136
|
-
|
|
81
|
+
// 渲染实际的媒体标签
|
|
82
|
+
return <tag {...{ attrs, style }} onClick={handleClick} />
|
|
137
83
|
}
|
|
138
84
|
|
|
85
|
+
// 定义 Browse 组件
|
|
139
86
|
const Browse = {
|
|
140
87
|
name: 'Browse',
|
|
141
88
|
props: BrowseProps,
|
|
142
|
-
render(h
|
|
143
|
-
const {data, $https, httpsUrl} = this
|
|
144
|
-
|
|
89
|
+
render(h) {
|
|
90
|
+
const { data, $https, httpsUrl } = this
|
|
91
|
+
// 格式化文件数据,合并 HTTPS 配置
|
|
92
|
+
const list = formatFileData(data, { ...$https, ...httpsUrl })
|
|
145
93
|
|
|
146
94
|
return (
|
|
147
95
|
<div class="Browse">
|
|
148
|
-
{
|
|
149
|
-
innerData.map( dataItem =>
|
|
150
|
-
renderContent.call(this, h, dataItem, innerData)
|
|
151
|
-
)
|
|
152
|
-
}
|
|
96
|
+
{list.map(item => renderContent.call(this, h, item, list))}
|
|
153
97
|
</div>
|
|
154
98
|
)
|
|
155
99
|
}
|
|
156
100
|
}
|
|
157
101
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
102
|
+
// 安装方法,用于注册全局组件
|
|
103
|
+
Browse.install = Vue => Vue.component('Browse', Browse)
|
|
161
104
|
|
|
162
|
-
export default Browse
|
|
105
|
+
export default Browse
|
|
@@ -178,6 +178,8 @@ export default {
|
|
|
178
178
|
return {
|
|
179
179
|
allowClear: true,
|
|
180
180
|
showSearch: true,
|
|
181
|
+
// 多选、标签模式下默认最多显示3个Tag
|
|
182
|
+
// maxTagCount: 3,
|
|
181
183
|
defaultActiveFirstOption: !this.isInput,
|
|
182
184
|
filterOption: this.shouldUseLocalFilter,
|
|
183
185
|
...this.$attrs
|
|
@@ -497,11 +499,9 @@ export default {
|
|
|
497
499
|
})
|
|
498
500
|
|
|
499
501
|
let newInnerOptions = []
|
|
500
|
-
|
|
501
|
-
newInnerOptions = [...records]
|
|
502
|
-
|
|
503
|
-
newInnerOptions = [...this.innerOptions, ...this.handleFilter(records)]
|
|
504
|
-
}
|
|
502
|
+
this.pagination.current === 1 && isReset
|
|
503
|
+
? newInnerOptions = [...records]
|
|
504
|
+
: newInnerOptions = [...this.innerOptions, ...this.handleFilter(records)]
|
|
505
505
|
|
|
506
506
|
// 对合并后的数据进行去重
|
|
507
507
|
this.innerOptions = this.deduplicateOptions(newInnerOptions)
|
|
@@ -1,113 +1,154 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
2
|
+
<div :class="['a-upload', `a-upload--${uploadConfig.listType}`]">
|
|
3
3
|
<Upload
|
|
4
4
|
name="file"
|
|
5
5
|
:file-list="fileList"
|
|
6
|
-
|
|
7
|
-
v-bind="uploadAttrs"
|
|
6
|
+
v-bind="uploadConfig"
|
|
8
7
|
@change="handleFileChange"
|
|
9
8
|
@preview="handleFilePreview"
|
|
10
|
-
@reject="
|
|
9
|
+
@reject="handleFileReject"
|
|
11
10
|
>
|
|
11
|
+
<!-- 文本按钮模式 -->
|
|
12
12
|
<Button
|
|
13
13
|
type="primary"
|
|
14
|
-
v-if="
|
|
14
|
+
v-if="isTextType"
|
|
15
|
+
:disabled="!canUpload"
|
|
15
16
|
>
|
|
16
17
|
<Icon type="upload" />上传
|
|
17
18
|
</Button>
|
|
19
|
+
|
|
20
|
+
<!-- 卡片模式 -->
|
|
18
21
|
<template v-else>
|
|
19
|
-
<Icon
|
|
22
|
+
<Icon
|
|
23
|
+
v-if="canUpload"
|
|
20
24
|
type="plus"
|
|
21
25
|
style="font-size: 36px"
|
|
22
26
|
/>
|
|
23
27
|
</template>
|
|
24
28
|
</Upload>
|
|
25
29
|
|
|
26
|
-
<
|
|
30
|
+
<div class="a-upload__tips" v-if="tips">{{ tips }}</div>
|
|
27
31
|
</div>
|
|
28
32
|
</template>
|
|
29
33
|
|
|
30
34
|
<script>
|
|
31
|
-
import { Icon, Button, Upload, message } from 'ant-design-vue'
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
import { previewFile } from '../../utils/File'
|
|
37
|
+
import { transferData } from '../../utils/Filter'
|
|
38
|
+
import { Icon, Button, Upload } from 'ant-design-vue'
|
|
35
39
|
|
|
36
40
|
export default {
|
|
37
41
|
name: 'AUpload',
|
|
42
|
+
|
|
38
43
|
model: {
|
|
39
44
|
prop: 'value',
|
|
40
45
|
event: 'handleFileUpload'
|
|
41
46
|
},
|
|
42
|
-
|
|
47
|
+
|
|
48
|
+
components: {
|
|
49
|
+
Icon,
|
|
50
|
+
Button,
|
|
51
|
+
Upload
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
inheritAttrs: false,
|
|
55
|
+
|
|
43
56
|
props: {
|
|
57
|
+
// 绑定值,支持字符串或数组格式
|
|
44
58
|
value: {
|
|
45
59
|
type: [String, Array],
|
|
46
60
|
default: () => []
|
|
47
61
|
},
|
|
48
|
-
|
|
62
|
+
// 提示文本信息
|
|
49
63
|
tips: String,
|
|
50
|
-
|
|
64
|
+
// 允许上传的最大文件数量
|
|
51
65
|
uploadLen: {
|
|
52
66
|
type: Number,
|
|
53
67
|
default: 1
|
|
54
68
|
},
|
|
55
|
-
|
|
69
|
+
// 自定义文件上传接口地址
|
|
56
70
|
fileUploadUrl: String,
|
|
57
|
-
|
|
71
|
+
// 文件访问地址的前缀 URL
|
|
58
72
|
filePrefixUrl: String,
|
|
59
|
-
|
|
60
|
-
fileAccept: String,
|
|
61
|
-
|
|
73
|
+
// 允许上传的文件类型限制(accept 属性)
|
|
74
|
+
fileAccept: String,
|
|
75
|
+
// 上传请求的额外头部信息
|
|
62
76
|
fileHeaders: Object,
|
|
63
|
-
|
|
77
|
+
// 自定义文件删除处理函数,若不传则使用默认 store action
|
|
64
78
|
fileRemoveHandle: Function
|
|
65
79
|
},
|
|
80
|
+
|
|
66
81
|
data() {
|
|
67
82
|
return {
|
|
68
83
|
fileList: [],
|
|
69
|
-
|
|
84
|
+
internalFileList: []
|
|
70
85
|
}
|
|
71
86
|
},
|
|
87
|
+
|
|
72
88
|
watch: {
|
|
73
|
-
value
|
|
74
|
-
|
|
89
|
+
value: {
|
|
90
|
+
handler: 'resetFileList',
|
|
91
|
+
immediate: true
|
|
75
92
|
}
|
|
76
93
|
},
|
|
94
|
+
|
|
77
95
|
computed: {
|
|
78
|
-
|
|
79
|
-
|
|
96
|
+
isTextType() {
|
|
97
|
+
return this.uploadConfig.listType === 'text'
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
canUpload() {
|
|
101
|
+
return this.fileList?.length < this.uploadLen && !this.uploadConfig.disabled
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
httpsUrl() {
|
|
105
|
+
const { $https, filePrefixUrl, fileUploadUrl } = this
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
...$https,
|
|
109
|
+
FILEURL: filePrefixUrl ?? $https?.FILEURL,
|
|
110
|
+
UPLOADURL: fileUploadUrl ?? $https?.UPLOADURL
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
uploadConfig() {
|
|
115
|
+
const { httpsUrl, fileAccept, fileHeaders, $store, $attrs } = this
|
|
116
|
+
|
|
80
117
|
return {
|
|
81
118
|
listType: 'picture-card',
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
119
|
+
accept: fileAccept,
|
|
120
|
+
prefix: httpsUrl.FILEURL,
|
|
121
|
+
action: httpsUrl.UPLOADURL,
|
|
122
|
+
headers: fileHeaders ?? $store?.getters?.fileHeaders,
|
|
123
|
+
...$attrs
|
|
86
124
|
}
|
|
87
125
|
}
|
|
88
126
|
},
|
|
89
|
-
|
|
90
|
-
this.setResetFile()
|
|
91
|
-
},
|
|
127
|
+
|
|
92
128
|
beforeDestroy() {
|
|
93
|
-
this.
|
|
94
|
-
this.modalValue = []
|
|
129
|
+
this.cleanup()
|
|
95
130
|
},
|
|
131
|
+
|
|
96
132
|
methods: {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
133
|
+
// 重置文件列表
|
|
134
|
+
resetFileList() {
|
|
135
|
+
const rawList = transferData(this.value, 'Array')
|
|
136
|
+
|
|
137
|
+
// 标准化内部数据:统一使用 id,移除 uid
|
|
138
|
+
this.internalFileList = rawList.map(file => {
|
|
139
|
+
const normalized = { ...file }
|
|
140
|
+
normalized.id = normalized.id || normalized.uid
|
|
141
|
+
if (normalized.uid) delete normalized.uid
|
|
142
|
+
|
|
143
|
+
return normalized
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// 构建展示列表:适配 Ant Design Upload 组件需要的 uid 格式
|
|
147
|
+
const { prefix } = this.uploadConfig
|
|
148
|
+
this.fileList = this.internalFileList.map(file => ({
|
|
109
149
|
...file,
|
|
110
|
-
|
|
150
|
+
uid: file.id,
|
|
151
|
+
url: `${prefix}${file.url}`,
|
|
111
152
|
type: file.contentType || file.type,
|
|
112
153
|
status: 'done'
|
|
113
154
|
}))
|
|
@@ -117,70 +158,90 @@ export default {
|
|
|
117
158
|
* 文件预览处理
|
|
118
159
|
* @param {Object} file - 文件对象
|
|
119
160
|
*/
|
|
120
|
-
handleFilePreview({uid
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const suffix = url.substr(url.lastIndexOf('.') + 1).toUpperCase()
|
|
124
|
-
|
|
125
|
-
if (type.includes('image') || IMAGE_SUFFIX.has(suffix)) {
|
|
126
|
-
this.$viewerApi({
|
|
127
|
-
options: {
|
|
128
|
-
url: 'url',
|
|
129
|
-
toolbar: true,
|
|
130
|
-
initialViewIndex: this.fileList.findIndex(file => file.url === url)
|
|
131
|
-
},
|
|
132
|
-
images: this.fileList
|
|
133
|
-
})
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// 仅适用于子项目调起
|
|
138
|
-
this.$postM({
|
|
139
|
-
type: 'customModal',
|
|
140
|
-
name: 'browse',
|
|
141
|
-
params: { data: this.modalValue.find(item => item.uid === uid) }
|
|
142
|
-
})
|
|
161
|
+
handleFilePreview({ uid }) {
|
|
162
|
+
const sourceFile = this.internalFileList.find(f => f.id === uid)
|
|
163
|
+
previewFile(sourceFile, this.internalFileList, this)
|
|
143
164
|
},
|
|
144
165
|
|
|
145
166
|
/**
|
|
146
167
|
* 文件状态变化处理
|
|
147
|
-
* @param {Object}
|
|
148
|
-
* @param {
|
|
168
|
+
* @param {Object} params - 参数对象
|
|
169
|
+
* @param {Object} params.file - 当前文件对象
|
|
170
|
+
* @param {Array} params.fileList - 文件列表
|
|
149
171
|
*/
|
|
150
172
|
handleFileChange({ file, fileList }) {
|
|
151
|
-
const {uid, status, response} = file
|
|
173
|
+
const { uid, status, response } = file
|
|
152
174
|
|
|
175
|
+
// 上传中
|
|
153
176
|
if (status === 'uploading') {
|
|
154
177
|
this.fileList = fileList
|
|
155
178
|
return
|
|
156
179
|
}
|
|
157
180
|
|
|
181
|
+
// 上传失败:后端返回非 200 状态码
|
|
158
182
|
if (response && response.code !== 200) {
|
|
159
|
-
this.fileList = this.fileList.filter(
|
|
160
|
-
this.$message.error(response.msg || '
|
|
183
|
+
this.fileList = this.fileList.filter(item => item.uid !== uid)
|
|
184
|
+
this.$message.error(response.msg || '文件上传失败')
|
|
161
185
|
return
|
|
162
186
|
}
|
|
163
187
|
|
|
188
|
+
// 根据状态处理
|
|
164
189
|
switch (status) {
|
|
165
190
|
case 'removed':
|
|
166
|
-
|
|
167
|
-
? this.fileRemoveHandle({ id: uid })
|
|
168
|
-
: this.$store.dispatch('fileRemoveHandle', { id: uid })
|
|
169
|
-
requestHandle.then(() => {
|
|
170
|
-
this.modalValue = this.modalValue.filter(e => e.uid !== uid)
|
|
171
|
-
this.$emit('handleFileUpload', JSON.stringify(this.modalValue))
|
|
172
|
-
})
|
|
191
|
+
this.handleFileRemove(uid)
|
|
173
192
|
break
|
|
174
193
|
case 'done':
|
|
175
|
-
|
|
176
|
-
this.modalValue.push({...innerData, uid: id})
|
|
177
|
-
this.$emit('handleFileUpload', JSON.stringify(this.modalValue))
|
|
194
|
+
this.handleFileDone(response)
|
|
178
195
|
break
|
|
179
196
|
case 'error':
|
|
180
197
|
this.$message.error('文件上传失败')
|
|
181
198
|
break
|
|
182
199
|
}
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 文件类型拒绝
|
|
204
|
+
*/
|
|
205
|
+
handleFileReject() {
|
|
206
|
+
this.$message.error(`上传文件类型只能为${this.fileAccept}`)
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 删除文件
|
|
211
|
+
* @param {String} id - 文件 ID
|
|
212
|
+
*/
|
|
213
|
+
handleFileRemove(id) {
|
|
214
|
+
const requestHandle = this.fileRemoveHandle
|
|
215
|
+
? this.fileRemoveHandle({ id })
|
|
216
|
+
: this.$store.dispatch('fileRemoveHandle', { id })
|
|
217
|
+
|
|
218
|
+
requestHandle.then(() => {
|
|
219
|
+
this.internalFileList = this.internalFileList.filter(e => e.id !== id)
|
|
220
|
+
this.$emit('handleFileUpload', JSON.stringify(this.internalFileList))
|
|
221
|
+
})
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 上传完成处理
|
|
226
|
+
* @param {Object} response - 上传响应对象
|
|
227
|
+
*/
|
|
228
|
+
handleFileDone(response) {
|
|
229
|
+
if (!response?.data) {
|
|
230
|
+
this.$message.error('文件上传失败!')
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.internalFileList.push(response.data)
|
|
235
|
+
this.$emit('handleFileUpload', JSON.stringify(this.internalFileList))
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 清理数据
|
|
240
|
+
*/
|
|
241
|
+
cleanup() {
|
|
242
|
+
this.fileList = []
|
|
243
|
+
this.internalFileList = []
|
|
183
244
|
}
|
|
184
245
|
}
|
|
185
246
|
}
|
|
186
|
-
</script>
|
|
247
|
+
</script>
|
|
@@ -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
|
}
|