n20-common-lib 3.3.28 → 3.3.30
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 +2 -1
- package/src/components/TablePro/index.js +3 -0
- package/src/components/TablePro/index.vue +5 -0
- package/src/components/v3/TablePro/index.js +4 -1
- package/src/components/v3/TablePro/index.vue +5 -0
- package/src/i18n.json +8 -0
- package/src/plugins/Sign/dn.js +30 -0
- package/src/plugins/Sign/sign.js +17 -18
- package/src/plugins/Sign/signV3/sign.js +35 -3
- package/src/utils/popupZIndex.js +42 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n20-common-lib",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.30",
|
|
4
4
|
"private": false,
|
|
5
5
|
"scripts": {
|
|
6
6
|
"serve": "vue-cli-service serve",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"axios": "*",
|
|
55
55
|
"dayjs": "*",
|
|
56
56
|
"decimal.js": "^10.5.0",
|
|
57
|
+
"dom-zindex": "^1.0.6",
|
|
57
58
|
"js-cookie": "^3.0.1",
|
|
58
59
|
"jsencrypt": "^3.3.2",
|
|
59
60
|
"jsonwebtoken": "^8.5.1",
|
|
@@ -6,6 +6,7 @@ import dayjs from 'dayjs'
|
|
|
6
6
|
import XEUtils from 'xe-utils'
|
|
7
7
|
import { $lc } from '../../utils/i18n/index.js'
|
|
8
8
|
import zhCN from 'vxe-table/lib/locale/lang/zh-CN'
|
|
9
|
+
import installPopupZIndexBridge from '../../utils/popupZIndex'
|
|
9
10
|
// 打平对象
|
|
10
11
|
function flattenObject(obj, prefix = '', result = {}) {
|
|
11
12
|
// 遍历对象的每个属性
|
|
@@ -158,6 +159,8 @@ vxeTable.formats.mixin({
|
|
|
158
159
|
}
|
|
159
160
|
}) */
|
|
160
161
|
function install(Vue) {
|
|
162
|
+
// 原生 vxe-table 与 TablePro 使用同一套弹层层级。
|
|
163
|
+
installPopupZIndexBridge()
|
|
161
164
|
Vue.use(vxeTable)
|
|
162
165
|
}
|
|
163
166
|
|
|
@@ -138,6 +138,7 @@ import tableSetSize from '../TableSetSize/index.vue'
|
|
|
138
138
|
import { $lc } from '../../utils/i18n/index.js'
|
|
139
139
|
import XEUtils from 'xe-utils'
|
|
140
140
|
import { isTableCellInteractiveTarget } from './cellClick'
|
|
141
|
+
import installPopupZIndexBridge from '../../utils/popupZIndex'
|
|
141
142
|
const DEFAULT_SCROLL_Y = {
|
|
142
143
|
enabled: true,
|
|
143
144
|
gt: 30,
|
|
@@ -161,6 +162,10 @@ const renderer = {
|
|
|
161
162
|
}
|
|
162
163
|
export default {
|
|
163
164
|
name: 'TablePro',
|
|
165
|
+
beforeCreate() {
|
|
166
|
+
// 按需引用组件时,也要在子表格创建 tooltip 前完成层级桥接。
|
|
167
|
+
installPopupZIndexBridge()
|
|
168
|
+
},
|
|
164
169
|
components: {
|
|
165
170
|
tableSetSize,
|
|
166
171
|
empty,
|
|
@@ -3,8 +3,9 @@ import 'vxe-table/lib/style.css'
|
|
|
3
3
|
import filterContent from './filterContent.vue'
|
|
4
4
|
import numerify from 'numerify'
|
|
5
5
|
import dayjs from 'dayjs'
|
|
6
|
-
import { $lc } from '
|
|
6
|
+
import { $lc } from '../../../utils/i18n/index.js'
|
|
7
7
|
import zhCN from 'vxe-table/lib/locale/lang/zh-CN'
|
|
8
|
+
import installPopupZIndexBridge from '../../../utils/popupZIndex'
|
|
8
9
|
// 打平对象
|
|
9
10
|
function flattenObject(obj, prefix = '', result = {}) {
|
|
10
11
|
// 遍历对象的每个属性
|
|
@@ -123,6 +124,8 @@ vxeTable.formats.mixin({
|
|
|
123
124
|
})
|
|
124
125
|
|
|
125
126
|
function install(Vue) {
|
|
127
|
+
// v3 独立安装时也复用公共层级桥接。
|
|
128
|
+
installPopupZIndexBridge()
|
|
126
129
|
Vue.use(vxeTable)
|
|
127
130
|
}
|
|
128
131
|
|
|
@@ -454,6 +454,7 @@ import { saveTransform } from '../../ShowColumn/index.vue'
|
|
|
454
454
|
import tableOperate from '../../TableOperate/index.vue'
|
|
455
455
|
import { isTableCellInteractiveTarget } from '../../TablePro/cellClick'
|
|
456
456
|
import OperateBtns from '../../TableProOperateColumn/OperateBtns.vue'
|
|
457
|
+
import installPopupZIndexBridge from '../../../utils/popupZIndex'
|
|
457
458
|
|
|
458
459
|
const DEFAULT_OPERATE_COLUMN_WIDTH = 180
|
|
459
460
|
|
|
@@ -473,6 +474,10 @@ const renderer = {
|
|
|
473
474
|
}
|
|
474
475
|
export default {
|
|
475
476
|
name: 'TableProV3',
|
|
477
|
+
beforeCreate() {
|
|
478
|
+
// 按需引用 v3 组件时,也在子表格创建 tooltip 前完成公共桥接。
|
|
479
|
+
installPopupZIndexBridge()
|
|
480
|
+
},
|
|
476
481
|
components: {
|
|
477
482
|
tableOperate,
|
|
478
483
|
tableShowColumn,
|
package/src/i18n.json
CHANGED
|
@@ -6167,6 +6167,14 @@
|
|
|
6167
6167
|
"zh-hk": "憑證過期",
|
|
6168
6168
|
"es": "Certificado caducado"
|
|
6169
6169
|
},
|
|
6170
|
+
"证书已过期": {
|
|
6171
|
+
"en": "Certificate expired",
|
|
6172
|
+
"th": "ใบรับรองหมดอายุ",
|
|
6173
|
+
"vi": "Chứng chỉ đã hết hạn",
|
|
6174
|
+
"ja": "証明書の有効期限が切れました",
|
|
6175
|
+
"zh-hk": "憑證已過期",
|
|
6176
|
+
"es": "Certificado caducado"
|
|
6177
|
+
},
|
|
6170
6178
|
"证书已废止": {
|
|
6171
6179
|
"en": "Certificate has been revoked",
|
|
6172
6180
|
"th": "ใบรับรองถูกเพิกถอนแล้ว",
|
package/src/plugins/Sign/dn.js
CHANGED
|
@@ -55,3 +55,33 @@ export function isDnMatched(certDn, userDn) {
|
|
|
55
55
|
const userCn = getCn(userAttrs)
|
|
56
56
|
return certCn && userCn && certCn === userCn
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 返回匹配 DN 的证书及到期时间,保留 SDK 原始索引用于后续签名。
|
|
61
|
+
*/
|
|
62
|
+
export function getMatchedCerts(dnList, dn) {
|
|
63
|
+
return dnList
|
|
64
|
+
.map((cert, index) => ({ cert, index }))
|
|
65
|
+
.filter(({ cert }) => isDnMatched(cert.certDN, dn))
|
|
66
|
+
.map(item => ({
|
|
67
|
+
...item,
|
|
68
|
+
// NSGetCertsListInfo 的 SDK 已解码 validEnd,补齐 GMT 前的空格后解析。
|
|
69
|
+
validEndTime: new Date(item.cert.validEnd?.replace(/GMT$/, ' GMT')).getTime()
|
|
70
|
+
}))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 业务条件筛选完成后过滤过期证书,再按到期时间倒序排列副本。
|
|
75
|
+
*/
|
|
76
|
+
export function getValidCerts(matchedCerts) {
|
|
77
|
+
const now = Date.now()
|
|
78
|
+
return matchedCerts
|
|
79
|
+
// 只剔除明确过期的证书,保留原先对缺失或无效日期的兼容行为。
|
|
80
|
+
.filter(({ validEndTime }) => !(validEndTime <= now))
|
|
81
|
+
.sort((a, b) => {
|
|
82
|
+
// 缺失或无法解析的日期放到最后,同一有效期保持原始顺序。
|
|
83
|
+
const aTime = Number.isNaN(a.validEndTime) ? -Infinity : a.validEndTime
|
|
84
|
+
const bTime = Number.isNaN(b.validEndTime) ? -Infinity : b.validEndTime
|
|
85
|
+
return bTime - aTime || a.index - b.index
|
|
86
|
+
})
|
|
87
|
+
}
|
package/src/plugins/Sign/sign.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Message, Notification } from 'element-ui'
|
|
|
3
3
|
import { $lc } from '../../utils/i18n/index.js'
|
|
4
4
|
|
|
5
5
|
import { IWSAgent } from './InfosecNetSignCNGAgent.min.js'
|
|
6
|
-
import {
|
|
6
|
+
import { getMatchedCerts, getValidCerts, isCertCheckFailed, parseCA } from './dn.js'
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
IWSASetTimeOut,
|
|
@@ -152,30 +152,29 @@ export async function performSign(plain, index) {
|
|
|
152
152
|
})
|
|
153
153
|
})
|
|
154
154
|
}
|
|
155
|
-
/**
|
|
156
|
-
* 从Dn中获取CN
|
|
157
|
-
* @param {string} dn 要解析的Dn
|
|
158
|
-
* @returns {string} 解析后的CN
|
|
159
|
-
*/
|
|
160
155
|
/**
|
|
161
156
|
* 验证Dn是否存在于Dn列表中
|
|
162
157
|
* @param {Array} dnList 获取到的Dn列表
|
|
163
158
|
* @param {string} dn 要验证的Dn
|
|
164
|
-
* @returns {number} -
|
|
159
|
+
* @returns {number} - 返回可用证书的原始索引;未匹配或全部过期时返回 -1
|
|
165
160
|
*/
|
|
166
161
|
function verifyDn(dnList, dn) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
if (index === -1) {
|
|
175
|
-
let dnList = dnList?.map((res) => res.certDN)?.join(',')
|
|
176
|
-
Message.error(`${$lc('证书Dn不匹配:')}${dnList}${$lc('里面无法匹配===>')}${dn}`)
|
|
177
|
-
return index
|
|
162
|
+
const matchedCerts = getMatchedCerts(dnList, dn)
|
|
163
|
+
if (matchedCerts.length === 0) {
|
|
164
|
+
const certDns = dnList.map((res) => res.certDN).join(',')
|
|
165
|
+
Message.error(`${$lc('证书Dn不匹配:')}${certDns}${$lc('里面无法匹配===>')}${dn}`)
|
|
166
|
+
return -1
|
|
178
167
|
}
|
|
168
|
+
|
|
169
|
+
// 保留 DN 匹配条件,剔除过期证书后选择 validEnd 最晚的一张。
|
|
170
|
+
const validCerts = getValidCerts(matchedCerts)
|
|
171
|
+
if (validCerts.length === 0) {
|
|
172
|
+
Message.error($lc('证书已过期'))
|
|
173
|
+
return -1
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 使用原始列表索引签名,避免排序后指向其他证书。
|
|
177
|
+
const index = validCerts[0].index
|
|
179
178
|
if (index !== -1) {
|
|
180
179
|
// GMT时间字符串
|
|
181
180
|
const gmtTimeString = dnList[index].validEnd?.replace(/GMT$/, ' GMT')
|
|
@@ -3,7 +3,7 @@ import { Message, MessageBox, Notification } from 'element-ui'
|
|
|
3
3
|
import { $lc } from '../../../utils/i18n/index.js'
|
|
4
4
|
|
|
5
5
|
import { IWSAgent } from './InfosecNetSignCNGAgent.min.js'
|
|
6
|
-
import { isCertCheckFailed, isDnMatched } from '../dn.js'
|
|
6
|
+
import { getMatchedCerts, getValidCerts, isCertCheckFailed, isDnMatched } from '../dn.js'
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
IWSASetTimeOut,
|
|
@@ -153,7 +153,8 @@ export function getCertInfo(dn) {
|
|
|
153
153
|
return
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
// 仅 NSGetCertsListInfo 的证书数据执行有效期过滤及排序。
|
|
157
|
+
certInfo = verifyCertsList(dnList, dn)
|
|
157
158
|
resolve(certInfo)
|
|
158
159
|
})
|
|
159
160
|
})
|
|
@@ -239,7 +240,38 @@ async function performSignSkf(plainText, value) {
|
|
|
239
240
|
* 验证Dn是否存在于Dn列表中
|
|
240
241
|
* @param {Array} dnList 获取到的Dn列表
|
|
241
242
|
* @param {string} dn 要验证的Dn
|
|
242
|
-
* @returns {number} -
|
|
243
|
+
* @returns {number} - 返回可用证书的原始索引;未匹配或全部过期时返回 -1
|
|
244
|
+
*/
|
|
245
|
+
function verifyCertsList(dnList, dn) {
|
|
246
|
+
// 保留原有 DN、类型和用途条件,过期过滤后仍优先使用 SM2 签名证书。
|
|
247
|
+
const matchedCerts = getMatchedCerts(dnList, dn).filter(
|
|
248
|
+
({ cert }) => (cert.CertType === 'SM2' && cert.KeyUsage === 'signature') || cert.CertType === 'RSA'
|
|
249
|
+
)
|
|
250
|
+
if (matchedCerts.length === 0) {
|
|
251
|
+
let dnListB = dnList?.map((res) => res.certDN)?.join(',')
|
|
252
|
+
Message.error(`${$lc('证书Dn不匹配:')}${dnListB}${$lc('里面无法匹配===>')}${dn}`)
|
|
253
|
+
return -1
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 所有符合条件的证书均过期时阻止后续签名。
|
|
257
|
+
const validCerts = getValidCerts(matchedCerts)
|
|
258
|
+
if (validCerts.length === 0) {
|
|
259
|
+
Message.error($lc('证书已过期'))
|
|
260
|
+
return -1
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// 列表已按到期时间倒序;优先取有效 SM2,SM2 均过期或不存在时再取 RSA。
|
|
264
|
+
const selectedCert = validCerts.find(({ cert }) => cert.CertType === 'SM2') || validCerts[0]
|
|
265
|
+
// 同步选中证书的原始索引、DN 和算法,避免排序后签名使用其他证书。
|
|
266
|
+
const { cert, index } = selectedCert
|
|
267
|
+
certIndex = index
|
|
268
|
+
certDN = cert.certDN
|
|
269
|
+
certType = cert.CertType === 'SM2' ? 'SM3' : 'SHA1'
|
|
270
|
+
return index
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* SKF 接口保留原有选证流程,其数据不参与 NSGetCertsListInfo 的有效期处理。
|
|
243
275
|
*/
|
|
244
276
|
function verifyDn(dnList, dn) {
|
|
245
277
|
let index = -1
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Vue from 'vue'
|
|
2
|
+
import DomZIndex from 'dom-zindex'
|
|
3
|
+
import PopupManager from 'element-ui/lib/utils/popup/popup-manager'
|
|
4
|
+
import SourcePopupManager from 'element-ui/src/utils/popup/popup-manager'
|
|
5
|
+
|
|
6
|
+
const BRIDGE_FLAG = '__n20PopupZIndexBridge__'
|
|
7
|
+
|
|
8
|
+
function bridgePopupManager(manager) {
|
|
9
|
+
if (manager[BRIDGE_FLAG]) return
|
|
10
|
+
|
|
11
|
+
const descriptor = Object.getOwnPropertyDescriptor(manager, 'zIndex')
|
|
12
|
+
|
|
13
|
+
// Element 保存下一次可用的层级,dom-zindex 保存最后一次已分配的层级。
|
|
14
|
+
DomZIndex.setCurrent(Math.max(DomZIndex.getCurrent(), manager.zIndex - 1))
|
|
15
|
+
Object.defineProperty(manager, 'zIndex', {
|
|
16
|
+
configurable: true,
|
|
17
|
+
get() {
|
|
18
|
+
// 兼容先安装表格、后安装 Element 的顺序,保留业务配置的初始层级。
|
|
19
|
+
const configuredZIndex = Number((Vue.prototype.$ELEMENT || {}).zIndex) || 2000
|
|
20
|
+
return Math.max(descriptor.get.call(manager), DomZIndex.getCurrent() + 1, configuredZIndex)
|
|
21
|
+
},
|
|
22
|
+
set(value) {
|
|
23
|
+
const nextZIndex = Number(value)
|
|
24
|
+
if (!Number.isFinite(nextZIndex)) return
|
|
25
|
+
|
|
26
|
+
// 两套组件共用递增水位,避免打开嵌套弹窗或设置较小层级时发生回退。
|
|
27
|
+
const currentZIndex = Math.max(DomZIndex.getCurrent(), nextZIndex - 1)
|
|
28
|
+
DomZIndex.setCurrent(currentZIndex)
|
|
29
|
+
descriptor.set.call(manager, currentZIndex + 1)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
Object.defineProperty(manager, BRIDGE_FLAG, { value: true })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 统一 Element 弹层与 vxe tooltip 的层级,重复安装 v2/v3 时只桥接一次。 */
|
|
36
|
+
export default function installPopupZIndexBridge() {
|
|
37
|
+
if (typeof document === 'undefined') return
|
|
38
|
+
|
|
39
|
+
bridgePopupManager(PopupManager)
|
|
40
|
+
// 组件库的 loading 等指令仍引用 Element 源码入口,需要同步这份管理器。
|
|
41
|
+
bridgePopupManager(SourcePopupManager)
|
|
42
|
+
}
|