@authme/identity-verification 2.8.15 → 2.8.17
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/assets/locale/zh_Hant_TW.json +3 -3
- package/assets/styles/style.css +15 -1
- package/index.cjs +161 -14
- package/index.js +162 -15
- package/package.json +6 -6
package/index.cjs
CHANGED
|
@@ -33,6 +33,8 @@ require('core-js/modules/es.typed-array.set.js');
|
|
|
33
33
|
require('core-js/modules/es.typed-array.sort.js');
|
|
34
34
|
require('core-js/modules/es.typed-array.to-locale-string.js');
|
|
35
35
|
require('core-js/modules/es.string.pad-start.js');
|
|
36
|
+
require('core-js/modules/es.string.match.js');
|
|
37
|
+
require('core-js/modules/es.string.starts-with.js');
|
|
36
38
|
require('core-js/modules/es.regexp.constructor.js');
|
|
37
39
|
require('core-js/modules/es.typed-array.uint8-array.js');
|
|
38
40
|
|
|
@@ -28132,7 +28134,12 @@ const popupView = arg => {
|
|
|
28132
28134
|
domPopupViewContainer.style.borderRadius = `${uiThemeConfig.popupView.cornerRadius}px`;
|
|
28133
28135
|
util.uiThemeText(domTitle, uiThemeConfig.titleOne);
|
|
28134
28136
|
util.uiThemeText(domContent, uiThemeConfig.bodyTwo);
|
|
28135
|
-
|
|
28137
|
+
console.log('deviceType', uiThemeConfig.deviceType);
|
|
28138
|
+
if (uiThemeConfig.deviceType === 'mobile') {
|
|
28139
|
+
util.uiThemeSmallButton(domConfirm, uiThemeConfig.smallermMajorButton);
|
|
28140
|
+
} else {
|
|
28141
|
+
util.uiThemeButton(domConfirm, uiThemeConfig.majorButton);
|
|
28142
|
+
}
|
|
28136
28143
|
if (arg.cancel) {
|
|
28137
28144
|
util.uiThemeSmallButton(domCancel, uiThemeConfig.smallerMinorButton);
|
|
28138
28145
|
domCancel.innerHTML = arg.cancel;
|
|
@@ -30638,7 +30645,8 @@ const ocrResultModal = arg => {
|
|
|
30638
30645
|
name,
|
|
30639
30646
|
label,
|
|
30640
30647
|
value,
|
|
30641
|
-
placeHolder
|
|
30648
|
+
placeHolder,
|
|
30649
|
+
attribute
|
|
30642
30650
|
}) {
|
|
30643
30651
|
const domGroupItem = document.createElement('div');
|
|
30644
30652
|
domGroupItem.classList.add('video-container__ocrResultModal-group-item');
|
|
@@ -30655,6 +30663,11 @@ const ocrResultModal = arg => {
|
|
|
30655
30663
|
domInput.value = value;
|
|
30656
30664
|
domError.innerText = `${label}格式不符`;
|
|
30657
30665
|
domInput.placeholder = placeHolder;
|
|
30666
|
+
if (attribute) {
|
|
30667
|
+
Object.keys(attribute).forEach(key => {
|
|
30668
|
+
domInput.setAttribute(key, attribute[key]);
|
|
30669
|
+
});
|
|
30670
|
+
}
|
|
30658
30671
|
domInput.addEventListener('input', () => {
|
|
30659
30672
|
validateFields() ? btnConfirmStatus(false) : btnConfirmStatus(true);
|
|
30660
30673
|
// btnConfirmStatus(Object.values(validateMap).some((i: any) => i.validate === false));
|
|
@@ -30728,6 +30741,15 @@ const ocrResultModal = arg => {
|
|
|
30728
30741
|
return domGroupItem;
|
|
30729
30742
|
}
|
|
30730
30743
|
function formatDate(dateString, format) {
|
|
30744
|
+
// 檢查是否為民國年格式
|
|
30745
|
+
if (dateString.match(/^\d{3}\/\d{2}\/\d{2}$/)) {
|
|
30746
|
+
// 將民國年轉換為西元年
|
|
30747
|
+
const parts = dateString.split('/');
|
|
30748
|
+
const _year = parseInt(parts[0], 10) + 1911; // 民國年轉西元年
|
|
30749
|
+
const _month = parts[1].padStart(2, '0'); // 補 0 的月份
|
|
30750
|
+
const _day = parts[2].padStart(2, '0'); // 補 0 的日期
|
|
30751
|
+
dateString = `${_year}-${_month}-${_day}`;
|
|
30752
|
+
}
|
|
30731
30753
|
// 確保日期格式為 "YYYY-MM-DD",避免瀏覽器解析錯誤
|
|
30732
30754
|
const normalizedDateString = dateString.replace(/\//g, '-');
|
|
30733
30755
|
// 解析日期字串
|
|
@@ -30736,19 +30758,105 @@ const ocrResultModal = arg => {
|
|
|
30736
30758
|
throw new Error('Invalid date format');
|
|
30737
30759
|
}
|
|
30738
30760
|
// 取得年月日
|
|
30739
|
-
|
|
30761
|
+
let year = date.getFullYear().toString(); // 取得年份
|
|
30740
30762
|
const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 補 0 的月份
|
|
30741
30763
|
const day = date.getDate().toString().padStart(2, '0'); // 補 0 的日期
|
|
30764
|
+
// 依照格式轉換成民國年
|
|
30765
|
+
if (format === 'yyy/MM/dd') {
|
|
30766
|
+
year = (parseInt(year) - 1911).toString(); // 民國年
|
|
30767
|
+
if (year.length === 2) {
|
|
30768
|
+
year = '0' + year; // 補 0 的民國年
|
|
30769
|
+
}
|
|
30770
|
+
}
|
|
30742
30771
|
// 替換格式
|
|
30743
|
-
return format.replace(/YYYY|yyyy/g, year) // 年份 (YYYY 或 yyyy)
|
|
30772
|
+
return format.replace(/YYYY|yyyy|YYY|yyy/g, year) // 年份 (YYYY 或 yyyy)
|
|
30744
30773
|
.replace(/MM|mm/g, month) // 月份 (MM)
|
|
30745
30774
|
.replace(/dd/g, day); // 日期 (dd)
|
|
30746
30775
|
}
|
|
30747
|
-
|
|
30748
|
-
function isValidDateFormat(
|
|
30749
|
-
|
|
30776
|
+
// 驗證日期格式
|
|
30777
|
+
function isValidDateFormat(input, format) {
|
|
30778
|
+
let dateStr = input.value;
|
|
30779
|
+
if (!isNaN(Number(dateStr))) {
|
|
30780
|
+
let year = '';
|
|
30781
|
+
let month = '';
|
|
30782
|
+
let day = '';
|
|
30783
|
+
if (format === 'yyy/MM/dd') {
|
|
30784
|
+
if (dateStr.length === 7) {
|
|
30785
|
+
// 民國年格式
|
|
30786
|
+
year = dateStr.slice(0, 3);
|
|
30787
|
+
month = dateStr.slice(3, 5);
|
|
30788
|
+
day = dateStr.slice(5, 7);
|
|
30789
|
+
dateStr = `${year}/${month}/${day}`;
|
|
30790
|
+
}
|
|
30791
|
+
} else {
|
|
30792
|
+
if (dateStr.length === 8) {
|
|
30793
|
+
// 西元年格式
|
|
30794
|
+
year = dateStr.slice(0, 4);
|
|
30795
|
+
month = dateStr.slice(4, 6);
|
|
30796
|
+
day = dateStr.slice(6, 8);
|
|
30797
|
+
dateStr = `${year}/${month}/${day}`;
|
|
30798
|
+
}
|
|
30799
|
+
}
|
|
30800
|
+
}
|
|
30801
|
+
input.value = dateStr;
|
|
30802
|
+
let regex = /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/;
|
|
30803
|
+
if (format === 'yyy/MM/dd') {
|
|
30804
|
+
regex = /^\d{3}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/;
|
|
30805
|
+
}
|
|
30750
30806
|
return regex.test(dateStr);
|
|
30751
30807
|
}
|
|
30808
|
+
function isValidDate(dateStr, format) {
|
|
30809
|
+
if (format === 'yyy/MM/dd') {
|
|
30810
|
+
// 民國年格式轉換回西元年
|
|
30811
|
+
const _year2 = parseInt(dateStr.split('/')[0]) + 1911;
|
|
30812
|
+
dateStr = dateStr.replace(/^\d{3}/, _year2.toString());
|
|
30813
|
+
}
|
|
30814
|
+
// 先用正則檢查格式 yyyy/MM/dd
|
|
30815
|
+
const regex = /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/;
|
|
30816
|
+
if (!regex.test(dateStr)) return false;
|
|
30817
|
+
const [year, month, day] = dateStr.split('/').map(Number);
|
|
30818
|
+
const date = new Date(year, month - 1, day);
|
|
30819
|
+
// 檢查轉換後的日期是否一致(避免像 2023/02/30 自動變成 2023/03/02)
|
|
30820
|
+
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
|
|
30821
|
+
}
|
|
30822
|
+
function isValidDateBeforeToday(dateStr, format) {
|
|
30823
|
+
if (format === 'yyy/MM/dd') {
|
|
30824
|
+
// 民國年格式轉換回西元年
|
|
30825
|
+
const year = parseInt(dateStr.split('/')[0]) + 1911;
|
|
30826
|
+
dateStr = dateStr.replace(/^\d{3}/, year.toString());
|
|
30827
|
+
}
|
|
30828
|
+
// 判斷是不是超過今天
|
|
30829
|
+
const today = new Date();
|
|
30830
|
+
// 將時間設為 23:59:59
|
|
30831
|
+
today.setHours(23, 59, 59, 999);
|
|
30832
|
+
// 將日期字串轉換為 Date 物件
|
|
30833
|
+
const inputDate = new Date(dateStr.replace(/\//g, '-')); // 將日期字串轉換為 Date 物件
|
|
30834
|
+
if (inputDate > today) {
|
|
30835
|
+
return false; // 如果日期超過今天,返回 false
|
|
30836
|
+
}
|
|
30837
|
+
|
|
30838
|
+
return true; // 如果日期在今天之前或等於今天,返回 true
|
|
30839
|
+
}
|
|
30840
|
+
|
|
30841
|
+
function parseRegex(input, forceUnicode = false) {
|
|
30842
|
+
try {
|
|
30843
|
+
let pattern = input;
|
|
30844
|
+
let flags = '';
|
|
30845
|
+
if (input.startsWith('/') && input.lastIndexOf('/') > 0) {
|
|
30846
|
+
const lastSlash = input.lastIndexOf('/');
|
|
30847
|
+
pattern = input.slice(1, lastSlash);
|
|
30848
|
+
flags = input.slice(lastSlash + 1);
|
|
30849
|
+
}
|
|
30850
|
+
// 如果有需要強制 Unicode 模式
|
|
30851
|
+
if (forceUnicode && !flags.includes('u')) {
|
|
30852
|
+
flags += 'u';
|
|
30853
|
+
}
|
|
30854
|
+
return new RegExp(pattern, flags);
|
|
30855
|
+
} catch (e) {
|
|
30856
|
+
console.warn('⚠️ 無效的 regex:', input, e);
|
|
30857
|
+
return null;
|
|
30858
|
+
}
|
|
30859
|
+
}
|
|
30752
30860
|
function checkModifiedData() {
|
|
30753
30861
|
const items = domModal.querySelectorAll('.video-container__ocrResultModal-group-item');
|
|
30754
30862
|
items.forEach(item => {
|
|
@@ -30813,7 +30921,7 @@ const ocrResultModal = arg => {
|
|
|
30813
30921
|
}
|
|
30814
30922
|
}
|
|
30815
30923
|
} else if (input && item.dateFormat) {
|
|
30816
|
-
if (isValidDateFormat(input.value)) {
|
|
30924
|
+
if (isValidDateFormat(input, item.dateFormat) && isValidDateBeforeToday(input.value, item.dateFormat) && isValidDate(input.value, item.dateFormat)) {
|
|
30817
30925
|
// if (item.dateFormat.test(input.value)) {
|
|
30818
30926
|
item.validate = true;
|
|
30819
30927
|
(_g = domItem.querySelector('.video-container__ocrResultModal-input')) === null || _g === void 0 ? void 0 : _g.classList.remove('error');
|
|
@@ -30888,11 +30996,14 @@ const ocrResultModal = arg => {
|
|
|
30888
30996
|
return ((_a = a.order) !== null && _a !== void 0 ? _a : Infinity) - ((_b = b.order) !== null && _b !== void 0 ? _b : Infinity);
|
|
30889
30997
|
});
|
|
30890
30998
|
arg.items.forEach(item => {
|
|
30999
|
+
var _a;
|
|
31000
|
+
const needsUnicode = ((_a = item.regex) === null || _a === void 0 ? void 0 : _a.includes('\\u')) || item.name === 'name';
|
|
31001
|
+
const parsed = parseRegex(item.regex, needsUnicode);
|
|
30891
31002
|
// init validateMap
|
|
30892
31003
|
if (item.regex) {
|
|
30893
31004
|
validateMap[item.name] = {
|
|
30894
31005
|
validate: false,
|
|
30895
|
-
regex:
|
|
31006
|
+
regex: parsed
|
|
30896
31007
|
};
|
|
30897
31008
|
} else if (item.selections) {
|
|
30898
31009
|
validateMap[item.name] = {
|
|
@@ -30902,7 +31013,7 @@ const ocrResultModal = arg => {
|
|
|
30902
31013
|
} else if (item.dateFormat) {
|
|
30903
31014
|
validateMap[item.name] = {
|
|
30904
31015
|
validate: false,
|
|
30905
|
-
dateFormat:
|
|
31016
|
+
dateFormat: item.dateFormat
|
|
30906
31017
|
};
|
|
30907
31018
|
}
|
|
30908
31019
|
// init UI
|
|
@@ -30920,7 +31031,23 @@ const ocrResultModal = arg => {
|
|
|
30920
31031
|
name: item.name,
|
|
30921
31032
|
label: item.name === 'issueReason' ? translateService.translate('sdk.ocr.verify.result.issueType') : translateService.translate(`sdk.ocr.verify.result.${item.name}`),
|
|
30922
31033
|
value: item.dateFormat ? formatDate(item.value, item.dateFormat) : item.value,
|
|
30923
|
-
placeHolder:
|
|
31034
|
+
placeHolder: (() => {
|
|
31035
|
+
if (item.name === 'name') {
|
|
31036
|
+
return translateService.translate('請輸入姓名');
|
|
31037
|
+
}
|
|
31038
|
+
if (item.name === 'idNumber') {
|
|
31039
|
+
return translateService.translate('請輸入身份證字號');
|
|
31040
|
+
}
|
|
31041
|
+
return item.dateFormat ? item.dateFormat.toUpperCase() : '';
|
|
31042
|
+
})(),
|
|
31043
|
+
attribute: (() => {
|
|
31044
|
+
if (item.dateFormat) {
|
|
31045
|
+
return {
|
|
31046
|
+
inputmode: 'numeric'
|
|
31047
|
+
};
|
|
31048
|
+
}
|
|
31049
|
+
return {};
|
|
31050
|
+
})()
|
|
30924
31051
|
});
|
|
30925
31052
|
domBody.appendChild(domGroupItem);
|
|
30926
31053
|
}
|
|
@@ -31875,7 +32002,7 @@ function startOCR(config) {
|
|
|
31875
32002
|
title: `${'請確認'}${translateService.translate(config.ocrConfig.type ? `sdk.ocr.verify.result.title.${keyMapping[config.ocrConfig.type]}` : '')}`,
|
|
31876
32003
|
subtitle: '若資料有錯誤,可點擊內容進行修改',
|
|
31877
32004
|
items: result.ocrResultFilds,
|
|
31878
|
-
confirmText: translateService.translate('sdk.general.
|
|
32005
|
+
confirmText: translateService.translate('sdk.general.accept'),
|
|
31879
32006
|
hintText: '逾時將自動轉跳至選單頁並無法保存此次紀錄',
|
|
31880
32007
|
countDown1Text: '請在',
|
|
31881
32008
|
countDown2Text: '內完成確認',
|
|
@@ -31968,6 +32095,10 @@ function startOCR(config) {
|
|
|
31968
32095
|
return rxjs.merge(flow$, cancel$, detectScreenResizeError$, timeout$).pipe(rxjs.take(1));
|
|
31969
32096
|
}
|
|
31970
32097
|
rxjs.fromEvent(window, 'offline').pipe(rxjs.switchMap(() => util.asyncOnLineShowErrorMessage(translateService.translate('sdk.general.error.alert.offline'), translateService.translate('sdk.general.error.retry'), false)), rxjs.takeUntil(unsubscribe$)).subscribe();
|
|
32098
|
+
rxjs.fromEvent(window, 'online').pipe(rxjs.switchMap(() => {
|
|
32099
|
+
util.hideErrorMessage(); // 執行副作用
|
|
32100
|
+
return rxjs.EMPTY; // 回傳一個空的 Observable
|
|
32101
|
+
}), rxjs.takeUntil(unsubscribe$)).subscribe();
|
|
31971
32102
|
// resize
|
|
31972
32103
|
rxjs.fromEvent(window, 'resize').pipe(rxjs.switchMapTo(util.getCanvasSize(uiComponentBasic.video)), rxjs.switchMap(canvasSizeInfo => config.setFrameSize(canvasSizeInfo.canvasWidth, canvasSizeInfo.canvasHeight, getCardBorderPoint())), rxjs.tap(() => {
|
|
31973
32104
|
uiComponentOCR.scanAnimationContainer.style.width = `${cardSizeInfo.width + scanPadding}px`;
|
|
@@ -33171,6 +33302,14 @@ class LivenessModule {
|
|
|
33171
33302
|
// )
|
|
33172
33303
|
// );
|
|
33173
33304
|
yield handleUpload(id, frameList, resultList, meta, config, shouldEncrypt, encryptDataBase64);
|
|
33305
|
+
// upload finish view
|
|
33306
|
+
const successView = util.uploadModal({
|
|
33307
|
+
type: 'success',
|
|
33308
|
+
titleSuccess: core.getTranslateInstance().translate('sdk.general.successUpload')
|
|
33309
|
+
});
|
|
33310
|
+
// setTimeout(() => {
|
|
33311
|
+
// successView?.removeModal();
|
|
33312
|
+
// }, 900);
|
|
33174
33313
|
const result = yield this.getResult(id);
|
|
33175
33314
|
return result.isPass;
|
|
33176
33315
|
}),
|
|
@@ -34908,6 +35047,14 @@ class OCRModule {
|
|
|
34908
35047
|
// needFraudOption ? this.fraudResult : null
|
|
34909
35048
|
// )
|
|
34910
35049
|
);
|
|
35050
|
+
// upload finish view
|
|
35051
|
+
const successView = util.uploadModal({
|
|
35052
|
+
type: 'success',
|
|
35053
|
+
titleSuccess: translateService.translate('sdk.general.successUpload')
|
|
35054
|
+
});
|
|
35055
|
+
setTimeout(() => {
|
|
35056
|
+
successView === null || successView === void 0 ? void 0 : successView.removeModal();
|
|
35057
|
+
}, 300);
|
|
34911
35058
|
// ocrResultFilds = res.fields.concat(ocrResultFilds);
|
|
34912
35059
|
ocrResultFilds = ocrResultFilds.map(item1 => {
|
|
34913
35060
|
const item2 = res.fields.find(item => item.name === item1.name);
|
|
@@ -35765,8 +35912,8 @@ class AuthmeIdentityVerification extends engine.AuthmeFunctionModule {
|
|
|
35765
35912
|
}
|
|
35766
35913
|
|
|
35767
35914
|
var name = "authme/sdk";
|
|
35768
|
-
var version$1 = "2.8.
|
|
35769
|
-
var date = "2025-05-
|
|
35915
|
+
var version$1 = "2.8.17";
|
|
35916
|
+
var date = "2025-05-22T09:38:34+0000";
|
|
35770
35917
|
var packageInfo = {
|
|
35771
35918
|
name: name,
|
|
35772
35919
|
version: version$1,
|
package/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import 'core-js/modules/es.promise.js';
|
|
|
7
7
|
import { getTranslateInstance, EventListenerService, TrackingEvent, generateStatus, StatusDescription, AuthmeError, ErrorCode, Feature, StatusEvent, StatusView, StatusAction, setRequestLoggingFunc, setAccessToken, getCustomerState } from '@authme/core';
|
|
8
8
|
import { EAuthMeFASServiceStatus, EAuthMeIDCardAntiFraudStage as EAuthMeIDCardAntiFraudStage$1, EAuthMeCardClass as EAuthMeCardClass$1, AuthmeFunctionModule, MlEngine, EngineModule, EAuthMeEngineReturnCode, AuthmeEngineModuleBase } from '@authme/engine';
|
|
9
9
|
import { IdRecognitionCardType, CountryCode, EAuthMeCardClass, EAuthMeIDCardAntiFraudStatus, EAuthMeIDCardAntiFraudStage, thicknessDefaultConfig, mapCardtypeToAuthmeClass, getRecognitionColumnOrder, cardTypeTitle, cardTypeConfirmTitle, cardTypeHeader, EAuthMeCardOCRStatus, EAuthMeMRZServiceStatus, saveExtraDoc, initScanDocumentResourceBase64, MRZService, option, themeUI, initScan, initScanDocument, ResourceImageType, uploadFrameBase64, finishScanDocument, CardOCR, IdCardAntiFraudService, twoWayAuthmeCardClassMap, RecognitionFileType, recognizeBase64, getCardSubTypes, getCardTypes, confirmScan } from '@authme/id-recognition';
|
|
10
|
-
import { getCssVariable, RGBToLottieColor, colorToRGB, Storage, useState, uiThemeText, uiThemeHint, clearCanvas, getImageData, isMobile, hidePopup, showPopup, waitTime, TIME_UNIT, AuthmeError as AuthmeError$1, ErrorCode as ErrorCode$1, uiThemeButton, uiThemeSmallButton, requestCamera, showElement, asyncOnLineShowErrorMessage, getCanvasSize, startSpinner, stopSpinner, themeConfigDefault, fontWeight, hideElement, dataURItoBlob, showErrorMessage, checkOnlineStatus, dropMenu, UintArrayToBlob, isIphone14proOrProMax, cropByRatio, switchCamera, asyncShowPopup, retryPromiseWithCondition, asyncShowErrorMessage,
|
|
10
|
+
import { getCssVariable, RGBToLottieColor, colorToRGB, Storage, useState, uiThemeText, uiThemeHint, clearCanvas, getImageData, isMobile, hidePopup, showPopup, waitTime, TIME_UNIT, AuthmeError as AuthmeError$1, ErrorCode as ErrorCode$1, uiThemeButton, uiThemeSmallButton, requestCamera, showElement, asyncOnLineShowErrorMessage, getCanvasSize, startSpinner, stopSpinner, themeConfigDefault, fontWeight, hideElement, dataURItoBlob, showErrorMessage, checkOnlineStatus, dropMenu, hideErrorMessage, UintArrayToBlob, isIphone14proOrProMax, cropByRatio, switchCamera, asyncShowPopup, retryPromiseWithCondition, asyncShowErrorMessage, uploadModal, backgroundRequest, debugTools, showErrorMessageEventName, RUN_FUNCTION_NAME, STORAGE_KEY, splitResult, DEVICE_TYPE, combineResult, startLoadingSDK, stopLoadingSDK } from '@authme/util';
|
|
11
11
|
import { mergeMap, animationFrames, filter, tap, map, from, catchError, EMPTY, of, merge, fromEvent, concatAll, takeUntil, Subject, defer, throttleTime, switchMap, raceWith, concatMap, throwError, finalize, timer, Observable, take, interval, mapTo, firstValueFrom, shareReplay, switchMapTo, takeWhile as takeWhile$1, race } from 'rxjs';
|
|
12
12
|
import 'core-js/modules/es.regexp.to-string.js';
|
|
13
13
|
import { FasRecognitionResult, EAuthMeFASServiceStage, FasService, LivenessAPI, EAuthMeMouthStatus, LivenessResultStatus } from '@authme/liveness';
|
|
@@ -29,6 +29,8 @@ import 'core-js/modules/es.typed-array.set.js';
|
|
|
29
29
|
import 'core-js/modules/es.typed-array.sort.js';
|
|
30
30
|
import 'core-js/modules/es.typed-array.to-locale-string.js';
|
|
31
31
|
import 'core-js/modules/es.string.pad-start.js';
|
|
32
|
+
import 'core-js/modules/es.string.match.js';
|
|
33
|
+
import 'core-js/modules/es.string.starts-with.js';
|
|
32
34
|
import 'core-js/modules/es.regexp.constructor.js';
|
|
33
35
|
import 'core-js/modules/es.typed-array.uint8-array.js';
|
|
34
36
|
|
|
@@ -28124,7 +28126,12 @@ const popupView = arg => {
|
|
|
28124
28126
|
domPopupViewContainer.style.borderRadius = `${uiThemeConfig.popupView.cornerRadius}px`;
|
|
28125
28127
|
uiThemeText(domTitle, uiThemeConfig.titleOne);
|
|
28126
28128
|
uiThemeText(domContent, uiThemeConfig.bodyTwo);
|
|
28127
|
-
|
|
28129
|
+
console.log('deviceType', uiThemeConfig.deviceType);
|
|
28130
|
+
if (uiThemeConfig.deviceType === 'mobile') {
|
|
28131
|
+
uiThemeSmallButton(domConfirm, uiThemeConfig.smallermMajorButton);
|
|
28132
|
+
} else {
|
|
28133
|
+
uiThemeButton(domConfirm, uiThemeConfig.majorButton);
|
|
28134
|
+
}
|
|
28128
28135
|
if (arg.cancel) {
|
|
28129
28136
|
uiThemeSmallButton(domCancel, uiThemeConfig.smallerMinorButton);
|
|
28130
28137
|
domCancel.innerHTML = arg.cancel;
|
|
@@ -30630,7 +30637,8 @@ const ocrResultModal = arg => {
|
|
|
30630
30637
|
name,
|
|
30631
30638
|
label,
|
|
30632
30639
|
value,
|
|
30633
|
-
placeHolder
|
|
30640
|
+
placeHolder,
|
|
30641
|
+
attribute
|
|
30634
30642
|
}) {
|
|
30635
30643
|
const domGroupItem = document.createElement('div');
|
|
30636
30644
|
domGroupItem.classList.add('video-container__ocrResultModal-group-item');
|
|
@@ -30647,6 +30655,11 @@ const ocrResultModal = arg => {
|
|
|
30647
30655
|
domInput.value = value;
|
|
30648
30656
|
domError.innerText = `${label}格式不符`;
|
|
30649
30657
|
domInput.placeholder = placeHolder;
|
|
30658
|
+
if (attribute) {
|
|
30659
|
+
Object.keys(attribute).forEach(key => {
|
|
30660
|
+
domInput.setAttribute(key, attribute[key]);
|
|
30661
|
+
});
|
|
30662
|
+
}
|
|
30650
30663
|
domInput.addEventListener('input', () => {
|
|
30651
30664
|
validateFields() ? btnConfirmStatus(false) : btnConfirmStatus(true);
|
|
30652
30665
|
// btnConfirmStatus(Object.values(validateMap).some((i: any) => i.validate === false));
|
|
@@ -30720,6 +30733,15 @@ const ocrResultModal = arg => {
|
|
|
30720
30733
|
return domGroupItem;
|
|
30721
30734
|
}
|
|
30722
30735
|
function formatDate(dateString, format) {
|
|
30736
|
+
// 檢查是否為民國年格式
|
|
30737
|
+
if (dateString.match(/^\d{3}\/\d{2}\/\d{2}$/)) {
|
|
30738
|
+
// 將民國年轉換為西元年
|
|
30739
|
+
const parts = dateString.split('/');
|
|
30740
|
+
const _year = parseInt(parts[0], 10) + 1911; // 民國年轉西元年
|
|
30741
|
+
const _month = parts[1].padStart(2, '0'); // 補 0 的月份
|
|
30742
|
+
const _day = parts[2].padStart(2, '0'); // 補 0 的日期
|
|
30743
|
+
dateString = `${_year}-${_month}-${_day}`;
|
|
30744
|
+
}
|
|
30723
30745
|
// 確保日期格式為 "YYYY-MM-DD",避免瀏覽器解析錯誤
|
|
30724
30746
|
const normalizedDateString = dateString.replace(/\//g, '-');
|
|
30725
30747
|
// 解析日期字串
|
|
@@ -30728,19 +30750,105 @@ const ocrResultModal = arg => {
|
|
|
30728
30750
|
throw new Error('Invalid date format');
|
|
30729
30751
|
}
|
|
30730
30752
|
// 取得年月日
|
|
30731
|
-
|
|
30753
|
+
let year = date.getFullYear().toString(); // 取得年份
|
|
30732
30754
|
const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 補 0 的月份
|
|
30733
30755
|
const day = date.getDate().toString().padStart(2, '0'); // 補 0 的日期
|
|
30756
|
+
// 依照格式轉換成民國年
|
|
30757
|
+
if (format === 'yyy/MM/dd') {
|
|
30758
|
+
year = (parseInt(year) - 1911).toString(); // 民國年
|
|
30759
|
+
if (year.length === 2) {
|
|
30760
|
+
year = '0' + year; // 補 0 的民國年
|
|
30761
|
+
}
|
|
30762
|
+
}
|
|
30734
30763
|
// 替換格式
|
|
30735
|
-
return format.replace(/YYYY|yyyy/g, year) // 年份 (YYYY 或 yyyy)
|
|
30764
|
+
return format.replace(/YYYY|yyyy|YYY|yyy/g, year) // 年份 (YYYY 或 yyyy)
|
|
30736
30765
|
.replace(/MM|mm/g, month) // 月份 (MM)
|
|
30737
30766
|
.replace(/dd/g, day); // 日期 (dd)
|
|
30738
30767
|
}
|
|
30739
|
-
|
|
30740
|
-
function isValidDateFormat(
|
|
30741
|
-
|
|
30768
|
+
// 驗證日期格式
|
|
30769
|
+
function isValidDateFormat(input, format) {
|
|
30770
|
+
let dateStr = input.value;
|
|
30771
|
+
if (!isNaN(Number(dateStr))) {
|
|
30772
|
+
let year = '';
|
|
30773
|
+
let month = '';
|
|
30774
|
+
let day = '';
|
|
30775
|
+
if (format === 'yyy/MM/dd') {
|
|
30776
|
+
if (dateStr.length === 7) {
|
|
30777
|
+
// 民國年格式
|
|
30778
|
+
year = dateStr.slice(0, 3);
|
|
30779
|
+
month = dateStr.slice(3, 5);
|
|
30780
|
+
day = dateStr.slice(5, 7);
|
|
30781
|
+
dateStr = `${year}/${month}/${day}`;
|
|
30782
|
+
}
|
|
30783
|
+
} else {
|
|
30784
|
+
if (dateStr.length === 8) {
|
|
30785
|
+
// 西元年格式
|
|
30786
|
+
year = dateStr.slice(0, 4);
|
|
30787
|
+
month = dateStr.slice(4, 6);
|
|
30788
|
+
day = dateStr.slice(6, 8);
|
|
30789
|
+
dateStr = `${year}/${month}/${day}`;
|
|
30790
|
+
}
|
|
30791
|
+
}
|
|
30792
|
+
}
|
|
30793
|
+
input.value = dateStr;
|
|
30794
|
+
let regex = /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/;
|
|
30795
|
+
if (format === 'yyy/MM/dd') {
|
|
30796
|
+
regex = /^\d{3}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/;
|
|
30797
|
+
}
|
|
30742
30798
|
return regex.test(dateStr);
|
|
30743
30799
|
}
|
|
30800
|
+
function isValidDate(dateStr, format) {
|
|
30801
|
+
if (format === 'yyy/MM/dd') {
|
|
30802
|
+
// 民國年格式轉換回西元年
|
|
30803
|
+
const _year2 = parseInt(dateStr.split('/')[0]) + 1911;
|
|
30804
|
+
dateStr = dateStr.replace(/^\d{3}/, _year2.toString());
|
|
30805
|
+
}
|
|
30806
|
+
// 先用正則檢查格式 yyyy/MM/dd
|
|
30807
|
+
const regex = /^\d{4}\/(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])$/;
|
|
30808
|
+
if (!regex.test(dateStr)) return false;
|
|
30809
|
+
const [year, month, day] = dateStr.split('/').map(Number);
|
|
30810
|
+
const date = new Date(year, month - 1, day);
|
|
30811
|
+
// 檢查轉換後的日期是否一致(避免像 2023/02/30 自動變成 2023/03/02)
|
|
30812
|
+
return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
|
|
30813
|
+
}
|
|
30814
|
+
function isValidDateBeforeToday(dateStr, format) {
|
|
30815
|
+
if (format === 'yyy/MM/dd') {
|
|
30816
|
+
// 民國年格式轉換回西元年
|
|
30817
|
+
const year = parseInt(dateStr.split('/')[0]) + 1911;
|
|
30818
|
+
dateStr = dateStr.replace(/^\d{3}/, year.toString());
|
|
30819
|
+
}
|
|
30820
|
+
// 判斷是不是超過今天
|
|
30821
|
+
const today = new Date();
|
|
30822
|
+
// 將時間設為 23:59:59
|
|
30823
|
+
today.setHours(23, 59, 59, 999);
|
|
30824
|
+
// 將日期字串轉換為 Date 物件
|
|
30825
|
+
const inputDate = new Date(dateStr.replace(/\//g, '-')); // 將日期字串轉換為 Date 物件
|
|
30826
|
+
if (inputDate > today) {
|
|
30827
|
+
return false; // 如果日期超過今天,返回 false
|
|
30828
|
+
}
|
|
30829
|
+
|
|
30830
|
+
return true; // 如果日期在今天之前或等於今天,返回 true
|
|
30831
|
+
}
|
|
30832
|
+
|
|
30833
|
+
function parseRegex(input, forceUnicode = false) {
|
|
30834
|
+
try {
|
|
30835
|
+
let pattern = input;
|
|
30836
|
+
let flags = '';
|
|
30837
|
+
if (input.startsWith('/') && input.lastIndexOf('/') > 0) {
|
|
30838
|
+
const lastSlash = input.lastIndexOf('/');
|
|
30839
|
+
pattern = input.slice(1, lastSlash);
|
|
30840
|
+
flags = input.slice(lastSlash + 1);
|
|
30841
|
+
}
|
|
30842
|
+
// 如果有需要強制 Unicode 模式
|
|
30843
|
+
if (forceUnicode && !flags.includes('u')) {
|
|
30844
|
+
flags += 'u';
|
|
30845
|
+
}
|
|
30846
|
+
return new RegExp(pattern, flags);
|
|
30847
|
+
} catch (e) {
|
|
30848
|
+
console.warn('⚠️ 無效的 regex:', input, e);
|
|
30849
|
+
return null;
|
|
30850
|
+
}
|
|
30851
|
+
}
|
|
30744
30852
|
function checkModifiedData() {
|
|
30745
30853
|
const items = domModal.querySelectorAll('.video-container__ocrResultModal-group-item');
|
|
30746
30854
|
items.forEach(item => {
|
|
@@ -30805,7 +30913,7 @@ const ocrResultModal = arg => {
|
|
|
30805
30913
|
}
|
|
30806
30914
|
}
|
|
30807
30915
|
} else if (input && item.dateFormat) {
|
|
30808
|
-
if (isValidDateFormat(input.value)) {
|
|
30916
|
+
if (isValidDateFormat(input, item.dateFormat) && isValidDateBeforeToday(input.value, item.dateFormat) && isValidDate(input.value, item.dateFormat)) {
|
|
30809
30917
|
// if (item.dateFormat.test(input.value)) {
|
|
30810
30918
|
item.validate = true;
|
|
30811
30919
|
(_g = domItem.querySelector('.video-container__ocrResultModal-input')) === null || _g === void 0 ? void 0 : _g.classList.remove('error');
|
|
@@ -30880,11 +30988,14 @@ const ocrResultModal = arg => {
|
|
|
30880
30988
|
return ((_a = a.order) !== null && _a !== void 0 ? _a : Infinity) - ((_b = b.order) !== null && _b !== void 0 ? _b : Infinity);
|
|
30881
30989
|
});
|
|
30882
30990
|
arg.items.forEach(item => {
|
|
30991
|
+
var _a;
|
|
30992
|
+
const needsUnicode = ((_a = item.regex) === null || _a === void 0 ? void 0 : _a.includes('\\u')) || item.name === 'name';
|
|
30993
|
+
const parsed = parseRegex(item.regex, needsUnicode);
|
|
30883
30994
|
// init validateMap
|
|
30884
30995
|
if (item.regex) {
|
|
30885
30996
|
validateMap[item.name] = {
|
|
30886
30997
|
validate: false,
|
|
30887
|
-
regex:
|
|
30998
|
+
regex: parsed
|
|
30888
30999
|
};
|
|
30889
31000
|
} else if (item.selections) {
|
|
30890
31001
|
validateMap[item.name] = {
|
|
@@ -30894,7 +31005,7 @@ const ocrResultModal = arg => {
|
|
|
30894
31005
|
} else if (item.dateFormat) {
|
|
30895
31006
|
validateMap[item.name] = {
|
|
30896
31007
|
validate: false,
|
|
30897
|
-
dateFormat:
|
|
31008
|
+
dateFormat: item.dateFormat
|
|
30898
31009
|
};
|
|
30899
31010
|
}
|
|
30900
31011
|
// init UI
|
|
@@ -30912,7 +31023,23 @@ const ocrResultModal = arg => {
|
|
|
30912
31023
|
name: item.name,
|
|
30913
31024
|
label: item.name === 'issueReason' ? translateService.translate('sdk.ocr.verify.result.issueType') : translateService.translate(`sdk.ocr.verify.result.${item.name}`),
|
|
30914
31025
|
value: item.dateFormat ? formatDate(item.value, item.dateFormat) : item.value,
|
|
30915
|
-
placeHolder:
|
|
31026
|
+
placeHolder: (() => {
|
|
31027
|
+
if (item.name === 'name') {
|
|
31028
|
+
return translateService.translate('請輸入姓名');
|
|
31029
|
+
}
|
|
31030
|
+
if (item.name === 'idNumber') {
|
|
31031
|
+
return translateService.translate('請輸入身份證字號');
|
|
31032
|
+
}
|
|
31033
|
+
return item.dateFormat ? item.dateFormat.toUpperCase() : '';
|
|
31034
|
+
})(),
|
|
31035
|
+
attribute: (() => {
|
|
31036
|
+
if (item.dateFormat) {
|
|
31037
|
+
return {
|
|
31038
|
+
inputmode: 'numeric'
|
|
31039
|
+
};
|
|
31040
|
+
}
|
|
31041
|
+
return {};
|
|
31042
|
+
})()
|
|
30916
31043
|
});
|
|
30917
31044
|
domBody.appendChild(domGroupItem);
|
|
30918
31045
|
}
|
|
@@ -31867,7 +31994,7 @@ function startOCR(config) {
|
|
|
31867
31994
|
title: `${'請確認'}${translateService.translate(config.ocrConfig.type ? `sdk.ocr.verify.result.title.${keyMapping[config.ocrConfig.type]}` : '')}`,
|
|
31868
31995
|
subtitle: '若資料有錯誤,可點擊內容進行修改',
|
|
31869
31996
|
items: result.ocrResultFilds,
|
|
31870
|
-
confirmText: translateService.translate('sdk.general.
|
|
31997
|
+
confirmText: translateService.translate('sdk.general.accept'),
|
|
31871
31998
|
hintText: '逾時將自動轉跳至選單頁並無法保存此次紀錄',
|
|
31872
31999
|
countDown1Text: '請在',
|
|
31873
32000
|
countDown2Text: '內完成確認',
|
|
@@ -31960,6 +32087,10 @@ function startOCR(config) {
|
|
|
31960
32087
|
return merge(flow$, cancel$, detectScreenResizeError$, timeout$).pipe(take(1));
|
|
31961
32088
|
}
|
|
31962
32089
|
fromEvent(window, 'offline').pipe(switchMap(() => asyncOnLineShowErrorMessage(translateService.translate('sdk.general.error.alert.offline'), translateService.translate('sdk.general.error.retry'), false)), takeUntil(unsubscribe$)).subscribe();
|
|
32090
|
+
fromEvent(window, 'online').pipe(switchMap(() => {
|
|
32091
|
+
hideErrorMessage(); // 執行副作用
|
|
32092
|
+
return EMPTY; // 回傳一個空的 Observable
|
|
32093
|
+
}), takeUntil(unsubscribe$)).subscribe();
|
|
31963
32094
|
// resize
|
|
31964
32095
|
fromEvent(window, 'resize').pipe(switchMapTo(getCanvasSize(uiComponentBasic.video)), switchMap(canvasSizeInfo => config.setFrameSize(canvasSizeInfo.canvasWidth, canvasSizeInfo.canvasHeight, getCardBorderPoint())), tap(() => {
|
|
31965
32096
|
uiComponentOCR.scanAnimationContainer.style.width = `${cardSizeInfo.width + scanPadding}px`;
|
|
@@ -33163,6 +33294,14 @@ class LivenessModule {
|
|
|
33163
33294
|
// )
|
|
33164
33295
|
// );
|
|
33165
33296
|
yield handleUpload(id, frameList, resultList, meta, config, shouldEncrypt, encryptDataBase64);
|
|
33297
|
+
// upload finish view
|
|
33298
|
+
const successView = uploadModal({
|
|
33299
|
+
type: 'success',
|
|
33300
|
+
titleSuccess: getTranslateInstance().translate('sdk.general.successUpload')
|
|
33301
|
+
});
|
|
33302
|
+
// setTimeout(() => {
|
|
33303
|
+
// successView?.removeModal();
|
|
33304
|
+
// }, 900);
|
|
33166
33305
|
const result = yield this.getResult(id);
|
|
33167
33306
|
return result.isPass;
|
|
33168
33307
|
}),
|
|
@@ -34900,6 +35039,14 @@ class OCRModule {
|
|
|
34900
35039
|
// needFraudOption ? this.fraudResult : null
|
|
34901
35040
|
// )
|
|
34902
35041
|
);
|
|
35042
|
+
// upload finish view
|
|
35043
|
+
const successView = uploadModal({
|
|
35044
|
+
type: 'success',
|
|
35045
|
+
titleSuccess: translateService.translate('sdk.general.successUpload')
|
|
35046
|
+
});
|
|
35047
|
+
setTimeout(() => {
|
|
35048
|
+
successView === null || successView === void 0 ? void 0 : successView.removeModal();
|
|
35049
|
+
}, 300);
|
|
34903
35050
|
// ocrResultFilds = res.fields.concat(ocrResultFilds);
|
|
34904
35051
|
ocrResultFilds = ocrResultFilds.map(item1 => {
|
|
34905
35052
|
const item2 = res.fields.find(item => item.name === item1.name);
|
|
@@ -35757,8 +35904,8 @@ class AuthmeIdentityVerification extends AuthmeFunctionModule {
|
|
|
35757
35904
|
}
|
|
35758
35905
|
|
|
35759
35906
|
var name = "authme/sdk";
|
|
35760
|
-
var version$1 = "2.8.
|
|
35761
|
-
var date = "2025-05-
|
|
35907
|
+
var version$1 = "2.8.17";
|
|
35908
|
+
var date = "2025-05-22T09:38:34+0000";
|
|
35762
35909
|
var packageInfo = {
|
|
35763
35910
|
name: name,
|
|
35764
35911
|
version: version$1,
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authme/identity-verification",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.17",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"core-js": "^3.6.0",
|
|
6
6
|
"lottie-web": "^5.9.2",
|
|
7
7
|
"rxjs": "^7.4.0",
|
|
8
|
-
"@authme/core": "2.8.
|
|
9
|
-
"@authme/engine": "2.8.
|
|
10
|
-
"@authme/id-recognition": "2.8.
|
|
11
|
-
"@authme/liveness": "2.8.
|
|
12
|
-
"@authme/util": "2.8.
|
|
8
|
+
"@authme/core": "2.8.17",
|
|
9
|
+
"@authme/engine": "2.8.17",
|
|
10
|
+
"@authme/id-recognition": "2.8.17",
|
|
11
|
+
"@authme/liveness": "2.8.17",
|
|
12
|
+
"@authme/util": "2.8.17"
|
|
13
13
|
},
|
|
14
14
|
"module": "./index.js",
|
|
15
15
|
"main": "./index.cjs",
|