n20-common-lib 3.0.31 → 3.0.32
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/assets/css/font-icon.scss +0 -1
- package/src/assets/css/table.scss +2 -0
- package/src/components/FileUploadTable/37.svg +29 -0
- package/src/components/FileUploadTable/46.svg +29 -0
- package/src/components/FileUploadTable/60.svg +29 -0
- package/src/components/FileUploadTable/FileUploadTableV3.vue +555 -652
- package/src/components/TablePro/index.vue +18 -6
|
@@ -1,225 +1,76 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="file-upload-table-v3">
|
|
3
|
-
|
|
4
|
-
<div>
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
</slot>
|
|
15
|
-
<slot v-if="!readonly && showBatchPrint" name="batch-btn">
|
|
16
|
-
<el-button size="mini" plain @click="batchPrint">{{ '批量打印' | $lc }}</el-button>
|
|
17
|
-
</slot>
|
|
18
|
-
<slot name="down-btn">
|
|
19
|
-
<el-button size="mini" plain @click="downRows">{{ '下载' | $lc }}</el-button>
|
|
20
|
-
</slot>
|
|
21
|
-
<slot v-if="!readonly" name="delete-btn">
|
|
22
|
-
<el-button type="danger" plain size="mini" @click="deleteRows">{{ '删除' | $lc }}</el-button>
|
|
23
|
-
</slot>
|
|
3
|
+
<div class="panel">
|
|
4
|
+
<div class="panel-top">
|
|
5
|
+
<div class="summary">
|
|
6
|
+
<i class="v3-icon-link"></i>
|
|
7
|
+
<span>{{ uploadedCount }} 个附件</span>
|
|
8
|
+
<el-button type="text" class="summary-action v3-icon-download" @click="downRows">全部下载</el-button>
|
|
9
|
+
</div>
|
|
10
|
+
<el-button type="text" class="toggle-btn" @click="toggleCollapse">
|
|
11
|
+
{{ showAllTypes ? '收起未传类型' : '展开全部' }}
|
|
12
|
+
<i :class="['el-icon-arrow-down', { 'is-reverse': showAllTypes }]"></i>
|
|
13
|
+
</el-button>
|
|
24
14
|
</div>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<template v-if="dataPorp.slotHeader">
|
|
37
|
-
<el-table-column
|
|
38
|
-
v-for="item in dataPorp.slotHeader"
|
|
39
|
-
:key="item.prop"
|
|
40
|
-
:label="item.label"
|
|
41
|
-
:prop="item.prop"
|
|
42
|
-
:align="item.align || 'center'"
|
|
43
|
-
:width="item.width || 'auto'"
|
|
44
|
-
:show-overflow-tooltip="item.showOverflowTooltip || item['show-overflow-tooltip']"
|
|
45
|
-
/>
|
|
46
|
-
</template>
|
|
47
|
-
<template v-else>
|
|
48
|
-
<el-table-column :label="'附件类型' | $lc" :prop="keys.type">
|
|
49
|
-
<slot slot="header" slot-scope="scope" name="type-header" :column="scope.column">{{ '附件类型' | $lc }}</slot>
|
|
50
|
-
<slot slot-scope="{ row }" name="type" :row="row">
|
|
51
|
-
<span v-if="readonly">{{ row[keys.type] | typeFiter(typeOptions) }}</span>
|
|
52
|
-
<div v-else class="flex-box flex-v">
|
|
53
|
-
<span v-if="requiredTypes.includes(row[keys.type])" style="color: red" class="m-r-s">*</span>
|
|
54
|
-
<el-select
|
|
55
|
-
v-model="row[keys.type]"
|
|
56
|
-
:disabled="row._typeDisabled"
|
|
57
|
-
:placeholder="'请选择' | $lc"
|
|
58
|
-
style="width: calc(100% - 16px)"
|
|
59
|
-
@change="$emit('typeChange', row[keys.type])"
|
|
60
|
-
>
|
|
61
|
-
<el-option
|
|
62
|
-
v-for="item in typeOptions"
|
|
63
|
-
:key="item.type"
|
|
64
|
-
:disabled="item.disabled"
|
|
65
|
-
:value="item.type"
|
|
66
|
-
:label="item.label"
|
|
67
|
-
/>
|
|
68
|
-
</el-select>
|
|
15
|
+
|
|
16
|
+
<div class="type-list">
|
|
17
|
+
<div v-for="(group, index) in displayTypeGroups" :key="group.typeValue || index" class="type-item">
|
|
18
|
+
<div class="type-row" :class="[{ 'type-row__is-success': getTypeStatus(group.typeValue) === 'success' }]">
|
|
19
|
+
<div class="type-meta">
|
|
20
|
+
<span v-if="isRequiredType(group.item)" class="required">*</span>
|
|
21
|
+
<span class="type-index">{{ index + 1 }}、</span>
|
|
22
|
+
<span class="type-name">{{ group.item[typeMap.label] }}</span>
|
|
23
|
+
<img v-if="getTypeStatus(group.typeValue) === 'success'" src="./ysc.svg" class="status-icon" />
|
|
24
|
+
<img v-else-if="getTypeStatus(group.typeValue) === 'warning'" src="./jytg.svg" class="status-icon" />
|
|
25
|
+
<img v-else src="./wsc.svg" class="status-icon" />
|
|
69
26
|
</div>
|
|
70
|
-
|
|
71
|
-
</el-table-column>
|
|
72
|
-
<el-table-column :label="'附件名称' | $lc" :prop="keys.name">
|
|
73
|
-
<slot slot="header" slot-scope="scope" name="name-header" :column="scope.column">{{ '附件名称' | $lc }}</slot>
|
|
74
|
-
<slot slot-scope="{ row }" name="name" :row="row">
|
|
75
|
-
<span v-if="readonly">{{ row[keys.name] ? row[keys.name].replace(/\.[A-z0-9]+$/, '') : '' }}</span>
|
|
76
|
-
<el-input
|
|
77
|
-
v-else
|
|
78
|
-
v-title
|
|
79
|
-
:value="row[keys.name] ? row[keys.name].replace(/\.[A-z0-9]+$/, '') : ''"
|
|
80
|
-
disabled
|
|
81
|
-
:placeholder="'请输入' | $lc"
|
|
82
|
-
/>
|
|
83
|
-
</slot>
|
|
84
|
-
</el-table-column>
|
|
85
|
-
<el-table-column v-if="readonly" :label="'附件上传' | $lc" :prop="keys.name">
|
|
86
|
-
<slot slot="header" slot-scope="scope" name="upload-header" :column="scope.column"
|
|
87
|
-
>{{ '附件上传' | $lc }}
|
|
88
|
-
</slot>
|
|
89
|
-
<slot slot-scope="{ row }" name="upload" :row="row">
|
|
90
|
-
{{ $options.filters.fileName(row, keys.url) || row[keys.name] }}
|
|
91
|
-
</slot>
|
|
92
|
-
</el-table-column>
|
|
93
|
-
<el-table-column v-if="!readonly" :label="'附件上传' | $lc">
|
|
94
|
-
<slot slot="header" slot-scope="scope" name="upload-header" :column="scope.column"
|
|
95
|
-
>{{ '附件上传' | $lc }}
|
|
96
|
-
</slot>
|
|
97
|
-
<slot slot-scope="{ row, $index }" name="upload" :row="row" :[indexK]="$index">
|
|
27
|
+
|
|
98
28
|
<Upload
|
|
99
|
-
:ref="'upload' +
|
|
29
|
+
:ref="'upload' + index"
|
|
100
30
|
class="n20-upload-table-up"
|
|
101
|
-
:file-name="
|
|
102
|
-
:data="row['_fileData'] || fileData"
|
|
31
|
+
:file-name="''"
|
|
103
32
|
:msg-type="null"
|
|
104
33
|
:show-clear="false"
|
|
105
34
|
:action="apiPrefix ? apiPrefix + action : action"
|
|
106
35
|
:multiple="multiple"
|
|
107
36
|
:headers="headers"
|
|
108
|
-
:disabled="
|
|
109
|
-
:
|
|
110
|
-
:
|
|
111
|
-
:
|
|
112
|
-
:
|
|
113
|
-
|
|
114
|
-
:on-success="
|
|
115
|
-
(response, file, fileList) =>
|
|
116
|
-
multiple
|
|
117
|
-
? MultipleSUccessFn(response, file, fileList, row)
|
|
118
|
-
: onSuccessFn(response, file, fileList, row)
|
|
37
|
+
:disabled="readonly || group.item.disabled"
|
|
38
|
+
:data="buildTypeUploadData(group.item)"
|
|
39
|
+
:accept="group.item.accept || fileAccept"
|
|
40
|
+
:size="group.item.size || fileSize"
|
|
41
|
+
:http-request="
|
|
42
|
+
uploadHttpRequest ? (options) => uploadHttpRequest(options, buildUploadRow(group.item)) : undefined
|
|
119
43
|
"
|
|
120
|
-
:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
:
|
|
145
|
-
text-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<el-button
|
|
149
|
-
v-if="row['_status'] === 'exception'"
|
|
150
|
-
type="text"
|
|
151
|
-
size="mini"
|
|
152
|
-
style="width: 60px"
|
|
153
|
-
@click="anewSubmitFn(row, $index)"
|
|
154
|
-
>{{ '重新上传' | $lc }}
|
|
155
|
-
</el-button>
|
|
156
|
-
<el-button
|
|
157
|
-
v-else-if="row['_percent'] >= 0 && row['_percent'] < 100"
|
|
158
|
-
type="text"
|
|
159
|
-
size="mini"
|
|
160
|
-
style="width: 60px"
|
|
161
|
-
@click="abortFn(row, $index)"
|
|
162
|
-
>{{ '取消' | $lc }}
|
|
163
|
-
</el-button>
|
|
44
|
+
:before-upload="(file) => beforeUploadFn(file, buildUploadRow(group.item))"
|
|
45
|
+
:on-progress="(event) => onProgressFn(event, group.typeValue)"
|
|
46
|
+
:on-success="(response, file, fileList) => onTypeUploadSuccess(response, file, fileList, group.item)"
|
|
47
|
+
:on-error="(err, file, fileList) => onTypeUploadError(err, file, fileList, group.item, index)"
|
|
48
|
+
>
|
|
49
|
+
<el-button slot="trigger" type="text" class="upload-trigger">去上传</el-button>
|
|
50
|
+
</Upload>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div v-if="group.rows.length" class="file-cards">
|
|
54
|
+
<div v-for="(row, rowIndex) in group.rows" :key="`${group.typeValue}-${rowIndex}`" class="file-card">
|
|
55
|
+
<div class="file-info">
|
|
56
|
+
<img v-if="matchFileExtension(row[keys.name], ['word', 'doc', 'docx'])" src="./46.svg" class="m-r-s" />
|
|
57
|
+
<img v-if="matchFileExtension(row[keys.name], ['xlsx', 'xls'])" src="./60.svg" class="m-r-s" />
|
|
58
|
+
<img v-if="matchFileExtension(row[keys.name], ['pdf'])" src="./37.svg" class="m-r-s" />
|
|
59
|
+
<div>
|
|
60
|
+
<div class="file-name" :title="row[keys.name]">{{ row[keys.name] }}</div>
|
|
61
|
+
<div class="file-meta">
|
|
62
|
+
<span class="m-r-m">{{ row[keys.user] || '-' }}</span>
|
|
63
|
+
<span>{{ row[keys.time] || '-' }}</span>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="file-actions">
|
|
68
|
+
<el-button type="text" icon="el-icon-view" :disabled="!row[keys.url]" @click="seeFile(row)" />
|
|
69
|
+
<el-button type="text" icon="v3-icon-download" :disabled="!row[keys.url]" @click="downFile(row)" />
|
|
70
|
+
<el-button v-if="!readonly" type="text" icon="v3-icon-delete" @click="deleteSingleRow(row)" />
|
|
71
|
+
</div>
|
|
164
72
|
</div>
|
|
165
|
-
</slot>
|
|
166
|
-
</template>
|
|
167
|
-
</el-table-column>
|
|
168
|
-
<el-table-column :label="'操作' | $lc" align="center" width="90" fixed="right">
|
|
169
|
-
<slot slot="header" slot-scope="scope" name="handle-header" :column="scope.column">{{ '操作' | $lc }}</slot>
|
|
170
|
-
<slot slot-scope="{ row }" name="handle" :row="row">
|
|
171
|
-
<el-button type="text" icon="el-icon-view" :disabled="!row[keys.url]" @click="seeFile(row)" />
|
|
172
|
-
<el-button
|
|
173
|
-
v-if="getOfficeStatus && openAI"
|
|
174
|
-
v-title="'ai识别'"
|
|
175
|
-
type="text"
|
|
176
|
-
icon="n20-icon-query"
|
|
177
|
-
:disabled="!row[keys.url]"
|
|
178
|
-
@click="AiFn(row)"
|
|
179
|
-
/>
|
|
180
|
-
<el-button
|
|
181
|
-
v-if="readonly"
|
|
182
|
-
type="text"
|
|
183
|
-
icon="el-icon-download"
|
|
184
|
-
:disabled="!row[keys.url]"
|
|
185
|
-
@click="downFile(row)"
|
|
186
|
-
/>
|
|
187
|
-
</slot>
|
|
188
|
-
</el-table-column>
|
|
189
|
-
</el-table> -->
|
|
190
|
-
<div class="flex-box flex-v flex-lr">
|
|
191
|
-
<div class="title">
|
|
192
|
-
附件上传
|
|
193
|
-
<span>(带 * 为必要上传的附件)</span>
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
<div class="file-list">
|
|
197
|
-
<div v-for="(item, index) in typeOptions" :key="index" class="file-item">
|
|
198
|
-
<div class="type-title">
|
|
199
|
-
<div class="flex-box flex-v">
|
|
200
|
-
<span class="m-r-s">*</span>
|
|
201
|
-
<span>{{ index + 1 }}、</span>
|
|
202
|
-
<span>{{ item.label }}</span>
|
|
203
|
-
<img src="./ysc.svg" width="14px" class="m-l-s" />
|
|
204
73
|
</div>
|
|
205
|
-
<Upload
|
|
206
|
-
:ref="'upload' + index"
|
|
207
|
-
class="n20-upload-table-up"
|
|
208
|
-
:msg-type="null"
|
|
209
|
-
:show-clear="false"
|
|
210
|
-
:action="apiPrefix ? apiPrefix + action : action"
|
|
211
|
-
:multiple="multiple"
|
|
212
|
-
:headers="headers"
|
|
213
|
-
:data="fileData"
|
|
214
|
-
:http-request="uploadHttpRequest ? (options) => uploadHttpRequest(options, row) : undefined"
|
|
215
|
-
:on-success="
|
|
216
|
-
(response, file, fileList) =>
|
|
217
|
-
multiple ? MultipleSUccessFn(response, file, fileList, row) : onSuccessFn(response, file, fileList, row)
|
|
218
|
-
"
|
|
219
|
-
:on-error="(err, file, fileList) => errorFn(err, file, fileList, row, $index)"
|
|
220
|
-
>
|
|
221
|
-
<el-button slot="trigger" type="text" size="small">去上传</el-button>
|
|
222
|
-
</Upload>
|
|
223
74
|
</div>
|
|
224
75
|
</div>
|
|
225
76
|
</div>
|
|
@@ -254,73 +105,20 @@
|
|
|
254
105
|
<i class="el-icon-s-release" style="font-size: 60px; color: #999"></i>
|
|
255
106
|
<span style="margin-top: 16px">
|
|
256
107
|
{{ '不支持在线预览,请' | $lc
|
|
257
|
-
}}<el-link type="primary" class="color-primary" @click="downFile(seeRow)">{{ '下载' | $lc }}</el-link
|
|
258
|
-
|
|
108
|
+
}}<el-link type="primary" class="color-primary" @click="downFile(seeRow)">{{ '下载' | $lc }}</el-link>
|
|
109
|
+
{{ '到本地查看' | $lc }}
|
|
259
110
|
</span>
|
|
260
111
|
</div>
|
|
261
112
|
</component>
|
|
262
113
|
</div>
|
|
263
114
|
</Dialog>
|
|
264
|
-
<Dialog
|
|
265
|
-
v-drag
|
|
266
|
-
:title="'附件批量上传' | $lc"
|
|
267
|
-
:visible.sync="visibleBatch"
|
|
268
|
-
top="5vh"
|
|
269
|
-
width="692px"
|
|
270
|
-
:close-on-click-modal="false"
|
|
271
|
-
:destroy-on-open="true"
|
|
272
|
-
>
|
|
273
|
-
<el-select v-model="bathType" class="m-b-s" clearable @change="handleBathChange">
|
|
274
|
-
<el-option
|
|
275
|
-
v-for="item in typeOptions"
|
|
276
|
-
:key="item.type"
|
|
277
|
-
:disabled="item.disabled"
|
|
278
|
-
:value="item.type"
|
|
279
|
-
:label="item.label"
|
|
280
|
-
/>
|
|
281
|
-
</el-select>
|
|
282
|
-
<Upload
|
|
283
|
-
v-if="bathType"
|
|
284
|
-
ref="upload-batch"
|
|
285
|
-
class="n20-upload-drag"
|
|
286
|
-
:msg-type="null"
|
|
287
|
-
:show-clear="false"
|
|
288
|
-
:drag="true"
|
|
289
|
-
:auto-upload="false"
|
|
290
|
-
:multiple="true"
|
|
291
|
-
:show-file-list="true"
|
|
292
|
-
:action="apiPrefix ? apiPrefix + action : action"
|
|
293
|
-
:data="fileData"
|
|
294
|
-
:headers="headers"
|
|
295
|
-
:accept="fileAccept"
|
|
296
|
-
:size="fileSize"
|
|
297
|
-
:http-request="uploadHttpRequestBath"
|
|
298
|
-
:before-upload="(file) => batchBeforeUploadFn(file)"
|
|
299
|
-
:on-remove="batchRemove"
|
|
300
|
-
:on-success="batchSuccess"
|
|
301
|
-
:on-error="batchError"
|
|
302
|
-
>
|
|
303
|
-
<template slot="trigger">
|
|
304
|
-
<i class="drag-icon n20-icon-shangchuan"></i>
|
|
305
|
-
<span class="drag-text">{{ '点击或将文件拖拽到这里上传' | $lc }}</span>
|
|
306
|
-
<span class="drag-tip">{{ fileAcceptTip }}</span>
|
|
307
|
-
</template>
|
|
308
|
-
</Upload>
|
|
309
|
-
<div class="dialog-footer">
|
|
310
|
-
<el-button type="primary" @click="batchUploadFn">{{ '确认' | $lc }}</el-button>
|
|
311
|
-
<el-button plain @click="visibleBatch = false">{{ '取消' | $lc }}</el-button>
|
|
312
|
-
</div>
|
|
313
|
-
</Dialog>
|
|
314
115
|
</div>
|
|
315
116
|
</template>
|
|
316
117
|
|
|
317
118
|
<script>
|
|
318
|
-
import getJsonc from '../../assets/getJsonc.js'
|
|
319
119
|
import _axios from 'axios'
|
|
320
120
|
import dayjs from 'dayjs'
|
|
321
121
|
import XEUtils from 'xe-utils'
|
|
322
|
-
|
|
323
|
-
import 'viewerjs/dist/viewer.css'
|
|
324
122
|
import auth from '../../utils/auth.js'
|
|
325
123
|
import axios from '../../utils/axios.js'
|
|
326
124
|
import { $lc } from '../../utils/i18n/index'
|
|
@@ -328,10 +126,13 @@ import importG from '../../utils/importGlobal.js'
|
|
|
328
126
|
import Dialog from '../Dialog/index.vue'
|
|
329
127
|
import Upload from '../Upload/index.vue'
|
|
330
128
|
|
|
129
|
+
import 'viewerjs/dist/viewer.css'
|
|
130
|
+
|
|
331
131
|
const ViewerImg = async function () {
|
|
332
132
|
let { component } = await importG('v-viewer', () => import(/*webpackChunkName: "v-viewer"*/ 'v-viewer'))
|
|
333
133
|
return component
|
|
334
134
|
}
|
|
135
|
+
|
|
335
136
|
const keysDefault = {
|
|
336
137
|
rowKey: 'id',
|
|
337
138
|
type: 'type',
|
|
@@ -340,11 +141,6 @@ const keysDefault = {
|
|
|
340
141
|
time: 'time',
|
|
341
142
|
user: 'user'
|
|
342
143
|
}
|
|
343
|
-
const typeOptionsDefault = [
|
|
344
|
-
{ type: '001', label: $lc('信贷合同') },
|
|
345
|
-
{ type: '002', label: $lc('贴现合同') },
|
|
346
|
-
{ type: '003', label: $lc('其他合同') }
|
|
347
|
-
]
|
|
348
144
|
|
|
349
145
|
export default {
|
|
350
146
|
name: 'FileUploadTableV3',
|
|
@@ -353,36 +149,7 @@ export default {
|
|
|
353
149
|
Dialog,
|
|
354
150
|
ViewerImg
|
|
355
151
|
},
|
|
356
|
-
filters: {
|
|
357
|
-
typeFiter(type, typeOptions) {
|
|
358
|
-
return typeOptions.find((c) => c.type === type)?.label || type
|
|
359
|
-
},
|
|
360
|
-
acceptFilter(type, typeOptions, fileAccept) {
|
|
361
|
-
return typeOptions.find((c) => c.type === type)?.accept || fileAccept
|
|
362
|
-
},
|
|
363
|
-
sizeFilter(type, typeOptions, fileSize) {
|
|
364
|
-
return typeOptions.find((c) => c.type === type)?.size || fileSize
|
|
365
|
-
},
|
|
366
|
-
fileName(row, urlK) {
|
|
367
|
-
if (row['_name']) {
|
|
368
|
-
return row['_name']
|
|
369
|
-
} else if (row[urlK]) {
|
|
370
|
-
let urlArr = row[urlK].split('/')
|
|
371
|
-
let _n = urlArr[urlArr.length - 1]
|
|
372
|
-
return _n ? decodeURI(_n) : undefined
|
|
373
|
-
}
|
|
374
|
-
return undefined
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
152
|
props: {
|
|
378
|
-
AIOptions: {
|
|
379
|
-
type: Object,
|
|
380
|
-
default: () => ({})
|
|
381
|
-
},
|
|
382
|
-
openAI: {
|
|
383
|
-
type: Boolean,
|
|
384
|
-
default: false
|
|
385
|
-
},
|
|
386
153
|
readonly: {
|
|
387
154
|
type: Boolean,
|
|
388
155
|
default: false
|
|
@@ -391,10 +158,6 @@ export default {
|
|
|
391
158
|
type: String,
|
|
392
159
|
default: '/bems/1.0/attach'
|
|
393
160
|
},
|
|
394
|
-
batchPrintMethod: {
|
|
395
|
-
type: Function,
|
|
396
|
-
default: undefined
|
|
397
|
-
},
|
|
398
161
|
headers: {
|
|
399
162
|
type: Object,
|
|
400
163
|
default: undefined
|
|
@@ -411,26 +174,14 @@ export default {
|
|
|
411
174
|
type: RegExp,
|
|
412
175
|
default: () => /\.(jpg|png|gif|svg|pdf)$/i
|
|
413
176
|
},
|
|
414
|
-
height: {
|
|
415
|
-
type: [String, Number],
|
|
416
|
-
default: '300px'
|
|
417
|
-
},
|
|
418
177
|
tableData: {
|
|
419
178
|
type: Array,
|
|
420
179
|
default: () => []
|
|
421
180
|
},
|
|
422
|
-
|
|
181
|
+
dataProp: {
|
|
423
182
|
type: Object,
|
|
424
183
|
default: () => ({})
|
|
425
184
|
},
|
|
426
|
-
showBatchUpload: {
|
|
427
|
-
type: Boolean,
|
|
428
|
-
default: false
|
|
429
|
-
},
|
|
430
|
-
showBatchPrint: {
|
|
431
|
-
type: Boolean,
|
|
432
|
-
default: false
|
|
433
|
-
},
|
|
434
185
|
uploadHttpRequest: {
|
|
435
186
|
type: Function,
|
|
436
187
|
default: undefined
|
|
@@ -438,21 +189,13 @@ export default {
|
|
|
438
189
|
getFileMethod: {
|
|
439
190
|
type: Function,
|
|
440
191
|
default: undefined
|
|
441
|
-
},
|
|
442
|
-
hideUser: {
|
|
443
|
-
type: Boolean,
|
|
444
|
-
default: false
|
|
445
|
-
},
|
|
446
|
-
hideTime: {
|
|
447
|
-
type: Boolean,
|
|
448
|
-
default: false
|
|
449
192
|
}
|
|
450
193
|
},
|
|
451
194
|
data() {
|
|
452
195
|
this.viewerOptions = {
|
|
453
196
|
debug: true,
|
|
454
197
|
inline: true,
|
|
455
|
-
scalable: false,
|
|
198
|
+
scalable: false,
|
|
456
199
|
navbar: false,
|
|
457
200
|
button: false,
|
|
458
201
|
title: true,
|
|
@@ -472,247 +215,317 @@ export default {
|
|
|
472
215
|
}
|
|
473
216
|
|
|
474
217
|
return {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
218
|
+
tabs: [
|
|
219
|
+
{ key: 'apply', label: '申请附件' },
|
|
220
|
+
{ key: 'base', label: '基础档案' },
|
|
221
|
+
{ key: 'credit', label: '征信报告' },
|
|
222
|
+
{ key: 'source', label: '原始附件' }
|
|
223
|
+
],
|
|
224
|
+
activeTab: 0,
|
|
225
|
+
showAllTypes: true,
|
|
478
226
|
requiredTypes: [],
|
|
479
|
-
fileText: '',
|
|
480
|
-
bathType: '',
|
|
481
227
|
indexK: '$index',
|
|
482
228
|
imgType: /\.(jpg|png|gif|svg)$/i,
|
|
483
|
-
selectionList: [],
|
|
484
|
-
currFileList: [],
|
|
485
229
|
visibleP: false,
|
|
486
230
|
visiblePv: false,
|
|
487
|
-
visibleBatch: false,
|
|
488
231
|
previewUrl: undefined,
|
|
489
232
|
previewName: undefined,
|
|
490
233
|
previewSameOrg: false,
|
|
491
234
|
seeRow: {},
|
|
492
|
-
|
|
235
|
+
uploadProgressMap: {}
|
|
493
236
|
}
|
|
494
237
|
},
|
|
495
238
|
computed: {
|
|
496
239
|
fileAccept() {
|
|
497
|
-
return this.
|
|
240
|
+
return this.dataProp.fileAccept || undefined
|
|
498
241
|
},
|
|
499
242
|
fileSize() {
|
|
500
|
-
return this.
|
|
501
|
-
},
|
|
502
|
-
fileAcceptTip() {
|
|
503
|
-
return this.dataPorp.fileAcceptTip || $lc('支持扩展名:.rar .zip .doc .docx .pdf .jpg...')
|
|
243
|
+
return this.dataProp.fileSize || undefined
|
|
504
244
|
},
|
|
505
245
|
fileData() {
|
|
506
|
-
return this.
|
|
246
|
+
return this.dataProp.fileData || undefined
|
|
507
247
|
},
|
|
508
248
|
typeOptions() {
|
|
509
|
-
return this.
|
|
249
|
+
return this.dataProp.typeOptions
|
|
510
250
|
},
|
|
511
251
|
keys() {
|
|
512
|
-
return this.
|
|
252
|
+
return this.dataProp.keys || keysDefault
|
|
513
253
|
},
|
|
514
254
|
multiple() {
|
|
515
|
-
return this.
|
|
255
|
+
return this.dataProp.multiple ?? true
|
|
256
|
+
},
|
|
257
|
+
uploadedCount() {
|
|
258
|
+
return this.tableData.filter((row) => row[this.keys.url] || row._name).length
|
|
259
|
+
},
|
|
260
|
+
typeRowsMap() {
|
|
261
|
+
const map = Object.create(null)
|
|
262
|
+
const typeKey = this.keys.type
|
|
263
|
+
const urlKey = this.keys.url
|
|
264
|
+
;(this.tableData || []).forEach((row) => {
|
|
265
|
+
const typeValue = row[typeKey]
|
|
266
|
+
if (!typeValue || (!row[urlKey] && !row._name)) return
|
|
267
|
+
if (!map[typeValue]) {
|
|
268
|
+
map[typeValue] = []
|
|
269
|
+
}
|
|
270
|
+
map[typeValue].push(row)
|
|
271
|
+
})
|
|
272
|
+
return map
|
|
273
|
+
},
|
|
274
|
+
displayTypeOptions() {
|
|
275
|
+
if (this.showAllTypes) return this.typeOptions
|
|
276
|
+
return (this.typeOptions || []).filter((item) => {
|
|
277
|
+
const typeValue = item[this.typeMap.value]
|
|
278
|
+
return (this.typeRowsMap[typeValue] || []).length > 0
|
|
279
|
+
})
|
|
280
|
+
},
|
|
281
|
+
displayTypeGroups() {
|
|
282
|
+
return (this.displayTypeOptions || []).map((item) => {
|
|
283
|
+
const typeValue = item[this.typeMap.value]
|
|
284
|
+
return {
|
|
285
|
+
item,
|
|
286
|
+
typeValue,
|
|
287
|
+
rows: this.typeRowsMap[typeValue] || []
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
},
|
|
291
|
+
typeMap() {
|
|
292
|
+
return (
|
|
293
|
+
this.dataProp.typeMap || {
|
|
294
|
+
label: 'attname',
|
|
295
|
+
value: 'attno'
|
|
296
|
+
}
|
|
297
|
+
)
|
|
516
298
|
}
|
|
517
299
|
},
|
|
518
300
|
watch: {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if (this.dataPorp.typeOptions.length === 0) {
|
|
529
|
-
return false
|
|
530
|
-
}
|
|
531
|
-
this.setTableData()
|
|
301
|
+
dataProp: {
|
|
302
|
+
/**
|
|
303
|
+
* 根据附件类型配置初始化必传项。
|
|
304
|
+
* @param {Object} val 配置对象。
|
|
305
|
+
* @returns {void}
|
|
306
|
+
*/
|
|
307
|
+
handler(val) {
|
|
308
|
+
const options = (val && val.typeOptions) || []
|
|
309
|
+
this.requiredTypes = options.filter((item) => item.required === 1).map((item) => item.attno || item.type)
|
|
532
310
|
},
|
|
533
311
|
immediate: true,
|
|
534
312
|
deep: true
|
|
535
313
|
}
|
|
536
314
|
},
|
|
537
315
|
mounted() {
|
|
538
|
-
this.
|
|
316
|
+
this.getFileTypes()
|
|
539
317
|
},
|
|
540
318
|
methods: {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
{
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
this.$emit('aiFn', data)
|
|
319
|
+
async getFileTypes() {
|
|
320
|
+
if (this.dataProp?.bussValues?.length) {
|
|
321
|
+
const { code, data } = await this.$axios.post(
|
|
322
|
+
`/neams/eamsattachfile/getByBussValues`,
|
|
323
|
+
this.dataProp?.bussValues
|
|
324
|
+
)
|
|
325
|
+
if (code !== 200) return
|
|
326
|
+
const { label, value } = this.typeMap
|
|
327
|
+
this.dataProp.typeOptions = data?.map((item) => {
|
|
328
|
+
return {
|
|
329
|
+
...item,
|
|
330
|
+
[label]: item.attname,
|
|
331
|
+
[value]: item.attno
|
|
332
|
+
}
|
|
333
|
+
})
|
|
557
334
|
}
|
|
558
335
|
},
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
336
|
+
/**
|
|
337
|
+
* 从文件名中提取扩展名并统一为小写。
|
|
338
|
+
* @param {string} fileName 文件名。
|
|
339
|
+
* @returns {string} 不含点号的小写扩展名,取不到时返回空字符串。
|
|
340
|
+
*/
|
|
341
|
+
getFileExtension(fileName) {
|
|
342
|
+
if (!fileName || typeof fileName !== 'string') return ''
|
|
343
|
+
const trimmedName = fileName.trim()
|
|
344
|
+
const lastDotIndex = trimmedName.lastIndexOf('.')
|
|
345
|
+
if (lastDotIndex < 0 || lastDotIndex === trimmedName.length - 1) return ''
|
|
346
|
+
return trimmedName.slice(lastDotIndex + 1).toLowerCase()
|
|
347
|
+
},
|
|
348
|
+
/**
|
|
349
|
+
* 判断文件扩展名是否命中指定后缀列表(大小写不敏感)。
|
|
350
|
+
* @param {string} fileName 文件名。
|
|
351
|
+
* @param {Array<string>} extList 扩展名白名单(不带点号)。
|
|
352
|
+
* @returns {boolean} 命中返回 true,否则返回 false。
|
|
353
|
+
*/
|
|
354
|
+
matchFileExtension(fileName, extList = []) {
|
|
355
|
+
const extension = this.getFileExtension(fileName)
|
|
356
|
+
if (!extension || !Array.isArray(extList) || !extList.length) return false
|
|
357
|
+
return extList.some((ext) => extension === String(ext).toLowerCase())
|
|
358
|
+
},
|
|
359
|
+
/**
|
|
360
|
+
* 判断当前类型是否为必传。
|
|
361
|
+
* @param {Object} item 类型项。
|
|
362
|
+
* @returns {boolean} 是否必传。
|
|
363
|
+
*/
|
|
364
|
+
isRequiredType(item) {
|
|
365
|
+
return this.requiredTypes.includes(item.attno || item.type)
|
|
366
|
+
},
|
|
367
|
+
/**
|
|
368
|
+
* 获取某附件类型的所有文件行。
|
|
369
|
+
* @param {string} type 附件类型值。
|
|
370
|
+
* @returns {Array<Object>} 该类型对应的文件列表。
|
|
371
|
+
*/
|
|
372
|
+
getRowsByType(type) {
|
|
373
|
+
return this.typeRowsMap[type] || []
|
|
374
|
+
},
|
|
375
|
+
/**
|
|
376
|
+
* 生成上传时使用的虚拟行对象。
|
|
377
|
+
* @param {Object} item 附件类型。
|
|
378
|
+
* @returns {Object} 供上传回调处理的行对象。
|
|
379
|
+
*/
|
|
380
|
+
buildUploadRow(item) {
|
|
381
|
+
const row = {
|
|
382
|
+
[this.keys.type]: item.type || item.attno,
|
|
383
|
+
[this.keys.user]: JSON.parse(sessionStorage.getItem('userInfo') || '{}').uname || ''
|
|
583
384
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
: `/neams/eamsBaseFile/getOfficeIsEnable`
|
|
601
|
-
)
|
|
602
|
-
this.officeStatus = data
|
|
603
|
-
},
|
|
604
|
-
handleBathUpload() {
|
|
605
|
-
this.visibleBatch = true
|
|
606
|
-
},
|
|
607
|
-
async batchPrint() {
|
|
608
|
-
if (!this.selectionList.length) {
|
|
609
|
-
return this.$message({
|
|
610
|
-
message: $lc(`请先勾选要打印的数据!`),
|
|
611
|
-
type: 'warning',
|
|
612
|
-
showClose: true
|
|
613
|
-
})
|
|
385
|
+
return row
|
|
386
|
+
},
|
|
387
|
+
/**
|
|
388
|
+
* 组装当前类型上传参数。
|
|
389
|
+
* @param {Object} item 附件类型。
|
|
390
|
+
* @returns {Object|undefined} 上传参数。
|
|
391
|
+
*/
|
|
392
|
+
buildTypeUploadData(item) {
|
|
393
|
+
const data = XEUtils.clone(this.fileData || {}, true)
|
|
394
|
+
if (!data || !data.data) return data
|
|
395
|
+
try {
|
|
396
|
+
const dto = JSON.parse(data.data)
|
|
397
|
+
dto[this.keys.type] = item.type || item.attno
|
|
398
|
+
data.data = JSON.stringify(dto)
|
|
399
|
+
} catch (e) {
|
|
400
|
+
return data
|
|
614
401
|
}
|
|
615
|
-
|
|
616
|
-
|
|
402
|
+
return data
|
|
403
|
+
},
|
|
404
|
+
/**
|
|
405
|
+
* 处理上传进度。
|
|
406
|
+
* @param {Object} event 上传进度事件。
|
|
407
|
+
* @param {string} type 附件类型。
|
|
408
|
+
* @returns {void}
|
|
409
|
+
*/
|
|
410
|
+
onProgressFn(event, type) {
|
|
411
|
+
const percent = event && event.percent ? Math.round(event.percent) : 0
|
|
412
|
+
this.$set(this.uploadProgressMap, type, percent <= 99 ? percent : 99)
|
|
413
|
+
},
|
|
414
|
+
/**
|
|
415
|
+
* 上传前拦截,透传外部回调。
|
|
416
|
+
* @param {File} file 文件对象。
|
|
417
|
+
* @param {Object} row 虚拟行对象。
|
|
418
|
+
* @returns {Promise|boolean|undefined} 上传前处理结果。
|
|
419
|
+
*/
|
|
420
|
+
beforeUploadFn(file, row) {
|
|
421
|
+
let bu = this.$listeners['before-upload'] || this.$listeners.beforeUpload
|
|
422
|
+
if (bu) return bu(file, row)
|
|
423
|
+
return undefined
|
|
424
|
+
},
|
|
425
|
+
/**
|
|
426
|
+
* 类型维度上传成功处理。
|
|
427
|
+
* @param {Object} response 上传响应。
|
|
428
|
+
* @param {File} file 上传文件。
|
|
429
|
+
* @param {Array<Object>} fileList 当前文件列表。
|
|
430
|
+
* @param {Object} item 类型配置。
|
|
431
|
+
* @returns {void}
|
|
432
|
+
*/
|
|
433
|
+
onTypeUploadSuccess(response, file, fileList, item) {
|
|
434
|
+
const row = {
|
|
435
|
+
id: 'n' + Math.random(),
|
|
436
|
+
_name: file.name,
|
|
437
|
+
[this.keys.rowKey]: response.data,
|
|
438
|
+
[this.keys.type]: item.type || item.attno,
|
|
439
|
+
[this.keys.time]: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
|
440
|
+
[this.keys.user]: JSON.parse(sessionStorage.getItem('userInfo') || '{}').uname || '',
|
|
441
|
+
[this.keys.url]: response.data,
|
|
442
|
+
[this.keys.name]: file.name,
|
|
443
|
+
_percent: response.code >= 900 || response.code === -1 ? 99 : 100,
|
|
444
|
+
_status: response.code >= 900 || response.code === -1 ? 'error' : 'success',
|
|
445
|
+
_typeDisabled: true
|
|
617
446
|
}
|
|
618
|
-
const { code, data } = await axios.post(
|
|
619
|
-
this.apiPrefix
|
|
620
|
-
? this.apiPrefix + `/neams/eamsbaserecord/mergeDownladPdf`
|
|
621
|
-
: `/neams/eamsbaserecord/mergeDownladPdf`,
|
|
622
|
-
this.selectionList.map((res) => res.beid) || [],
|
|
623
|
-
{
|
|
624
|
-
responseType: 'blob'
|
|
625
|
-
}
|
|
626
|
-
)
|
|
627
|
-
if (code === 200) {
|
|
628
|
-
let aDom = document.createElement('a')
|
|
629
|
-
aDom.href = data
|
|
630
|
-
aDom.download = '批量附件.pdf'
|
|
631
|
-
aDom.click()
|
|
632
447
|
|
|
448
|
+
this.tableData.unshift(row)
|
|
449
|
+
this.$set(this.uploadProgressMap, item.type || item.attno, 100)
|
|
450
|
+
this.$emit('on-success', file, row)
|
|
451
|
+
|
|
452
|
+
if (this.multiple && fileList && fileList.length > 1) {
|
|
633
453
|
this.$nextTick(() => {
|
|
634
|
-
|
|
635
|
-
|
|
454
|
+
const uploadRef =
|
|
455
|
+
this.$refs['upload' + this.typeOptions.findIndex((x) => (x.type || x.attno) === (item.type || item.attno))]
|
|
456
|
+
if (uploadRef) {
|
|
457
|
+
uploadRef.fileList = []
|
|
458
|
+
}
|
|
636
459
|
})
|
|
637
460
|
}
|
|
638
461
|
},
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (
|
|
652
|
-
this.visibleBatch = false
|
|
653
|
-
}
|
|
654
|
-
$uploadwrap.submit()
|
|
655
|
-
},
|
|
656
|
-
batchSuccess(response, file, fileList) {
|
|
657
|
-
let row = { ...this.dataPorp.keys }
|
|
658
|
-
this.tableData.splice(0, 0, row)
|
|
659
|
-
this.$nextTick(() => {
|
|
660
|
-
this.onSuccessFn(response, file, fileList, row)
|
|
661
|
-
})
|
|
662
|
-
|
|
663
|
-
if (fileList.every((f) => f.status === 'success')) {
|
|
664
|
-
this.visibleBatch = false
|
|
665
|
-
}
|
|
666
|
-
},
|
|
667
|
-
batchError(err, file, fileList) {
|
|
668
|
-
if (!fileList.some((f) => f.uid === file.uid)) {
|
|
669
|
-
let list = [...fileList]
|
|
462
|
+
/**
|
|
463
|
+
* 类型维度上传失败处理。
|
|
464
|
+
* @param {Error|Object} err 错误对象。
|
|
465
|
+
* @param {File} file 上传文件。
|
|
466
|
+
* @param {Array<Object>} fileList 当前文件列表。
|
|
467
|
+
* @param {Object} item 类型配置。
|
|
468
|
+
* @param {number} index 当前索引。
|
|
469
|
+
* @returns {void}
|
|
470
|
+
*/
|
|
471
|
+
onTypeUploadError(err, file, fileList, item, index) {
|
|
472
|
+
this.$set(this.uploadProgressMap, item.type || item.attno, 0)
|
|
473
|
+
const clUpload = this.$refs['upload' + index]
|
|
474
|
+
if (clUpload) {
|
|
670
475
|
file.status = 'ready'
|
|
671
|
-
|
|
672
|
-
file.OrgName || (file.OrgName = file.name)
|
|
673
|
-
file.name = file.OrgName + ` *(${err.msg})`
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
list.push(file)
|
|
677
|
-
let $uploadwrap = this.$refs['upload-batch']
|
|
678
|
-
$uploadwrap.fileList = list
|
|
476
|
+
clUpload.fileList = [file]
|
|
679
477
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
this.$emit('
|
|
691
|
-
},
|
|
478
|
+
this.$emit('on-error', file, item)
|
|
479
|
+
},
|
|
480
|
+
/**
|
|
481
|
+
* 删除单条附件记录。
|
|
482
|
+
* @param {Object} row 文件行数据。
|
|
483
|
+
* @returns {void}
|
|
484
|
+
*/
|
|
485
|
+
deleteSingleRow(row) {
|
|
486
|
+
const index = this.tableData.findIndex((item) => item === row)
|
|
487
|
+
if (index > -1) this.tableData.splice(index, 1)
|
|
488
|
+
this.$emit('delete-rows', [row])
|
|
489
|
+
},
|
|
490
|
+
/**
|
|
491
|
+
* 切换展开/收起未上传类型。
|
|
492
|
+
* @returns {void}
|
|
493
|
+
*/
|
|
494
|
+
toggleCollapse() {
|
|
495
|
+
this.showAllTypes = !this.showAllTypes
|
|
496
|
+
},
|
|
497
|
+
/**
|
|
498
|
+
* 计算类型状态图标。
|
|
499
|
+
* @param {string} type 附件类型值。
|
|
500
|
+
* @returns {string} success/warning/default。
|
|
501
|
+
*/
|
|
502
|
+
getTypeStatus(type) {
|
|
503
|
+
const rows = this.getRowsByType(type)
|
|
504
|
+
if (!rows.length) return 'default'
|
|
505
|
+
if (rows.some((row) => row._status === 'error' || row._status === 'exception')) return 'warning'
|
|
506
|
+
return 'success'
|
|
507
|
+
},
|
|
508
|
+
/**
|
|
509
|
+
* 批量下载全部已上传附件。
|
|
510
|
+
* @returns {void}
|
|
511
|
+
*/
|
|
692
512
|
downRows() {
|
|
693
|
-
|
|
513
|
+
const list = this.tableData.filter((item) => item[this.keys.url] || item._name)
|
|
514
|
+
if (!list.length) {
|
|
694
515
|
return this.$message({
|
|
695
|
-
message: $lc(
|
|
516
|
+
message: $lc('请先上传要下载的数据!'),
|
|
696
517
|
type: 'warning',
|
|
697
518
|
showClose: true
|
|
698
519
|
})
|
|
699
520
|
}
|
|
700
|
-
this.$emit(
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
message: $lc('请先勾选要删除的数据!'),
|
|
709
|
-
type: 'warning',
|
|
710
|
-
showClose: true
|
|
711
|
-
})
|
|
712
|
-
}
|
|
713
|
-
this.$emit('delete-rows', this.selectionList)
|
|
714
|
-
},
|
|
715
|
-
|
|
521
|
+
this.$emit('down-rows', list)
|
|
522
|
+
},
|
|
523
|
+
/**
|
|
524
|
+
* 获取附件下载或预览信息。
|
|
525
|
+
* @param {Object} row 文件行数据。
|
|
526
|
+
* @param {'preview'} [type] 读取类型。
|
|
527
|
+
* @returns {Promise<Object>} 文件信息。
|
|
528
|
+
*/
|
|
716
529
|
async getFileInfo(row, type) {
|
|
717
530
|
if (this.getFileMethod) {
|
|
718
531
|
return this.getFileMethod(row, type)
|
|
@@ -721,36 +534,39 @@ export default {
|
|
|
721
534
|
this.seePrefix && (_url = this.seePrefix + _url)
|
|
722
535
|
if (_url) {
|
|
723
536
|
if (type === 'preview') {
|
|
724
|
-
// 预览
|
|
725
537
|
return {
|
|
726
538
|
url: `/api/onlinePreview?beid=${row[this.keys.rowKey]}`,
|
|
727
539
|
name: row[this.keys.name] + '.html',
|
|
728
540
|
sameOrg: this.seeTypes.test(row[this.keys.name])
|
|
729
541
|
}
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
this.apiPrefix
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
responseType: 'blob'
|
|
739
|
-
}
|
|
740
|
-
)
|
|
741
|
-
let name = row[this.keys.name] || blob.name
|
|
742
|
-
return {
|
|
743
|
-
url: URL.createObjectURL(blob),
|
|
744
|
-
name: name,
|
|
745
|
-
sameOrg: this.seeTypes.test(name)
|
|
542
|
+
}
|
|
543
|
+
let blob = await axios.get(
|
|
544
|
+
this.apiPrefix
|
|
545
|
+
? this.apiPrefix + `/neams/eamsbaserecord/download/${row[this.keys.rowKey]}`
|
|
546
|
+
: `/neams/eamsbaserecord/download/${row[this.keys.rowKey]}`,
|
|
547
|
+
null,
|
|
548
|
+
{
|
|
549
|
+
responseType: 'blob'
|
|
746
550
|
}
|
|
551
|
+
)
|
|
552
|
+
let name = row[this.keys.name] || blob.name
|
|
553
|
+
return {
|
|
554
|
+
url: URL.createObjectURL(blob),
|
|
555
|
+
name: name,
|
|
556
|
+
sameOrg: this.seeTypes.test(name)
|
|
747
557
|
}
|
|
748
|
-
} else {
|
|
749
|
-
return {}
|
|
750
558
|
}
|
|
559
|
+
return {}
|
|
751
560
|
},
|
|
561
|
+
/**
|
|
562
|
+
* 下载单个附件。
|
|
563
|
+
* @param {Object} row 文件行数据。
|
|
564
|
+
* @returns {Promise<void>} 下载执行结果。
|
|
565
|
+
*/
|
|
752
566
|
async downFile(row) {
|
|
753
|
-
let
|
|
567
|
+
let info = await this.getFileInfo(row)
|
|
568
|
+
let url = info.url
|
|
569
|
+
let name = info.name
|
|
754
570
|
if (url) {
|
|
755
571
|
let aDom = document.createElement('a')
|
|
756
572
|
aDom.href = url
|
|
@@ -763,8 +579,16 @@ export default {
|
|
|
763
579
|
})
|
|
764
580
|
}
|
|
765
581
|
},
|
|
582
|
+
/**
|
|
583
|
+
* 预览单个附件。
|
|
584
|
+
* @param {Object} row 文件行数据。
|
|
585
|
+
* @returns {Promise<void>} 预览执行结果。
|
|
586
|
+
*/
|
|
766
587
|
async seeFile(row) {
|
|
767
|
-
let
|
|
588
|
+
let info = await this.getFileInfo(row, 'preview')
|
|
589
|
+
let url = info.url
|
|
590
|
+
let name = info.name
|
|
591
|
+
let sameOrg = info.sameOrg
|
|
768
592
|
if (url) {
|
|
769
593
|
this.previewSameOrg = sameOrg
|
|
770
594
|
this.previewUrl = url
|
|
@@ -776,16 +600,28 @@ export default {
|
|
|
776
600
|
this.seeRow = row
|
|
777
601
|
}
|
|
778
602
|
},
|
|
603
|
+
/**
|
|
604
|
+
* 预览上一条附件。
|
|
605
|
+
* @returns {void}
|
|
606
|
+
*/
|
|
779
607
|
preSee() {
|
|
780
608
|
let i = this.tableData.findIndex((row) => row === this.seeRow)
|
|
781
609
|
let row = this.tableData[i - 1] || this.tableData[this.tableData.length - 1]
|
|
782
610
|
this.seeFile(row)
|
|
783
611
|
},
|
|
612
|
+
/**
|
|
613
|
+
* 预览下一条附件。
|
|
614
|
+
* @returns {void}
|
|
615
|
+
*/
|
|
784
616
|
nextSee() {
|
|
785
617
|
let i = this.tableData.findIndex((row) => row === this.seeRow)
|
|
786
618
|
let row = this.tableData[i + 1] || this.tableData[0]
|
|
787
619
|
this.seeFile(row)
|
|
788
620
|
},
|
|
621
|
+
/**
|
|
622
|
+
* 关闭预览并释放资源。
|
|
623
|
+
* @returns {void}
|
|
624
|
+
*/
|
|
789
625
|
closeSee() {
|
|
790
626
|
this.previewUrl && URL.revokeObjectURL(this.previewUrl)
|
|
791
627
|
this.previewUrl = undefined
|
|
@@ -794,144 +630,211 @@ export default {
|
|
|
794
630
|
this.visiblePv = false
|
|
795
631
|
}, 300)
|
|
796
632
|
},
|
|
633
|
+
/**
|
|
634
|
+
* 兜底上传请求实现(兼容外部不传 uploadHttpRequest)。
|
|
635
|
+
* @param {Object} opt 上传参数。
|
|
636
|
+
* @returns {Promise<any>} 上传结果。
|
|
637
|
+
*/
|
|
797
638
|
uploadHttpRequestBath(opt) {
|
|
798
|
-
console.log(opt)
|
|
799
639
|
if (this.uploadHttpRequest) {
|
|
800
640
|
return this.uploadHttpRequest(opt)
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
} else {
|
|
810
|
-
data = opt.data
|
|
641
|
+
}
|
|
642
|
+
let FD = new FormData()
|
|
643
|
+
FD.append(opt.filename, opt.file)
|
|
644
|
+
|
|
645
|
+
let data = opt.data
|
|
646
|
+
if (data) {
|
|
647
|
+
for (let k in data) {
|
|
648
|
+
FD.append(k, data[k])
|
|
811
649
|
}
|
|
650
|
+
}
|
|
812
651
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
652
|
+
let abort
|
|
653
|
+
let Pro = axios.post(opt.action + '?r=' + Math.random(), FD, {
|
|
654
|
+
headers: Object.assign(auth.setHeaders(this.headers), { 'Content-Type': 'multipart/form-data' }),
|
|
655
|
+
loading: false,
|
|
656
|
+
timeout: 900000,
|
|
657
|
+
onUploadProgress: (arg) => {
|
|
658
|
+
if (opt.onProgress) {
|
|
659
|
+
arg.percent = arg.progress * 100
|
|
660
|
+
opt.onProgress(arg)
|
|
819
661
|
}
|
|
662
|
+
},
|
|
663
|
+
cancelToken: new _axios.CancelToken((cancel) => {
|
|
664
|
+
abort = cancel
|
|
665
|
+
})
|
|
666
|
+
})
|
|
667
|
+
Pro.abort = abort
|
|
668
|
+
return Pro
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
</script>
|
|
673
|
+
|
|
674
|
+
<style lang="scss" scoped>
|
|
675
|
+
.file-upload-table-v3 {
|
|
676
|
+
width: 100%;
|
|
677
|
+
|
|
678
|
+
background: #fff;
|
|
679
|
+
|
|
680
|
+
.panel {
|
|
681
|
+
padding: 0 16px 16px;
|
|
682
|
+
|
|
683
|
+
.panel-top {
|
|
684
|
+
height: 40px;
|
|
685
|
+
display: flex;
|
|
686
|
+
align-items: center;
|
|
687
|
+
justify-content: space-between;
|
|
688
|
+
font-size: 14px;
|
|
689
|
+
.summary {
|
|
690
|
+
display: flex;
|
|
691
|
+
align-items: center;
|
|
692
|
+
color: #4e5969;
|
|
693
|
+
|
|
694
|
+
i {
|
|
695
|
+
margin-right: 4px;
|
|
820
696
|
}
|
|
821
697
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
timeout: 900000,
|
|
827
|
-
onUploadProgress: (arg) => {
|
|
828
|
-
if (opt.onProgress) {
|
|
829
|
-
arg.percent = arg.progress * 100
|
|
830
|
-
opt.onProgress(arg)
|
|
831
|
-
}
|
|
832
|
-
},
|
|
833
|
-
cancelToken: new _axios.CancelToken((cancel) => {
|
|
834
|
-
abort = cancel
|
|
835
|
-
})
|
|
836
|
-
})
|
|
837
|
-
Pro.abort = abort
|
|
838
|
-
return Pro
|
|
698
|
+
.summary-action {
|
|
699
|
+
margin-left: 12px;
|
|
700
|
+
padding: 0;
|
|
701
|
+
}
|
|
839
702
|
}
|
|
840
|
-
},
|
|
841
|
-
beforeUploadFn(file, row) {
|
|
842
|
-
this.$set(row, '_percent', 0)
|
|
843
|
-
this.$set(row, '_status', undefined)
|
|
844
703
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
this.$set(row, '_name', file.name)
|
|
857
|
-
|
|
858
|
-
this.$set(row, [this.keys.rowKey], response.data)
|
|
859
|
-
this.$set(row, [this.keys.type], row[this.keys.type] || this.bathType)
|
|
860
|
-
row[this.keys.time] = dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
861
|
-
if (response.code >= 900 || response.code === -1) {
|
|
862
|
-
this.$set(row, '_percent', 99)
|
|
863
|
-
this.$set(row, '_status', 'error')
|
|
864
|
-
} else {
|
|
865
|
-
this.$set(row, '_percent', 100)
|
|
866
|
-
this.$set(row, '_status', 'success')
|
|
704
|
+
.toggle-btn {
|
|
705
|
+
padding: 0;
|
|
706
|
+
|
|
707
|
+
i {
|
|
708
|
+
margin-left: 4px;
|
|
709
|
+
transition: transform 0.2s;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.is-reverse {
|
|
713
|
+
transform: rotate(180deg);
|
|
714
|
+
}
|
|
867
715
|
}
|
|
868
|
-
|
|
869
|
-
|
|
716
|
+
}
|
|
717
|
+
.type-list {
|
|
718
|
+
min-height: 200px;
|
|
719
|
+
max-height: 680px;
|
|
720
|
+
overflow-y: auto;
|
|
721
|
+
.type-item {
|
|
722
|
+
margin-top: 8px;
|
|
870
723
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
724
|
+
.type-row {
|
|
725
|
+
min-height: 46px;
|
|
726
|
+
background: #f7f8fa;
|
|
727
|
+
border-radius: 4px;
|
|
728
|
+
padding: 0 12px;
|
|
729
|
+
display: flex;
|
|
730
|
+
align-items: center;
|
|
731
|
+
justify-content: space-between;
|
|
732
|
+
|
|
733
|
+
.type-meta {
|
|
734
|
+
display: flex;
|
|
735
|
+
align-items: center;
|
|
736
|
+
color: #1d2129;
|
|
737
|
+
font-family: 'PingFang SC';
|
|
738
|
+
font-size: 14px;
|
|
739
|
+
font-style: normal;
|
|
740
|
+
font-weight: 500;
|
|
741
|
+
line-height: 22px;
|
|
742
|
+
|
|
743
|
+
.required {
|
|
744
|
+
color: #f53f3f;
|
|
745
|
+
margin-right: 2px;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.type-index {
|
|
749
|
+
margin-right: 2px;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.status-icon {
|
|
753
|
+
width: 16px;
|
|
754
|
+
height: 16px;
|
|
755
|
+
margin-left: 8px;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.upload-trigger {
|
|
760
|
+
font-size: 14px;
|
|
761
|
+
font-style: normal;
|
|
762
|
+
font-weight: 400;
|
|
763
|
+
line-height: 22px;
|
|
764
|
+
padding: 0;
|
|
765
|
+
color: #007aff;
|
|
879
766
|
}
|
|
880
|
-
})
|
|
881
|
-
let _percent = 0
|
|
882
|
-
let _status = undefined
|
|
883
|
-
if (response.code >= 900 || response.code === -1) {
|
|
884
|
-
_percent = 99
|
|
885
|
-
_status = 'error'
|
|
886
|
-
} else {
|
|
887
|
-
_percent = 99
|
|
888
|
-
_status = 'success'
|
|
889
767
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
[this.keys.time]: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
|
895
|
-
[this.keys.url]: response.data,
|
|
896
|
-
[this.keys.name]: file.name,
|
|
897
|
-
_status,
|
|
898
|
-
_typeDisabled: true,
|
|
899
|
-
[this.keys.user]: deepRow[this.keys.user],
|
|
900
|
-
[this.keys.type]: deepRow[this.keys.type]
|
|
901
|
-
})
|
|
902
|
-
}, 100)
|
|
903
|
-
} else {
|
|
904
|
-
this.onSuccessFn(response, file, fileList, row)
|
|
905
|
-
}
|
|
906
|
-
},
|
|
907
|
-
errorFn(err, file, fileList, row, $index) {
|
|
908
|
-
this.$set(row, '_status', 'exception')
|
|
768
|
+
.type-row__is-success {
|
|
769
|
+
border-radius: 4px;
|
|
770
|
+
background-color: #e8fff3;
|
|
771
|
+
}
|
|
909
772
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
773
|
+
.file-cards {
|
|
774
|
+
margin-top: 8px;
|
|
775
|
+
display: grid;
|
|
776
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
777
|
+
gap: 12px;
|
|
914
778
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
779
|
+
.file-card {
|
|
780
|
+
height: 50px;
|
|
781
|
+
background: #f7f8fa;
|
|
782
|
+
border-radius: 2px;
|
|
783
|
+
padding: 4px 8px;
|
|
784
|
+
display: flex;
|
|
785
|
+
align-items: center;
|
|
786
|
+
justify-content: space-between;
|
|
919
787
|
|
|
920
|
-
|
|
921
|
-
|
|
788
|
+
.file-info {
|
|
789
|
+
flex: 1;
|
|
790
|
+
display: flex;
|
|
791
|
+
align-items: center;
|
|
792
|
+
min-width: 0;
|
|
793
|
+
cursor: pointer;
|
|
922
794
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
795
|
+
.file-name {
|
|
796
|
+
font-size: 14px;
|
|
797
|
+
color: #1d2129;
|
|
798
|
+
font-weight: 500;
|
|
799
|
+
line-height: 22px;
|
|
800
|
+
overflow: hidden;
|
|
801
|
+
text-overflow: ellipsis;
|
|
802
|
+
white-space: nowrap;
|
|
803
|
+
}
|
|
928
804
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
805
|
+
.file-meta {
|
|
806
|
+
margin-top: 2px;
|
|
807
|
+
font-size: 12px;
|
|
808
|
+
font-style: normal;
|
|
809
|
+
font-weight: 400;
|
|
810
|
+
line-height: 20px;
|
|
811
|
+
color: #4e5969;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.file-actions {
|
|
816
|
+
margin-left: 8px;
|
|
817
|
+
border-left: 1px solid #e5e6eb;
|
|
818
|
+
display: flex;
|
|
819
|
+
align-items: center;
|
|
820
|
+
.el-button {
|
|
821
|
+
padding: 0 0 0 12px;
|
|
822
|
+
color: #4e5969;
|
|
823
|
+
:hover {
|
|
824
|
+
color: #007aff;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
934
831
|
}
|
|
935
832
|
}
|
|
936
833
|
}
|
|
937
|
-
|
|
834
|
+
|
|
835
|
+
.file-upload-table_preview-pn {
|
|
836
|
+
position: absolute;
|
|
837
|
+
right: 46px;
|
|
838
|
+
top: 10px;
|
|
839
|
+
}
|
|
840
|
+
</style>
|