|
|
function batchFindObjctValue (obj = {}, keys = []) {
|
|
|
const values = {}
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
const key = keys[i]
|
|
|
const keyPath = key.split('.')
|
|
|
let currentKey = keyPath.shift()
|
|
|
let result = obj
|
|
|
while (currentKey) {
|
|
|
if (!result) {
|
|
|
break
|
|
|
}
|
|
|
result = result[currentKey]
|
|
|
currentKey = keyPath.shift()
|
|
|
}
|
|
|
values[key] = result
|
|
|
}
|
|
|
return values
|
|
|
}
|
|
|
|
|
|
function getType (val) {
|
|
|
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase()
|
|
|
}
|
|
|
|
|
|
function hasOwn (obj, key) {
|
|
|
return Object.prototype.hasOwnProperty.call(obj, key)
|
|
|
}
|
|
|
|
|
|
function isValidString (val) {
|
|
|
return val && getType(val) === 'string'
|
|
|
}
|
|
|
|
|
|
function isPlainObject (obj) {
|
|
|
return getType(obj) === 'object'
|
|
|
}
|
|
|
|
|
|
function isFn (fn) {
|
|
|
// 务必注意AsyncFunction
|
|
|
return typeof fn === 'function'
|
|
|
}
|
|
|
|
|
|
// 获取文件后缀,只添加几种图片类型供客服消息接口使用
|
|
|
const mime2ext = {
|
|
|
'image/png': 'png',
|
|
|
'image/jpeg': 'jpg',
|
|
|
'image/gif': 'gif',
|
|
|
'image/svg+xml': 'svg',
|
|
|
'image/bmp': 'bmp',
|
|
|
'image/webp': 'webp'
|
|
|
}
|
|
|
|
|
|
function getExtension (contentType) {
|
|
|
return mime2ext[contentType]
|
|
|
}
|
|
|
|
|
|
const isSnakeCase = /_(\w)/g
|
|
|
const isCamelCase = /[A-Z]/g
|
|
|
|
|
|
function snake2camel (value) {
|
|
|
return value.replace(isSnakeCase, (_, c) => (c ? c.toUpperCase() : ''))
|
|
|
}
|
|
|
|
|
|
function camel2snake (value) {
|
|
|
return value.replace(isCamelCase, str => '_' + str.toLowerCase())
|
|
|
}
|
|
|
|
|
|
function parseObjectKeys (obj, type) {
|
|
|
let parserReg, parser
|
|
|
switch (type) {
|
|
|
case 'snake2camel':
|
|
|
parser = snake2camel
|
|
|
parserReg = isSnakeCase
|
|
|
break
|
|
|
case 'camel2snake':
|
|
|
parser = camel2snake
|
|
|
parserReg = isCamelCase
|
|
|
break
|
|
|
}
|
|
|
for (const key in obj) {
|
|
|
if (hasOwn(obj, key)) {
|
|
|
if (parserReg.test(key)) {
|
|
|
const keyCopy = parser(key)
|
|
|
obj[keyCopy] = obj[key]
|
|
|
delete obj[key]
|
|
|
if (isPlainObject(obj[keyCopy])) {
|
|
|
obj[keyCopy] = parseObjectKeys(obj[keyCopy], type)
|
|
|
} else if (Array.isArray(obj[keyCopy])) {
|
|
|
obj[keyCopy] = obj[keyCopy].map((item) => {
|
|
|
return parseObjectKeys(item, type)
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return obj
|
|
|
}
|
|
|
|
|
|
function snake2camelJson (obj) {
|
|
|
return parseObjectKeys(obj, 'snake2camel')
|
|
|
}
|
|
|
|
|
|
function camel2snakeJson (obj) {
|
|
|
return parseObjectKeys(obj, 'camel2snake')
|
|
|
}
|
|
|
|
|
|
function getOffsetDate (offset) {
|
|
|
return new Date(
|
|
|
Date.now() + (new Date().getTimezoneOffset() + (offset || 0) * 60) * 60000
|
|
|
)
|
|
|
}
|
|
|
|
|
|
function getDateStr (date, separator = '-') {
|
|
|
date = date || new Date()
|
|
|
const dateArr = []
|
|
|
dateArr.push(date.getFullYear())
|
|
|
dateArr.push(('00' + (date.getMonth() + 1)).substr(-2))
|
|
|
dateArr.push(('00' + date.getDate()).substr(-2))
|
|
|
return dateArr.join(separator)
|
|
|
}
|
|
|
|
|
|
function getTimeStr (date, separator = ':') {
|
|
|
date = date || new Date()
|
|
|
const timeArr = []
|
|
|
timeArr.push(('00' + date.getHours()).substr(-2))
|
|
|
timeArr.push(('00' + date.getMinutes()).substr(-2))
|
|
|
timeArr.push(('00' + date.getSeconds()).substr(-2))
|
|
|
return timeArr.join(separator)
|
|
|
}
|
|
|
|
|
|
function getFullTimeStr (date) {
|
|
|
date = date || new Date()
|
|
|
return getDateStr(date) + ' ' + getTimeStr(date)
|
|
|
}
|
|
|
|
|
|
function getDistinctArray (arr) {
|
|
|
return Array.from(new Set(arr))
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 拼接url
|
|
|
* @param {string} base 基础路径
|
|
|
* @param {string} path 在基础路径上拼接的路径
|
|
|
* @returns
|
|
|
*/
|
|
|
function resolveUrl (base, path) {
|
|
|
if (/^https?:/.test(path)) {
|
|
|
return path
|
|
|
}
|
|
|
return base + path
|
|
|
}
|
|
|
|
|
|
function getVerifyCode (len = 6) {
|
|
|
let code = ''
|
|
|
for (let i = 0; i < len; i++) {
|
|
|
code += Math.floor(Math.random() * 10)
|
|
|
}
|
|
|
return code
|
|
|
}
|
|
|
|
|
|
function coverMobile (mobile) {
|
|
|
if (typeof mobile !== 'string') {
|
|
|
return mobile
|
|
|
}
|
|
|
return mobile.slice(0, 3) + '****' + mobile.slice(7)
|
|
|
}
|
|
|
|
|
|
function getNonceStr (length = 16) {
|
|
|
let str = ''
|
|
|
while (str.length < length) {
|
|
|
str += Math.random().toString(32).substring(2)
|
|
|
}
|
|
|
return str.substring(0, length)
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
require('lodash.merge')
|
|
|
} catch (error) {
|
|
|
console.error('uni-id-co缺少依赖,请在uniCloud/cloudfunctions/uni-id-co目录执行 npm install 安装依赖')
|
|
|
throw error
|
|
|
}
|
|
|
|
|
|
function isMatchUserApp (userAppList, matchAppList) {
|
|
|
if (userAppList === undefined || userAppList === null) {
|
|
|
return true
|
|
|
}
|
|
|
if (getType(userAppList) !== 'array') {
|
|
|
return false
|
|
|
}
|
|
|
if (userAppList.includes('*')) {
|
|
|
return true
|
|
|
}
|
|
|
if (getType(matchAppList) === 'string') {
|
|
|
matchAppList = [matchAppList]
|
|
|
}
|
|
|
return userAppList.some(item => matchAppList.includes(item))
|
|
|
}
|
|
|
|
|
|
function checkIdCard (idCardNumber) {
|
|
|
if (!idCardNumber || typeof idCardNumber !== 'string' || idCardNumber.length !== 18) return false
|
|
|
|
|
|
const coefficient = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
|
|
|
const checkCode = [1, 0, 'x', 9, 8, 7, 6, 5, 4, 3, 2]
|
|
|
const code = idCardNumber.substring(17)
|
|
|
|
|
|
let sum = 0
|
|
|
for (let i = 0; i < 17; i++) {
|
|
|
sum += Number(idCardNumber.charAt(i)) * coefficient[i]
|
|
|
}
|
|
|
|
|
|
return checkCode[sum % 11].toString() === code.toLowerCase()
|
|
|
}
|
|
|
|
|
|
function catchAwait (fn, finallyFn) {
|
|
|
if (!fn) return [new Error('no function')]
|
|
|
|
|
|
if (Promise.prototype.finally === undefined) {
|
|
|
// eslint-disable-next-line no-extend-native
|
|
|
Promise.prototype.finally = function (finallyFn) {
|
|
|
return this.then(
|
|
|
res => Promise.resolve(finallyFn()).then(() => res),
|
|
|
error => Promise.resolve(finallyFn()).then(() => { throw error })
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return fn
|
|
|
.then((data) => [undefined, data])
|
|
|
.catch((error) => [error])
|
|
|
.finally(() => typeof finallyFn === 'function' && finallyFn())
|
|
|
}
|
|
|
|
|
|
function dataDesensitization (value = '', options = {}) {
|
|
|
const { onlyLast = false } = options
|
|
|
const [firstIndex, middleIndex, lastIndex] = onlyLast ? [0, 0, -1] : [0, 1, -1]
|
|
|
|
|
|
if (!value) return value
|
|
|
const first = value.slice(firstIndex, middleIndex)
|
|
|
const middle = value.slice(middleIndex, lastIndex)
|
|
|
const last = value.slice(lastIndex)
|
|
|
const star = Array.from(new Array(middle.length), (v) => '*').join('')
|
|
|
|
|
|
return first + star + last
|
|
|
}
|
|
|
|
|
|
function getCurrentDateTimestamp (date = Date.now(), targetTimezone = 8) {
|
|
|
const oneHour = 60 * 60 * 1000
|
|
|
return parseInt((date + targetTimezone * oneHour) / (24 * oneHour)) * (24 * oneHour) - targetTimezone * oneHour
|
|
|
}
|
|
|
|
|
|
module.exports = {
|
|
|
getType,
|
|
|
isValidString,
|
|
|
batchFindObjctValue,
|
|
|
isPlainObject,
|
|
|
isFn,
|
|
|
getDistinctArray,
|
|
|
getFullTimeStr,
|
|
|
resolveUrl,
|
|
|
getOffsetDate,
|
|
|
camel2snakeJson,
|
|
|
snake2camelJson,
|
|
|
getExtension,
|
|
|
getVerifyCode,
|
|
|
coverMobile,
|
|
|
getNonceStr,
|
|
|
isMatchUserApp,
|
|
|
checkIdCard,
|
|
|
catchAwait,
|
|
|
dataDesensitization,
|
|
|
getCurrentDateTimestamp
|
|
|
}
|