n20-common-lib 2.22.44 → 2.22.46
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
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
<div class="n20-date-picker" :class="{ 'has-long-term': showLongTerm }">
|
|
3
|
+
<el-date-picker
|
|
4
|
+
ref="date-picker"
|
|
5
|
+
class="n20-date-editor"
|
|
6
|
+
:class="{ 'has-value': clearable && value }"
|
|
7
|
+
v-bind="$attrs"
|
|
8
|
+
:value="value"
|
|
9
|
+
:clearable="clearable"
|
|
10
|
+
:disabled="datePickerDisabled"
|
|
11
|
+
v-on="listeners"
|
|
12
|
+
/>
|
|
13
|
+
<el-checkbox
|
|
14
|
+
v-if="showLongTerm"
|
|
15
|
+
v-model="longTermC"
|
|
16
|
+
class="n20-date-picker__long-term"
|
|
17
|
+
:disabled="checkboxDisabled"
|
|
18
|
+
>
|
|
19
|
+
{{ longTermLabel | $lc }}
|
|
20
|
+
</el-checkbox>
|
|
21
|
+
</div>
|
|
11
22
|
</template>
|
|
12
23
|
|
|
13
24
|
<script>
|
|
25
|
+
const LONG_TERM_DATE = new Date(9999, 11, 31, 23, 59, 59)
|
|
26
|
+
|
|
14
27
|
export default {
|
|
15
28
|
name: 'DatePicker',
|
|
16
29
|
props: {
|
|
@@ -21,7 +34,139 @@ export default {
|
|
|
21
34
|
clearable: {
|
|
22
35
|
type: Boolean,
|
|
23
36
|
default: true
|
|
37
|
+
},
|
|
38
|
+
showLongTerm: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false
|
|
41
|
+
},
|
|
42
|
+
longTerm: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false
|
|
45
|
+
},
|
|
46
|
+
longTermLabel: {
|
|
47
|
+
type: String,
|
|
48
|
+
default: '长期'
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
computed: {
|
|
52
|
+
listeners() {
|
|
53
|
+
return Object.assign({}, this.$listeners, {
|
|
54
|
+
input: (val) => {
|
|
55
|
+
this.$emit('input', val)
|
|
56
|
+
if (this.longTerm) {
|
|
57
|
+
this.$emit('update:long-term', false)
|
|
58
|
+
this.$emit('changeLongTerm', {
|
|
59
|
+
longTerm: false,
|
|
60
|
+
value: val
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
},
|
|
66
|
+
longTermC: {
|
|
67
|
+
get() {
|
|
68
|
+
return this.longTerm
|
|
69
|
+
},
|
|
70
|
+
set(val) {
|
|
71
|
+
this.handleLongTermChange(val)
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
datePickerDisabled() {
|
|
75
|
+
return this.longTerm || this.isDisabled
|
|
76
|
+
},
|
|
77
|
+
checkboxDisabled() {
|
|
78
|
+
return this.isDisabled
|
|
79
|
+
},
|
|
80
|
+
isDisabled() {
|
|
81
|
+
return this.$attrs.disabled === '' || this.$attrs.disabled === true || this.$attrs.disabled === 'disabled'
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
methods: {
|
|
85
|
+
handleLongTermChange(val) {
|
|
86
|
+
this.$emit('update:long-term', val)
|
|
87
|
+
|
|
88
|
+
if (val) {
|
|
89
|
+
const longTermValue = this.getLongTermValue()
|
|
90
|
+
this.$emit('input', longTermValue)
|
|
91
|
+
this.$emit('change', longTermValue)
|
|
92
|
+
this.$emit('changeLongTerm', {
|
|
93
|
+
longTerm: true,
|
|
94
|
+
value: longTermValue
|
|
95
|
+
})
|
|
96
|
+
} else {
|
|
97
|
+
const currentValue = this.getCurrentValue()
|
|
98
|
+
this.$emit('input', currentValue)
|
|
99
|
+
this.$emit('change', currentValue)
|
|
100
|
+
this.$emit('changeLongTerm', {
|
|
101
|
+
longTerm: false,
|
|
102
|
+
value: currentValue
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
getLongTermValue() {
|
|
107
|
+
return this.getDateValue(LONG_TERM_DATE)
|
|
108
|
+
},
|
|
109
|
+
getCurrentValue() {
|
|
110
|
+
return this.getDateValue(new Date())
|
|
111
|
+
},
|
|
112
|
+
getDateValue(date) {
|
|
113
|
+
const valueFormat = this.$attrs['value-format']
|
|
114
|
+
|
|
115
|
+
if (valueFormat === 'timestamp') {
|
|
116
|
+
return date.getTime()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!valueFormat) {
|
|
120
|
+
return new Date(date.getTime())
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const year = date.getFullYear() + ''
|
|
124
|
+
const month = this.padDateValue(date.getMonth() + 1)
|
|
125
|
+
const day = this.padDateValue(date.getDate())
|
|
126
|
+
const hours = this.padDateValue(date.getHours())
|
|
127
|
+
const minutes = this.padDateValue(date.getMinutes())
|
|
128
|
+
const seconds = this.padDateValue(date.getSeconds())
|
|
129
|
+
|
|
130
|
+
return valueFormat
|
|
131
|
+
.replace(/yyyy/g, year)
|
|
132
|
+
.replace(/YYYY/g, year)
|
|
133
|
+
.replace(/MM/g, month)
|
|
134
|
+
.replace(/dd/g, day)
|
|
135
|
+
.replace(/DD/g, day)
|
|
136
|
+
.replace(/HH/g, hours)
|
|
137
|
+
.replace(/hh/g, hours)
|
|
138
|
+
.replace(/mm/g, minutes)
|
|
139
|
+
.replace(/ss/g, seconds)
|
|
140
|
+
},
|
|
141
|
+
padDateValue(value) {
|
|
142
|
+
return value > 9 ? value + '' : '0' + value
|
|
24
143
|
}
|
|
25
144
|
}
|
|
26
145
|
}
|
|
27
146
|
</script>
|
|
147
|
+
|
|
148
|
+
<style scoped>
|
|
149
|
+
.n20-date-picker {
|
|
150
|
+
display: inline-block;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.n20-date-picker > .n20-date-editor {
|
|
154
|
+
width: 100%;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.n20-date-picker.has-long-term {
|
|
158
|
+
display: inline-flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.n20-date-picker.has-long-term > .n20-date-editor {
|
|
163
|
+
flex: 1;
|
|
164
|
+
width: auto;
|
|
165
|
+
min-width: 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.n20-date-picker__long-term {
|
|
169
|
+
margin-left: 8px;
|
|
170
|
+
white-space: nowrap;
|
|
171
|
+
}
|
|
172
|
+
</style>
|
|
@@ -1,43 +1,32 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
/>
|
|
26
|
-
<el-checkbox
|
|
27
|
-
v-if="showLongTermCheckbox"
|
|
28
|
-
v-model="longTermC"
|
|
29
|
-
class="n20-date-picker-por__long-term"
|
|
30
|
-
:disabled="longTermDisabled"
|
|
31
|
-
>
|
|
32
|
-
{{ '长期' | $lc }}
|
|
33
|
-
</el-checkbox>
|
|
34
|
-
</div>
|
|
2
|
+
<el-date-picker
|
|
3
|
+
ref="date-picker"
|
|
4
|
+
v-model="valueC"
|
|
5
|
+
class="n20-date-editor"
|
|
6
|
+
:class="{
|
|
7
|
+
'has-value': clearable && valueC,
|
|
8
|
+
[this.$attrs && this.$attrs['rule-form']]: !valueC
|
|
9
|
+
}"
|
|
10
|
+
:popper-class="
|
|
11
|
+
!clearable && type === 'datetimerange'
|
|
12
|
+
? 'clearable-datetimerange' + ' ' + $attrs['popper-class']
|
|
13
|
+
: $attrs['popper-class']
|
|
14
|
+
"
|
|
15
|
+
:type="type"
|
|
16
|
+
:value-format="valueFormat"
|
|
17
|
+
:placeholder="'选择日期' | $lc"
|
|
18
|
+
:start-placeholder="'开始日期' | $lc"
|
|
19
|
+
:end-placeholder="'结束日期' | $lc"
|
|
20
|
+
:picker-options="pickerOptionsAs"
|
|
21
|
+
:clearable="clearable"
|
|
22
|
+
v-bind="$attrs"
|
|
23
|
+
v-on="listeners"
|
|
24
|
+
/>
|
|
35
25
|
</template>
|
|
36
26
|
|
|
37
27
|
<script>
|
|
38
|
-
import dayjs from 'dayjs'
|
|
39
|
-
|
|
40
28
|
import { $lc } from '../../utils/i18n/index'
|
|
29
|
+
import dayjs from 'dayjs'
|
|
41
30
|
|
|
42
31
|
let startDate = ''
|
|
43
32
|
|
|
@@ -263,20 +252,25 @@ export default {
|
|
|
263
252
|
type: Boolean,
|
|
264
253
|
default: true
|
|
265
254
|
},
|
|
266
|
-
showLongTerm: {
|
|
267
|
-
type: Boolean,
|
|
268
|
-
default: false
|
|
269
|
-
},
|
|
270
|
-
longTerm: {
|
|
271
|
-
type: Boolean,
|
|
272
|
-
default: false
|
|
273
|
-
},
|
|
274
255
|
pickerOptions: {
|
|
275
256
|
type: Object,
|
|
276
257
|
default: () => ({})
|
|
277
258
|
}
|
|
278
259
|
},
|
|
279
260
|
data() {
|
|
261
|
+
let shortcuts = undefined
|
|
262
|
+
if (this.shortcuts && ['daterange', 'datetimerange'].includes(this.type))
|
|
263
|
+
shortcuts = this.startStop ? shortcuts_2 : shortcuts_1
|
|
264
|
+
|
|
265
|
+
this.pickerOptionsAs = Object.assign(
|
|
266
|
+
{
|
|
267
|
+
disabledDate: this.minNow ? disabledDate_1 : this.maxNow ? disabledDate_2 : undefined,
|
|
268
|
+
shortcuts
|
|
269
|
+
// onPick
|
|
270
|
+
},
|
|
271
|
+
this.pickerOptions
|
|
272
|
+
)
|
|
273
|
+
|
|
280
274
|
this.listeners = Object.assign({}, this.$listeners, {
|
|
281
275
|
input: () => {},
|
|
282
276
|
change: () => {}
|
|
@@ -285,56 +279,9 @@ export default {
|
|
|
285
279
|
return {}
|
|
286
280
|
},
|
|
287
281
|
computed: {
|
|
288
|
-
isRangeType() {
|
|
289
|
-
return ['daterange', 'monthrange', 'datetimerange'].includes(this.type)
|
|
290
|
-
},
|
|
291
|
-
showLongTermCheckbox() {
|
|
292
|
-
return this.showLongTerm && this.isRangeType
|
|
293
|
-
},
|
|
294
|
-
isLongTerm() {
|
|
295
|
-
return this.showLongTermCheckbox && this.longTerm
|
|
296
|
-
},
|
|
297
|
-
pickerType() {
|
|
298
|
-
if (!this.isLongTerm) return this.type
|
|
299
|
-
const typeMap = {
|
|
300
|
-
daterange: 'date',
|
|
301
|
-
datetimerange: 'datetime',
|
|
302
|
-
monthrange: 'month'
|
|
303
|
-
}
|
|
304
|
-
return typeMap[this.type] || this.type
|
|
305
|
-
},
|
|
306
|
-
pickerOptionsAs() {
|
|
307
|
-
let shortcuts = undefined
|
|
308
|
-
if (!this.isLongTerm && this.shortcuts && ['daterange', 'datetimerange'].includes(this.type)) {
|
|
309
|
-
shortcuts = this.startStop ? shortcuts_2 : shortcuts_1
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return Object.assign(
|
|
313
|
-
{
|
|
314
|
-
disabledDate: this.minNow ? disabledDate_1 : this.maxNow ? disabledDate_2 : undefined,
|
|
315
|
-
shortcuts
|
|
316
|
-
// onPick
|
|
317
|
-
},
|
|
318
|
-
this.pickerOptions
|
|
319
|
-
)
|
|
320
|
-
},
|
|
321
|
-
longTermC: {
|
|
322
|
-
get() {
|
|
323
|
-
return this.longTerm
|
|
324
|
-
},
|
|
325
|
-
set(val) {
|
|
326
|
-
this.handleLongTermChange(val)
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
longTermDisabled() {
|
|
330
|
-
return this.$attrs.disabled === '' || this.$attrs.disabled === true || this.$attrs.disabled === 'disabled'
|
|
331
|
-
},
|
|
332
282
|
valueC: {
|
|
333
283
|
get() {
|
|
334
|
-
if (this.
|
|
335
|
-
if (this.isLongTerm) {
|
|
336
|
-
return this.startDate || null
|
|
337
|
-
}
|
|
284
|
+
if (['daterange', 'monthrange', 'datetimerange'].includes(this.type)) {
|
|
338
285
|
if (this.startDate && this.endDate) {
|
|
339
286
|
return [this.startDate, this.endDate]
|
|
340
287
|
} else {
|
|
@@ -345,11 +292,7 @@ export default {
|
|
|
345
292
|
}
|
|
346
293
|
},
|
|
347
294
|
set(val) {
|
|
348
|
-
if (this.
|
|
349
|
-
if (this.isLongTerm) {
|
|
350
|
-
this.handleLongTermDateChange(val)
|
|
351
|
-
return
|
|
352
|
-
}
|
|
295
|
+
if (['daterange', 'monthrange', 'datetimerange'].includes(this.type)) {
|
|
353
296
|
if (val && val[0]) {
|
|
354
297
|
if (this.type === 'monthrange' && ['yyyy-MM-dd', 'yyyy-MM-dd HH:mm:ss'].includes(this.valueFormat)) {
|
|
355
298
|
let end = new Date(val[1])
|
|
@@ -387,51 +330,6 @@ export default {
|
|
|
387
330
|
}
|
|
388
331
|
},
|
|
389
332
|
methods: {
|
|
390
|
-
handleLongTermChange(val) {
|
|
391
|
-
this.$emit('update:long-term', val)
|
|
392
|
-
|
|
393
|
-
if (val) {
|
|
394
|
-
this.$emit('update:end-date', undefined)
|
|
395
|
-
this.$emit('end', undefined)
|
|
396
|
-
this.$emit('changeLongTerm', {
|
|
397
|
-
longTerm: true,
|
|
398
|
-
startTime: this.startDate || null
|
|
399
|
-
})
|
|
400
|
-
} else {
|
|
401
|
-
this.$emit('update:start-date', null)
|
|
402
|
-
this.$emit('update:end-date', null)
|
|
403
|
-
this.$emit('start', null)
|
|
404
|
-
this.$emit('end', null)
|
|
405
|
-
this.$emit('changeLongTerm', {
|
|
406
|
-
longTerm: false,
|
|
407
|
-
startTime: null
|
|
408
|
-
})
|
|
409
|
-
this.$emit('change', null)
|
|
410
|
-
}
|
|
411
|
-
},
|
|
412
|
-
handleLongTermDateChange(val) {
|
|
413
|
-
if (val) {
|
|
414
|
-
this.$emit('update:start-date', val)
|
|
415
|
-
this.$emit('update:end-date', undefined)
|
|
416
|
-
this.$emit('start', val)
|
|
417
|
-
this.$emit('end', undefined)
|
|
418
|
-
this.$emit('change', [val, undefined])
|
|
419
|
-
this.$emit('changeLongTerm', {
|
|
420
|
-
longTerm: true,
|
|
421
|
-
startTime: val
|
|
422
|
-
})
|
|
423
|
-
} else {
|
|
424
|
-
this.$emit('update:start-date', null)
|
|
425
|
-
this.$emit('update:end-date', undefined)
|
|
426
|
-
this.$emit('start', null)
|
|
427
|
-
this.$emit('end', undefined)
|
|
428
|
-
this.$emit('change', val)
|
|
429
|
-
this.$emit('changeLongTerm', {
|
|
430
|
-
longTerm: true,
|
|
431
|
-
startTime: null
|
|
432
|
-
})
|
|
433
|
-
}
|
|
434
|
-
},
|
|
435
333
|
HandleBlur() {
|
|
436
334
|
let startSh = shortcuts_2.find((s) => s.text.includes($lc('开始')))
|
|
437
335
|
let endSh = shortcuts_2.find((s) => s.text.includes($lc('截止')))
|
|
@@ -451,29 +349,3 @@ export default {
|
|
|
451
349
|
}
|
|
452
350
|
}
|
|
453
351
|
</script>
|
|
454
|
-
|
|
455
|
-
<style scoped>
|
|
456
|
-
.n20-date-picker-por {
|
|
457
|
-
display: inline-block;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
.n20-date-picker-por > .n20-date-editor {
|
|
461
|
-
width: 100%;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
.n20-date-picker-por.has-long-term {
|
|
465
|
-
display: inline-flex;
|
|
466
|
-
align-items: center;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
.n20-date-picker-por.has-long-term > .n20-date-editor {
|
|
470
|
-
flex: 1;
|
|
471
|
-
width: auto;
|
|
472
|
-
min-width: 0;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
.n20-date-picker-por__long-term {
|
|
476
|
-
margin-left: 8px;
|
|
477
|
-
white-space: nowrap;
|
|
478
|
-
}
|
|
479
|
-
</style>
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
:close-on-click-modal="false"
|
|
269
269
|
:destroy-on-open="true"
|
|
270
270
|
>
|
|
271
|
-
<el-select v-model="bathType" class="m-b-s" clearable @change="handleBathChange">
|
|
271
|
+
<el-select v-model="bathType" class="m-b-s w-100p" clearable @change="handleBathChange">
|
|
272
272
|
<el-option
|
|
273
273
|
v-for="item in typeOptions"
|
|
274
274
|
:key="item.type"
|
|
@@ -288,7 +288,7 @@
|
|
|
288
288
|
:multiple="true"
|
|
289
289
|
:show-file-list="true"
|
|
290
290
|
:action="apiPrefix ? apiPrefix + action : action"
|
|
291
|
-
:data="fileData"
|
|
291
|
+
:data="_batchFileData || fileData"
|
|
292
292
|
:headers="headers"
|
|
293
293
|
:accept="fileAccept"
|
|
294
294
|
:size="fileSize"
|
|
@@ -501,7 +501,9 @@ export default {
|
|
|
501
501
|
previewName: undefined,
|
|
502
502
|
previewSameOrg: false,
|
|
503
503
|
seeRow: {},
|
|
504
|
-
officeStatus: false
|
|
504
|
+
officeStatus: false,
|
|
505
|
+
// 批量上传使用的文件数据(避免直接修改计算属性)
|
|
506
|
+
_batchFileData: null
|
|
505
507
|
}
|
|
506
508
|
},
|
|
507
509
|
computed: {
|
|
@@ -745,20 +747,32 @@ export default {
|
|
|
745
747
|
if (bu) return bu(file)
|
|
746
748
|
},
|
|
747
749
|
handleBathChange() {
|
|
748
|
-
|
|
750
|
+
// 创建新的文件数据对象,避免直接修改计算属性
|
|
751
|
+
let fileData = this.fileData || {}
|
|
752
|
+
let dto = JSON.parse(fileData.data || '{}')
|
|
749
753
|
dto[this.keys.type] = this.bathType
|
|
750
|
-
this.
|
|
754
|
+
this._batchFileData = {
|
|
755
|
+
...fileData,
|
|
756
|
+
data: JSON.stringify(dto)
|
|
757
|
+
}
|
|
751
758
|
},
|
|
752
759
|
batchUploadFn() {
|
|
753
760
|
let $uploadwrap = this.$refs['upload-batch']
|
|
754
|
-
|
|
755
|
-
if (fileList.length !== 0 && fileList.every((f) => f.status === 'success')) {
|
|
756
|
-
this.visibleBatch = false
|
|
757
|
-
}
|
|
761
|
+
// 直接提交上传,关闭对话框的逻辑在 batchSuccess 回调中处理
|
|
758
762
|
$uploadwrap.submit()
|
|
759
763
|
},
|
|
760
764
|
batchSuccess(response, file, fileList) {
|
|
761
|
-
|
|
765
|
+
// 创建完整的行对象,初始化状态字段
|
|
766
|
+
let row = {
|
|
767
|
+
id: 'n' + Math.random(),
|
|
768
|
+
[this.keys.name]: '',
|
|
769
|
+
[this.keys.type]: this.bathType,
|
|
770
|
+
[this.keys.time]: '',
|
|
771
|
+
[this.keys.user]: JSON.parse(sessionStorage.getItem('userInfo')).uname,
|
|
772
|
+
_percent: 0,
|
|
773
|
+
_status: undefined,
|
|
774
|
+
_typeDisabled: false
|
|
775
|
+
}
|
|
762
776
|
this.tableData.splice(0, 0, row)
|
|
763
777
|
this.$nextTick(() => {
|
|
764
778
|
this.onSuccessFn(response, file, fileList, row)
|
|
@@ -916,13 +930,8 @@ export default {
|
|
|
916
930
|
let FD = new FormData()
|
|
917
931
|
FD.append(opt.filename, opt.file)
|
|
918
932
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
data = window._fileData
|
|
922
|
-
delete window._fileData
|
|
923
|
-
} else {
|
|
924
|
-
data = opt.data
|
|
925
|
-
}
|
|
933
|
+
// 优先使用 opt.data,其次使用 this.fileData,移除全局变量 window._fileData 的使用
|
|
934
|
+
let data = opt.data || this.fileData
|
|
926
935
|
|
|
927
936
|
if (data) {
|
|
928
937
|
let dto = JSON.parse(data.data)
|
|
@@ -996,7 +1005,7 @@ export default {
|
|
|
996
1005
|
_percent = 99
|
|
997
1006
|
_status = 'error'
|
|
998
1007
|
} else {
|
|
999
|
-
_percent =
|
|
1008
|
+
_percent = 100
|
|
1000
1009
|
_status = 'success'
|
|
1001
1010
|
}
|
|
1002
1011
|
setTimeout(() => {
|
|
@@ -28,142 +28,205 @@ IWSASetTimeOut(6000)
|
|
|
28
28
|
// console.warn(version)
|
|
29
29
|
// })
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* 从 sessionStorage 安全获取用户 DN
|
|
33
|
+
* @returns {string} 用户 DN,获取失败时返回空字符串
|
|
34
|
+
*/
|
|
31
35
|
function getDN() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
try {
|
|
37
|
+
const userInfo = JSON.parse(sessionStorage.getItem('userInfo'))
|
|
38
|
+
return userInfo && userInfo.dn ? userInfo.dn : ''
|
|
39
|
+
} catch (e) {
|
|
40
|
+
return ''
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 获取用户编号
|
|
46
|
+
* @param {string} [uno] - 可选的用户编号
|
|
47
|
+
* @returns {string} 用户编号
|
|
48
|
+
*/
|
|
49
|
+
function getUserNo(uno) {
|
|
50
|
+
return uno || sessionStorage.getItem('userNo')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 根据算法标识获取 RSA 密钥长度
|
|
55
|
+
* @param {string} alg - 算法标识
|
|
56
|
+
* @returns {string} 密钥长度
|
|
57
|
+
*/
|
|
58
|
+
function getRSAKeySize(alg) {
|
|
59
|
+
if (alg === 'RSA_1024') return '1024'
|
|
60
|
+
if (alg === 'RSA_2048') return '2048'
|
|
61
|
+
return '1024'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 构建证书请求 DTO
|
|
66
|
+
* @param {Object} certData - 原始证书数据
|
|
67
|
+
* @param {Array} p10Result - P10 生成结果 [code, container, publicKey]
|
|
68
|
+
* @returns {Object} 证书请求 DTO
|
|
69
|
+
*/
|
|
70
|
+
function buildCertDTO(certData, p10Result) {
|
|
71
|
+
return {
|
|
72
|
+
...certData,
|
|
73
|
+
publicKey: p10Result[2],
|
|
74
|
+
tmpPubKey: p10Result[1] || ''
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 处理证书导入结果提示
|
|
80
|
+
* @param {string} certCode - 证书导入结果码
|
|
81
|
+
* @returns {boolean} 导入是否成功
|
|
82
|
+
*/
|
|
83
|
+
function handleCertImportResult(certCode) {
|
|
84
|
+
if (certCode === '0') {
|
|
85
|
+
Message.success('证书导入成功')
|
|
86
|
+
return true
|
|
87
|
+
} else {
|
|
88
|
+
Message.error('导入证书失败,错误码:' + certCode)
|
|
89
|
+
return false
|
|
36
90
|
}
|
|
37
|
-
return dn
|
|
38
91
|
}
|
|
39
92
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
93
|
+
/**
|
|
94
|
+
* 同步证书到期日到服务端
|
|
95
|
+
* @param {string} dn - 用户DN
|
|
96
|
+
* @param {string} dnExpiryDate - 证书到期日(yyyy-MM-dd)
|
|
97
|
+
*/
|
|
98
|
+
async function syncDnValidDate(dn, dnExpiryDate) {
|
|
99
|
+
if (!dn || !dnExpiryDate) return
|
|
100
|
+
try {
|
|
101
|
+
await axios.post('/bems/prod_1.0/user/wfMasterUser/updateDnValidDate', {
|
|
102
|
+
dn,
|
|
103
|
+
dnValidDate: dnExpiryDate
|
|
45
104
|
})
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('同步证书到期日失败:', error)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* RSA 算法生成容器 P10 并导入签名证书
|
|
112
|
+
* @param {Object} certData - 证书数据
|
|
113
|
+
*/
|
|
114
|
+
async function generateRSACert(certData, dn) {
|
|
115
|
+
// 设置提供者 Microsoft Base Cryptographic Provider v1.0
|
|
116
|
+
IWSA_rsa_csp_setProvider('Microsoft Base Cryptographic Provider v1.0')
|
|
117
|
+
// 设置同步模式
|
|
118
|
+
IWSASetAsyncMode(false)
|
|
119
|
+
|
|
120
|
+
const alg = getRSAKeySize(certData.alg)
|
|
121
|
+
/**
|
|
122
|
+
* (方法 RSA)生成 P10 包,新容器
|
|
123
|
+
* 参数一:签名密钥或加密密钥标识, "true"/"false"
|
|
124
|
+
* 参数二:密钥长度 512,1024,2048,4096
|
|
125
|
+
* 参数三:主题 DN,空值 DN 请赋值""空串
|
|
126
|
+
* 参数四:摘要算法 OID,使用默认值请赋值""空串
|
|
127
|
+
* 参数五:公钥算法 OID,使用默认值请赋值""空串
|
|
128
|
+
* 参数六:签名算法 OID,使用默认值请赋值""空串
|
|
129
|
+
* 参数七:私钥是否可导出, "true"/"false"
|
|
130
|
+
* 参数八:是否启用增强密钥保护, "true"/"false"
|
|
131
|
+
*/
|
|
132
|
+
const res = IWSA_rsa_csp_genContainerP10('true', alg, '', '', '', '', 'false', 'false')
|
|
133
|
+
if (res[0] !== '0') {
|
|
134
|
+
Message.error('产生 P10失败,错误码:' + res[0])
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const dto = buildCertDTO(certData, res)
|
|
139
|
+
const { code, data } = await axios.post('/bems/prod_1.0/dssc/sign/getRadsCert', dto)
|
|
140
|
+
if (code !== 200) return
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* (方法 RSA)导入签名证书 X509
|
|
144
|
+
* 参数一:容器名,支持"":使用产生 P10 时的容器
|
|
145
|
+
* 参数二:X509 证书,Base64 编码
|
|
146
|
+
*/
|
|
147
|
+
const certCode = IWSA_rsa_csp_importSignX509Cert(res[1], data.signCer)
|
|
148
|
+
if (handleCertImportResult(certCode)) {
|
|
149
|
+
// 证书导入成功后同步到期日
|
|
150
|
+
await syncDnValidDate(dn, data.dnExpiryDate)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* SM2 国密算法生成容器 P10 并导入签名证书
|
|
156
|
+
* @param {Object} certData - 证书数据
|
|
157
|
+
*/
|
|
158
|
+
async function generateSM2Cert(certData, dn) {
|
|
159
|
+
// 设置同步模式
|
|
160
|
+
IWSASetAsyncMode(false)
|
|
161
|
+
|
|
162
|
+
const providerList = IWSA_sm2_skf_getProviderList()
|
|
163
|
+
if (providerList.length === 0) {
|
|
164
|
+
Message.error('请检查ukey是否正常')
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
const deviceList = IWSA_sm2_skf_getDeviceList(providerList[0].Provider)
|
|
168
|
+
if (deviceList.length === 0) {
|
|
169
|
+
Message.error('未获取到SM2设备')
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
const applicationList = IWSA_sm2_skf_getApplicationList(providerList[0].Provider, deviceList[0].Device)
|
|
173
|
+
if (applicationList.length === 0) {
|
|
174
|
+
Message.error('未获取到SM2应用')
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
IWSA_sm2_skf_setDevice(providerList[0].Provider, deviceList[0].Device, applicationList[0].Application)
|
|
178
|
+
|
|
179
|
+
let pin
|
|
180
|
+
try {
|
|
181
|
+
const result = await MessageBox.prompt('请输入PIN码', '提示', {
|
|
182
|
+
confirmButtonText: '确定',
|
|
183
|
+
cancelButtonText: '取消',
|
|
184
|
+
closeOnClickModal: false,
|
|
185
|
+
inputType: 'password'
|
|
56
186
|
})
|
|
187
|
+
pin = result.value
|
|
188
|
+
} catch (e) {
|
|
189
|
+
// 用户取消输入
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* (方法 SM2)生成 P10 包,新容器
|
|
195
|
+
* 参数一:主题 DN,空值 DN 请赋值""空串
|
|
196
|
+
*/
|
|
197
|
+
const res = IWSA_sm2_skf_genContainerP10(pin, '', '', 'true')
|
|
198
|
+
if (res[0] !== '0') {
|
|
199
|
+
Message.error('产生 P10失败,错误码:' + res[0])
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const dto = buildCertDTO(certData, res)
|
|
204
|
+
const { code, data } = await axios.post('/bems/prod_1.0/dssc/sign/getRadsCert', dto)
|
|
205
|
+
if (code !== 200) return
|
|
206
|
+
|
|
207
|
+
const certCode = IWSA_sm2_skf_importSignX509Cert(pin, res[1], data.signCer)
|
|
208
|
+
if (handleCertImportResult(certCode)) {
|
|
209
|
+
// 证书导入成功后同步到期日
|
|
210
|
+
await syncDnValidDate(dn, data.dnExpiryDate)
|
|
211
|
+
}
|
|
57
212
|
}
|
|
58
213
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// 设置同步模式
|
|
68
|
-
IWSASetAsyncMode(false)
|
|
69
|
-
let alg = data.alg === 'RSA_1024' ? '1024' : data.alg === 'RSA_2048' ? '2048' : '1024'
|
|
70
|
-
/**
|
|
71
|
-
* (方法 RSA)生成 P10 包,新容器
|
|
72
|
-
* 参数一:签名密钥或加密密钥标识,”true”/”false”
|
|
73
|
-
* 参数二:密钥长度 512,1024, 2048,4096
|
|
74
|
-
* 参数三:主题 DN,空值 DN 请赋值””空串
|
|
75
|
-
* 参数四:摘要算法 OID,使用默认值请赋值””空串
|
|
76
|
-
* 参数五:公钥算法 OID,,使用默认值请赋值””空串
|
|
77
|
-
* 参数六:签名算法 OID,,使用默认值请赋值””空串
|
|
78
|
-
* 参数七:私钥是否可导出,”true”/”false”
|
|
79
|
-
* 参数八:是否启用增强密钥保护,”true”/”false”
|
|
80
|
-
*/
|
|
81
|
-
const res = IWSA_rsa_csp_genContainerP10('true', alg, '', '', '', '', 'false', 'false')
|
|
82
|
-
if (res[0] === '0') {
|
|
83
|
-
let dto = {
|
|
84
|
-
...data,
|
|
85
|
-
publicKey: res[2],
|
|
86
|
-
tmpPubKey: res[1] || ''
|
|
87
|
-
}
|
|
88
|
-
axios.post(`/bems/prod_1.0/dssc/sign/getRadsCert`, dto).then(({ code, data }) => {
|
|
89
|
-
if (code === 200) {
|
|
90
|
-
/**
|
|
91
|
-
* (方法 RSA)导入签名证书 X509
|
|
92
|
-
* 参数一:容器名,支持””:使用产生 P10 时的容器
|
|
93
|
-
* 参数二:X509 证书,Base64 编码
|
|
94
|
-
*/
|
|
214
|
+
/**
|
|
215
|
+
* 海港版本获取并导入用户证书
|
|
216
|
+
* @param {string} uno - 用户编号
|
|
217
|
+
*/
|
|
218
|
+
async function getUserCert(uno) {
|
|
219
|
+
const userNo = getUserNo(uno)
|
|
220
|
+
const { code, data } = await axios.post(`/bems/prod_1.0/dssc/sign/updateCert_direct/${userNo}`)
|
|
221
|
+
if (code !== 200) return
|
|
95
222
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
})
|
|
104
|
-
} else {
|
|
105
|
-
Message.error('产生 P10失败,错误码::' + data[0])
|
|
106
|
-
}
|
|
107
|
-
// 国密
|
|
108
|
-
} else {
|
|
109
|
-
/**
|
|
110
|
-
* (方法 SM2)生成 P10 包,新容器
|
|
111
|
-
* 参数y一:主题 DN,空值 DN 请赋值””空串
|
|
112
|
-
*/
|
|
113
|
-
// 设置同步模式
|
|
114
|
-
IWSASetAsyncMode(false)
|
|
115
|
-
const roviderList = IWSA_sm2_skf_getProviderList()
|
|
116
|
-
console.log(roviderList)
|
|
117
|
-
if (roviderList.length === 0) {
|
|
118
|
-
Message.error('请检查ukey是否正常')
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
const providerList = IWSA_sm2_skf_getDeviceList(roviderList[0].Provider)
|
|
122
|
-
if (providerList.length === 0) {
|
|
123
|
-
Message.error('未获取到SM2设备')
|
|
124
|
-
return
|
|
125
|
-
}
|
|
126
|
-
const applicationList = IWSA_sm2_skf_getApplicationList(roviderList[0].Provider, providerList[0].Device)
|
|
127
|
-
if (applicationList.length === 0) {
|
|
128
|
-
Message.error('未获取到SM2应用')
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
IWSA_sm2_skf_setDevice(roviderList[0].Provider, providerList[0].Device, applicationList[0].Application)
|
|
132
|
-
await MessageBox.prompt('请输入PIN码', '提示', {
|
|
133
|
-
confirmButtonText: '确定',
|
|
134
|
-
cancelButtonText: '取消',
|
|
135
|
-
closeOnClickModal: false,
|
|
136
|
-
inputType: 'password'
|
|
137
|
-
}).then(({ value }) => {
|
|
138
|
-
const res = IWSA_sm2_skf_genContainerP10(value, '', '', 'true')
|
|
139
|
-
if (res[0] === '0') {
|
|
140
|
-
let dto = {
|
|
141
|
-
...data,
|
|
142
|
-
publicKey: res[2],
|
|
143
|
-
tmpPubKey: res[1] || ''
|
|
144
|
-
}
|
|
145
|
-
axios.post(`/bems/prod_1.0/dssc/sign/getRadsCert`, dto).then(({ code, data }) => {
|
|
146
|
-
if (code === 200) {
|
|
147
|
-
/**
|
|
148
|
-
* (方法 RSA)导入签名证书 X509
|
|
149
|
-
* 参数一:容器名,支持””:使用产生 P10 时的容器
|
|
150
|
-
* 参数二:X509 证书,Base64 编码
|
|
151
|
-
*/
|
|
152
|
-
const certData = IWSA_sm2_skf_importSignX509Cert(value, res[1], data.signCer)
|
|
153
|
-
if (certData[0] === '0') {
|
|
154
|
-
Message.success('证书导入成功')
|
|
155
|
-
} else {
|
|
156
|
-
Message.error('导入证书失败,错误码::' + certData[0])
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
} else {
|
|
161
|
-
Message.error('产生 P10失败,错误码::' + data[0])
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
})
|
|
223
|
+
const dn = getDN()
|
|
224
|
+
// 非国密走 RSA,国密走 SM2
|
|
225
|
+
if (data.alg !== 'SM2') {
|
|
226
|
+
await generateRSACert(data, dn)
|
|
227
|
+
} else {
|
|
228
|
+
await generateSM2Cert(data, dn)
|
|
229
|
+
}
|
|
167
230
|
}
|
|
168
231
|
|
|
169
232
|
/**
|
|
@@ -234,26 +297,25 @@ export function updateCert(cspName, onSuccess, dnInfo) {
|
|
|
234
297
|
Message.error('容器生成失败,请联系管理员,错误码为' + res[0])
|
|
235
298
|
}
|
|
236
299
|
}
|
|
237
|
-
function GetDateNotAfter(res, dn) {
|
|
238
|
-
if (res[0] === '0') {
|
|
239
|
-
getDnCertBase64(dn, res)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
300
|
/**
|
|
244
301
|
* 海港版本证书自动更新
|
|
245
|
-
* @param {
|
|
246
|
-
* @returns
|
|
302
|
+
* @param {string} uno - 用户编号
|
|
303
|
+
* @returns {Promise<void>}
|
|
247
304
|
*/
|
|
248
305
|
export function updateCertHG(uno) {
|
|
249
|
-
getUserCert(uno)
|
|
306
|
+
return getUserCert(uno).catch((error) => {
|
|
307
|
+
console.error('海港证书更新失败:', error)
|
|
308
|
+
})
|
|
250
309
|
}
|
|
251
310
|
|
|
311
|
+
/**
|
|
312
|
+
* 比较 DN 是否匹配(单向包含匹配)
|
|
313
|
+
* @param {string} dn1 - 证书 DN
|
|
314
|
+
* @param {string} dn2 - 目标 DN
|
|
315
|
+
* @returns {boolean}
|
|
316
|
+
*/
|
|
252
317
|
function compareDN(dn1, dn2) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
return true
|
|
257
|
-
}
|
|
258
|
-
return false
|
|
318
|
+
const dn1Arr = dn1.split(',').map((c) => c.trim())
|
|
319
|
+
const dn2Arr = dn2.split(',').map((c) => c.trim())
|
|
320
|
+
return dn1Arr.every((dnAttr) => dn2Arr.includes(dnAttr))
|
|
259
321
|
}
|
|
@@ -95,7 +95,7 @@ export function getCert(dn) {
|
|
|
95
95
|
let signType = window.sessionStorage.getItem('signType')
|
|
96
96
|
console.log('signType', signType)
|
|
97
97
|
return new Promise((resolve, reject) => {
|
|
98
|
-
if (signType === 'inetSign' /* 信安CA */) {
|
|
98
|
+
if (signType === 'inetSign' || signType === 'signV3' /* 信安CA */) {
|
|
99
99
|
// 是否使用信安3.0版本sdk (默认使用2.0版本)
|
|
100
100
|
if (window.NetSignVersion === 'signV3') {
|
|
101
101
|
importG('inetSign', () => import(/*webpackChunkName: "inetSign"*/ './signV3/sign.js')).then(
|