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,6 +1,6 @@
1
1
  {
2
2
  "name": "n20-common-lib",
3
- "version": "2.22.44",
3
+ "version": "2.22.46",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
@@ -1,16 +1,29 @@
1
1
  <template>
2
- <el-date-picker
3
- ref="date-picker"
4
- class="n20-date-editor"
5
- :class="{ 'has-value': clearable && value }"
6
- v-bind="$attrs"
7
- :value="value"
8
- :clearable="clearable"
9
- v-on="$listeners"
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
- <div class="n20-date-picker-por" :class="{ 'has-long-term': showLongTermCheckbox }">
3
- <el-date-picker
4
- ref="date-picker"
5
- v-model="valueC"
6
- class="n20-date-editor"
7
- :class="{
8
- 'has-value': clearable && valueC,
9
- [this.$attrs && this.$attrs['rule-form']]: !valueC
10
- }"
11
- :popper-class="
12
- !clearable && pickerType === 'datetimerange'
13
- ? 'clearable-datetimerange' + ' ' + $attrs['popper-class']
14
- : $attrs['popper-class']
15
- "
16
- :type="pickerType"
17
- :value-format="valueFormat"
18
- :placeholder="'选择日期' | $lc"
19
- :start-placeholder="'开始日期' | $lc"
20
- :end-placeholder="'结束日期' | $lc"
21
- :picker-options="pickerOptionsAs"
22
- :clearable="clearable"
23
- v-bind="$attrs"
24
- v-on="listeners"
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.isRangeType) {
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.isRangeType) {
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
- let dto = JSON.parse(this.dataPorp.fileData.data)
750
+ // 创建新的文件数据对象,避免直接修改计算属性
751
+ let fileData = this.fileData || {}
752
+ let dto = JSON.parse(fileData.data || '{}')
749
753
  dto[this.keys.type] = this.bathType
750
- this.fileData.data = JSON.stringify(dto)
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
- let fileList = $uploadwrap.fileList
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
- let row = { ...this.dataPorp.keys }
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
- let data
920
- if (window._fileData) {
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 = 99
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
- let dn = ''
33
- let userInfo = JSON.parse(sessionStorage.getItem('userInfo'))
34
- if (userInfo && userInfo.dn) {
35
- dn = userInfo.dn
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
- function getDnCertBase64(dn, res) {
41
- axios
42
- .post(`/bems/prod_1.0/dssc/sign/getDnCertBase64`, {
43
- userDn: dn,
44
- p10: res[2]
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
- .then(({ data }) => {
47
- if (data) {
48
- let list = JSON.parse(data)
49
- if (list[0]?.errNum === '0') {
50
- let code = IWSA_rsa_csp_importSignP7Cert(res[1], list[0]?.cert)
51
- if (code === '0') {
52
- return Message.success('证书导入成功')
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
- function getUserCert(uno) {
60
- uno = uno || sessionStorage.getItem('userNo')
61
- axios.post(`/bems/prod_1.0/dssc/sign/updateCert_direct/${uno}`).then(async ({ code, data }) => {
62
- if (code === 200) {
63
- // 非国密
64
- if (data.alg !== 'SM2') {
65
- // 设置提供者 Microsoft Base Cryptographic Provider v1.0
66
- IWSA_rsa_csp_setProvider('Microsoft Base Cryptographic Provider v1.0')
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
- const certData = IWSA_rsa_csp_importSignX509Cert(res[1], data.signCer)
97
- if (certData[0] === '0') {
98
- Message.success('证书导入成功')
99
- } else {
100
- Message.error('导入证书失败,错误码::' + certData[0])
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 {*} cspName
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
- let dn1Arr = dn1.split(',').map((c) => c.trim())
254
- let dn2Arr = dn2.split(',').map((c) => c.trim())
255
- if (dn1Arr.every((dnAttr) => dn2Arr.includes(dnAttr))) {
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(