UNPKG

mtl-js-sdk

Version:

ynf-fw-mtl-api

997 lines (929 loc) 30 kB
/* * @Author: wangyingliang@yonyou.com * @Date: 2024-10-31 09:34:14 * @LastEditors: wangyingliang wangyingliang@yonyou.com * @LastEditTime: 2025-09-02 17:45:00 * @FilePath: /mtl-api-project/src/platforms/h5/methods.js * @Description: H5 平台入口文件 * Copyright (c) 2024 by Yonyou, All Rights Reserved. */ import xaxios from 'axios' import QRious from 'qrious' import home from './unique.js' import unique from '../../common/unique.js' import map from '../h5/map/amapLocation.js' import amap from '../h5/map/amapOpen.js' /* eslint-disable no-extra-boolean-cast */ const baseUrl = "ht" + "tps://bip-dai" + "ly.yonyoucloud.com/iuap-yonbuilder-mobile" const SUCCESS_CODE = 200 const FAIL_CODE = 1 const unsupportFailRes = { code: FAIL_CODE, message: "The current platform doesn't support", } var isAddEventListener = false var isChooseImagesAddEventListener = false const axios = xaxios?.default || xaxios const DEFAULT_STORAGE_DOMAIN = "domain.default" const unsupportMethods = [ "startRecord", "stopRecord", "onVoiceRecordEnd", "startSpeechSyn", "stopSpeechSyn", "playVoice", "pauseVoice", "stopVoice", "onVoicePlayEnd", "uploadVoice", "downloadVoice", "uploadImage", "downloadImage", "translateVoice", "smileDetect", "faceRegister", "faceVerify", "faceCompare", "getAuthCode", "getAppCode", "getMac", "getOAuthCode", "customScanQRCode", "doShare", "openShare", "openSchema", "setStatusBar", "registerCommonCallback", "getStatusBarHeight", "markAndNavigationDestination", "showToast", "previewImage", "execUpesnBridge", "moveFileToDisk", ] function unsupportMethodIMP(object = {}) { object.fail && object.fail(unsupportFailRes) object.complete && object.complete(unsupportFailRes) } /** * 处理API成功的回调 */ function successCallBack(obj = {}) { obj.success && obj.success({}) obj.complete && obj.complete({}) } function successCallBackArray(obj = {}) { obj.success && obj.success([]) obj.complete && obj.complete({}) } const supportMethods = [ "getAppInfo", "isExclusivePreloadMDF", "getExclusiveAppH5LocationPath", "restoreScreenOrientation", "changeScreenOrientation", "isWebviewCanGoBack", "onWebviewGoBack", "backIntercept", "closeScanQRCode", "switchLongPress", "setUserFontSize", "afterPrivacyAgreement", "webViewCustomScanQRCode", "execPluginBridge", "execPluginSyncBridge", "setCookie", "requestPermission", "chooseMap", "setGesturePassword", "verifyGesturePassword", "verifyLoginPassword", "continuousLocationStart", "mapLocationExtend", "chooseImageToServer", "compressLocalImage", "continuousShooting", "getVideoThumbnail", "chooseFile", "chooseFileFromLibrary", "commonReplyComponent", "searchBleClient", "bindSensor", "getBindedSensor", "connectBle", "registerConnectStatusListener", "collectVib", "collectTmp", "collectRev", "getConnectStatus", "stopCollect", "disconnectBle", "encryptData", "decryptData", "viewUserInfo", "chooseDepartment", "chooseContacts", "chooseAllContacts", "chooseInsideGroup", "convertMemberIDs", "chooseUserOrGroupFromChat", "createFeedComponent", "sendImageMessages", "createNewSchedule", "viewScheduleList", "viewScheduleDetail", "getSchedulesFromMobile", "sendMiniMail", "openLibraryFiles", "chooseLibraryFiles", "getUserAgent", "getUserFontSize", "openCreateSpace", "copyTextPasteboard", "operateCloudAlarm", "checkCloudAlarm", "continuousShootingLocal", "openChatByGroupId", "getXYVersion", "openXYChatView", "closeXYChatView", "mdfIsLoad", "chooseGroupContacts", "jumpSystemSettings", "configSkinAndTabbar", "getWechatBill", "isFileExist", "getAppInformation", "getMultiDataCenterConfig", "selectFiles", "getWatermarkInfo", "openLiveFlow", "relayoutCustomWebview", "writeAnnounceReply", "openAnnounceReply", "collectionData", "getGzipAppData", "configAppletMenu", "getHhtQrCodeInfo", "startMirrorScreen", "closeMirrorScreen", "checkMirrorStatus", "yonyouPay", "announceDetail", "writeLocationLog", "readLocationLog", "reloadWorkbenchPath", "openSearchAppList", "openSignViewWithParams", "shareApplet", "zebraPrinterList", "zebraPrintImage", "getOffLineOutSignPhoto", "config", "registerLifeCycle", "appletFromQzId", "openWindow", "openPluginWithParams", "openAppSetting", "openCustomSetting", "releaseBle", "vibrateLong", "openDocument", "appearanceMode", "onAppearanceModeChange", "toggleCamera", "onPullDownHandle", "stopPullDownHandle", "onPullUpHandle", "stopPullUpHandle", "deleteBase64Image", "getBase64Image", "saveBase64Image", "createShortcut", "openScheduleDetail", "executeDBOperate", "saveImageToPhotoAlbum", "h5PageClose", "configureWebView", ] function generateQRCode(object) { if (unique.isEmpty("str", object.str, object)) { return } let qr = new QRious({ value: object.str, size: object.size || 100, }) let imgSrc = qr.toDataURL("image/jpeg") let res = { imgSrc } object.success && object.success(res) object.complete && object.complete(res) } function scanInvoice(object) { mtl.chooseImage({ count: 1, // 默认9 sizeType: ["original", "compressed"], sourceType: ["album", "camera"], success: (res) => { let localIds = res.localIds mtl.recognizeInvoice({ ...object, image: localIds[0] }) }, fail: object.fail, }) } function recognizeInvoice(object) { recognize({ ...object, recognizetype: "invoice" }) } function scanIDCard(object) { let sourceType = object.sourceType mtl.chooseImage({ count: 1, // 默认9 sizeType: ["original", "compressed"], sourceType: sourceType || ["album", "camera"], success: (res) => { console.log("scanIDCard success", res) let localIds = res.localIds mtl.recognizeIDCard({ ...object, image: localIds[0] }) }, fail: object.fail, }) } function recognizeIDCard(object) { recognize({ ...object, recognizetype: "id" }) } function scanBankCard(object) { mtl.chooseImage({ count: 1, // 默认9 sizeType: ["original", "compressed"], sourceType: ["album", "camera"], success: (res) => { let localIds = res.localIds mtl.recognizeBankCard({ ...object, image: localIds[0] }) }, fail: object.fail, }) } function recognizeBankCard(object) { recognize({ ...object, recognizetype: "bank" }) } function recognize(object) { let { appCode, image, side, url = baseUrl, recognizetype } = object let index = image.indexOf("base64,") if (index !== -1) { image = image.substring(index + 7, image.count) } let path if (recognizetype === "invoice") { path = `${url}/rest/v1/api/apilink/ocr/invoice/vat/base64` } else if (recognizetype === "id") { path = `${url}/rest/v1/api/apilink/ocr/card/id/base64` } else if (recognizetype === "bank") { path = `${url}/rest/v1/api/apilink/ocr/card/bank/base64` } let params = { image: image, apiCode: appCode, isFront: side === "back" ? false : true, } axios({ method: "post", url: path, params: null, data: params, headers: { "Content-Type": "application/json;charset=UTF-8", }, }) .then((res) => { object.success && object.success(res.data) object.complete && object.complete(res) }) .catch(function (err) { object.fail && object.fail(err) object.complete && object.complete(err) }) } function request(object) { let { url, method = "GET", headers = { "content-type": "application/json" }, params = {}, withCredentials = true, responseType = 'text' } = object if (url && url.substring(0, 2) === "${") { const key = getBracketStr(url) const config = mtl.getStorageSync({ domain: "mtl", key: "mtlContext", }) let host = "" if (config.host) { host = config.host[key] } url = url.replace(`\${${key}}`, host) } // 兼容老的逻辑 // 除了GET请求之外,其他参数都放在data中。如果其他请求方式需要传到params中,使用方需要将入参拼接到url let data = {} if (method.toUpperCase() != "GET") { data = params params = {} } let obj = { url, method, headers, params, data, responseType, withCredentials, } axios(obj) .then((response) => { let { status: code, statusText: message, data } = response if (code === 200) { object.success && object.success(response) } else { object.fail && object.fail({ code, message, data }) } object.complete && object.complete({ code, message, data }) }) .catch((err) => { const result = { code: FAIL_CODE, message: err.message } object.fail && object.fail(result) object.complete && object.complete(result) }) } function getBracketStr(text) { let result = "" if (!text || text === "") return result let regex = /\{(.+?)\}/g let options = text.match(regex) if (options && options !== "") { let option = options[0] if (option && option !== "") { result = option.substring(1, option.length - 1) } } return result } function setStorage(obj) { let { domain = DEFAULT_STORAGE_DOMAIN, key, data } = obj if (unique.isEmpty("key", key, obj)) { return } if (typeof key != "string") { throw new TypeError("key is not a string") } let structs = localStorage.getItem(domain) structs = (structs && JSON.parse(structs)) || {} structs[key] = data localStorage.setItem(domain, JSON.stringify(structs)) obj.success && obj.success({ code: SUCCESS_CODE, message: "setStorage:ok" }) obj.complete && obj.complete({ code: SUCCESS_CODE, message: "setStorage:ok" }) } function getStorage(obj) { let res = null let data = null let { domain = DEFAULT_STORAGE_DOMAIN, key} = obj if (unique.isEmpty("key", key, obj)) { return } if (typeof key != "string") { res = { code: FAIL_CODE, message: new TypeError("key is not a string").toString(), } obj.fail && obj.fail(res) } else { // 先使用 domain.default 获取当前域名下全部数据 let structs = localStorage.getItem(domain) structs = structs && JSON.parse(structs) data = structs && structs.hasOwnProperty(key) ? structs[key] : null if (typeof data === "boolean" || typeof data === "number" || !!data) { res = { code: SUCCESS_CODE, message: "getStorage:ok", data: data, } obj.success && obj.success(res) } else { // domain.default 获取不到时, 直接使用 key 获取. structs = localStorage.getItem(key) try { data = structs && JSON.parse(structs) if (!!data) { res = { code: SUCCESS_CODE, message: "getStorage:ok", data: data, } obj.success && obj.success(res) } else { res = { code: FAIL_CODE, message: `key = ${key}, data is null !`, } obj.fail && obj.fail(res) } } catch (error) { if (typeof structs == "string") { res = { code: SUCCESS_CODE, message: "getStorage:ok", data: structs, } obj.success && obj.success(res) } else { res = { code: FAIL_CODE, message: `key = ${key}, data is null !`, } obj.fail && obj.fail(res) } } } } obj.complete && obj.complete(res) return data } function removeStorage(obj = {}) { let { domain = DEFAULT_STORAGE_DOMAIN, key } = obj let data = null if (unique.isEmpty("key", key, obj)) { return } if (typeof key != "string") { throw new TypeError("key is not a string") } let structs = localStorage.getItem(domain) structs = (structs && JSON.parse(structs)) || {} if (data) { structs[key] = data } else { delete structs[key] } localStorage.setItem(domain, JSON.stringify(structs)) obj.success && obj.success() obj.complete && obj.complete({ code: SUCCESS_CODE, message: "removeStorage:ok" }) } function clearStorage(obj) { const domain = (obj && obj.domain) || DEFAULT_STORAGE_DOMAIN localStorage.removeItem(domain) obj.success && obj.success() obj.complete && obj.complete({ code: SUCCESS_CODE, message: "clearStorage:ok" }) } // 协同审批中心使用此参数 function navigateTo({url, useOpen=false}) { if (useOpen) { window.open(url) } else { window.location.href = url } } function redirectTo({ url, parameters }) { location.replace(url) } function navigateBack() { history.back() } function reLaunch({ url }) { history.go(1 - history.length) history.replaceState({}, null, url) } function openLocation(obj) { amap.amapOpen(obj) } function getLocation(obj) { map.amapLocation(obj) } function scanQRCode(obj) { var person = window.prompt("please input scan result:") if (!!!person) { obj.fail && obj.fail({ code: FAIL_CODE, message: "input is empty" }) obj.complete && obj.complete({ code: FAIL_CODE, message: "input is empty" }) } else { obj.success && obj.success({ resultStr: person }) obj.complete && obj.complete({ resultStr: person }) } } function getConfig(object) { const info = localStorage.getItem("mtlAppConfig") const res = (info && JSON.parse(info)) || {} object.success && object.success(res) } function openNewWebview(obj = {}) { mtl.navigateTo({ url: obj.url, success: function (res) { obj.success && obj.success(res) }, fail: function (err) { obj.fail && obj.fail(err) }, }) } function closeCurrentWebview(obj = {}) { mtl.navigateBack(obj) } function openExclusiveApp(obj = {}) { const { appUrl } = obj if (unique.isEmpty("appUrl", appUrl, obj)) { return } mtl.navigateTo({ url: appUrl, success: function (res) { obj.success && obj.success(res) }, fail: function (err) { obj.fail && obj.fail(err) }, }) successCallBack(obj) } function webviewLoadUrl(obj = {}) { const { url } = obj if (unique.isEmpty("url", url, obj)) { return } window.location.href = url successCallBack(obj) } // 获取原生导航信息 function getNavBarInfo(obj = {}) { let data = { isNativeNavBar: false, height: 0 } obj.success && obj.success(data) obj.complete && obj.complete(data) } function getNetworkType(obj = {}) { let type = "" if (navigator.onLine) { type = "wifi" } else { type = "none" } obj.success && obj.success({ networkType: type }) obj.complete && obj.complete({ networkType: type }) } function chooseVideo(obj = {}) { chooseImage(obj, true) } /** * 调用系统相机或相册, 6.2.14版本增加. * @param {array} sourceType 采集源(可选项). camera 相机, album 相册, ['album', 'camera'](默认) * @param {int} shootMode 拍摄模式(可选项). 0:拍照片+拍视频(默认); - 1:拍照片; - 2:拍视频 * @param {boolean} mirror 是否关闭自拍镜像,前置摄像头拍照时生效(可选项). (默认 false) * @param {int} count 最多可以选择的图片张数,仅从相册选择时有效,相机拍照只会返回一张(可选项). (默认 9) * @param {int} recordSecond 拍摄视频时的视频时长(可选项). (默认15s) * @param {boolean} isEditImage 拍照完成后是否显示画笔按钮,仅拍照模式下支持(可选项). (默认 true) * @param {boolean} isSaveToAlbum 拍照完成后是否保存到本地相册,仅拍照模式下支持(可选项). (默认 false) * @param {boolean} isSaveOriginal 拍照完成后保存相册照片是否带水印,仅拍照模式下支持(可选项). (默认 false) * @param {boolean} returnThumbnail 是否需要返回缩略图,watermark生效时,此参数无效,只返回带水印的路径(可选项). (默认 false) * @param {object} watermark 图片水印字符串,不传则不显示水印,仅图片支持水印设置 */ function chooseImages(obj) { const { count = 1, sourceType = ["album", "camera"], watermark } = obj let elementById = "mtlChooseImages" let input = document.getElementById(obj?.targetId || elementById) if (!input) { input = document.createElement("input") } input.type = "file" input.id = elementById input.name = elementById input.style.display = "none" // input.style.position = "absolute" // input.style.left = "-9999px" var targetElement = document.getElementById(obj?.targetId) if (targetElement) { targetElement && targetElement.appendChild(input) } else { document.body && document.body.appendChild(input) } // 限制文件类型. input.accept = obj?.accept || "image/*" if (sourceType.length === 1 && sourceType[0] === "camera") { input.capture = "camera" } else { try { input.removeAttribute("capture") } catch (error) { console.log("input.removeAttribute fail, err = ", error) } } if (count > 1) { input.multiple = "multiple" } // document.getElementById("mtlChooseImage").click(); // document.getElementById("mtlChooseImage").onchange=function(){ // input.click(); setTimeout(() => { input.dispatchEvent(new MouseEvent("click")) }, 50); if (isChooseImagesAddEventListener) { return } isChooseImagesAddEventListener = true input.addEventListener("change", function (event) { isChooseImagesAddEventListener = false var files = event?.target?.files; // 获取文件列表 if (files?.length === 0) { return } if (count > 1 && files.length > count) { input.remove() obj.fail && obj.fail({ code: "-1004", message: "You can only choose " + count + " files", }) return } var pictures = [] if (watermark && watermark != {}) { // 遍历图片 for (let index = 0; index < files.length; index++) { const element = files[index]; // 添加水印时需要转换 base64 fileToBase64(element).then(function (base64) { unique.addImageWaterMark({ image: base64, ...obj, success: (res) => { // 加完水印后转回file var file = unique.base64ToFile(res.image, element.name); pictures.push(file) if (index == files.length - 1) { input.remove() obj.success && obj.success({ pictures: pictures }) } }, fail: (err) => { obj?.fail && obj?.fail(err) } }) }).catch(function (error) { console.log(error); input.remove() obj?.fail && obj?.fail(error) }); } return } input.remove() obj.success && obj.success({ pictures: files }) }) } function chooseImage(obj = {}, isVideo = false) { const { count = 9, sourceType = ["album", "camera"], watermark } = obj let elementById = isVideo ? "mtlChooseVideo" : "mtlChooseImage" let input = document.getElementById(elementById) if (!input) { input = document.createElement("input") } input.type = "file" input.id = elementById input.name = elementById input.style.display = "none" // input.style.position = "absolute" // input.style.left = "-9999px" var targetElement = document.getElementById(obj?.targetId) if (targetElement) { targetElement && targetElement.appendChild(input) } else { document.body && document.body.appendChild(input) } if (!isVideo) { input.accept = obj?.accept || "image/*" } if (sourceType.length === 1 && sourceType[0] === "camera" && !isVideo) { input.capture = "camera" } else { try { input.removeAttribute("capture") } catch (error) { console.log("input.removeAttribute fail, err = ", error) } } if (count > 1) { input.multiple = "multiple" } // document.getElementById("mtlChooseImage").click(); // document.getElementById("mtlChooseImage").onchange=function(){ // input.click(); setTimeout(() => { input.dispatchEvent(new MouseEvent("click")) }, 50); if (isAddEventListener) { return } isAddEventListener = true input.addEventListener("change", function (event) { isAddEventListener = false var files = event.target?.files; // 获取文件列表 if (files?.length === 0) { return } if (count > 1 && files.length > count) { input.remove() obj.fail && obj.fail({ code: "-1004", message: "You can only choose " + count + " files", }) return } var base64IDs = [] var sizeFiles = [] // 将数据转换为base64 for (let index = 0; index < files.length; index++) { const element = files[index]; fileToBase64(element).then(function (base64) { base64IDs[index] = base64 sizeFiles[index] = element.size // 处理完最后一个后 if (index == files.length - 1) { let resData = { localIds: base64IDs, sizeFiles: sizeFiles, pictures: files, } input.remove() if (watermark && !isVideo) { unique.selectedImages({ ...obj, ...resData }) return } obj.success && obj.success(resData) } }).catch(function (error) { console.log(error); obj?.fail && obj?.fail(error) }); } }) } function fileToBase64(file) { return new Promise(function (resolve, reject) { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function (event) { resolve(event.target.result); }; reader.onerror = function (error) { reject(error); }; }); } function blobToBase64(index, files, sizeFiles, fileData, fn) { if (index === files.length) { fn({ files, sizeFiles, fileData }) } else { const element = files[index] const reader = new FileReader() reader.readAsDataURL(element) reader.onload = function (e) { const res = e.target.result files[index] = res sizeFiles[index] = element.size // base64 转 formdata fileData[index] = { file: element, fileName: element.name, fileType: element.type, fileSize: element.size, } blobToBase64(index + 1, files, sizeFiles, fileData, fn) } } } function getLocalImgData(obj = {}) { var { localId } = obj if (localId) { if (localId.indexOf("\n") != -1 || localId.indexOf("\r") != -1 || localId.indexOf(" ") != -1) { // 包含\n,可以直接替换, 解决android机器base64编码后带有\n问题 localId = localId.replace(/(\r\n)|(\n)|(\s)/g, "") } obj.success && obj.success({ localData: localId }) obj.complete && obj.complete({ localData: localId }) } else { obj.fail && obj.fail({ code: FAIL_CODE, message: "no found localId", }) } } function getUserInfo(obj = {}) { mtl.getStorage({ key: "USER_ID", success: function (res) { obj.success && obj.success({ userId: res.data }) obj.complete && obj.complete({ data: res, code: 200 }) }, fail: function (err) { obj.fail && obj.fail(err) obj.complete && obj.complete(err) }, }) } let exports = { upesn: home.upesn, chooseImage, chooseVideo, chooseImages, getLocalImgData, getNetworkType, generateQRCode, scanInvoice, recognizeInvoice, scanIDCard, recognizeIDCard, scanBankCard, recognizeBankCard, request, setStorage, getStorage, removeStorage, clearStorage, navigateTo, redirectTo, navigateBack, reLaunch, openLocation, getLocation, scanQRCode, getConfig, openNewWebview, closeCurrentWebview, openExclusiveApp, webviewLoadUrl, getNavBarInfo, getUserInfo, downloadFile: home.upesn.downloadFile, mdfCustomScanQRCode: home.upesn.mdfCustomScanQRCode, mdfChangeCustomScanMode: home.upesn.mdfChangeCustomScanMode, mdfChangeFlashLightStatus: home.upesn.mdfChangeFlashLightStatus, dail: home.upesn.dail, settingNavBar: home.upesn.settingNavBar, voiceToText: home.upesn.voiceToText, getBlueToothState: home.upesn.getBlueToothState, blueToothConnectState: home.upesn.blueToothConnectState, blueToothConnect: home.upesn.blueToothConnect, blueToothPrint: home.upesn.blueToothPrint, blueToothDisConnect: home.upesn.blueToothDisConnect, blueToothScan: home.upesn.blueToothScan, blueToothStopScan: home.upesn.blueToothStopScan, rfidConnect: home.upesn.rfidConnect, rfidDisconnect: home.upesn.rfidDisconnect, setAppletCapsuleStyle: home.upesn.setAppletCapsuleStyle, getAppletCapsuleParams: home.upesn.getAppletCapsuleParams, setStatusBarStyle: home.upesn.setStatusBarStyle, openChatWindow: home.upesn.openChatWindow, chooseDocFiles: home.upesn.chooseDocFiles, chooseLocalFileToServer: home.upesn.chooseLocalFileToServer, chooseVideoToServer: home.upesn.chooseVideoToServer, sendTodoReceipt: home.upesn.sendTodoReceipt, getAppInfomation: home.upesn.getAppInfomation, backToHome: home.upesn.backToHome, chooseImageToServer: home.upesn.chooseImageToServer, getUserYHTInfo: home.upesn.getUserYHTInfo, setUserYHTInfo: home.upesn.setUserYHTInfo, getToken: home.upesn.getToken, gainUserInfo: home.upesn.gainUserInfo, uploadFile: home.upesn.uploadFile, uploadToFileService: home.upesn.uploadToFileService, wpsPreview: home.upesn.wpsPreview, previewDoc: home.upesn.previewDoc, previewFile: home.upesn.previewFile, getAppData: home.upesn.getAppData, chooseLocalFiles: unique.chooseLocalFiles, onNetworkStatusChange: unique.onNetworkStatusChange, openAppWithParams: unique.openAppWithParams, getAppletShareParams: unique.getAppletShareParams, getSystemInfo: unique.getSystemInfo, getClipboardData: unique.getClipboardData, setClipboardData: unique.setClipboardData, watchShake: unique.watchShake, vibrateOnce: unique.vibrateOnce, saveExclusiveDomain: unique.saveExclusiveDomain, saveExclusiveUserInfo: unique.saveExclusiveUserInfo, saveExclusiveYhtInfo: unique.saveExclusiveYhtInfo, getExclusiveCode: unique.getExclusiveCode, setExclusiveLanguage: unique.setExclusiveLanguage, addImageWaterMark: unique.addImageWaterMark, mtlContext: unique.mtlContext, checkBridgeNameExist: unique.checkBridgeNameExist, canExecUpesnBridge: unique.canExecUpesnBridge, } unsupportMethods.forEach((prop) => { exports[prop] = unsupportMethodIMP }) supportMethods.forEach((pop) => { if (!exports[pop]) { if (pop === "chooseLibraryFiles" || pop === "chooseContacts" || pop === "chooseDepartment") { exports[pop] = successCallBackArray } else { exports[pop] = successCallBack } } }) export default exports