This commit is contained in:
Your Name
2026-03-11 09:49:47 +08:00
parent 02ae537b4c
commit 38ad60f4bb
290 changed files with 36917 additions and 123 deletions
@@ -0,0 +1,162 @@
import type { func } from '../type';
export const isUndefined = function (input: any) {
return typeof input === 'undefined';
};
export const isPlainObject = function (input: any) {
// 注意不能使用以下方式判断,因为IE9/IE10下,对象的__proto__是 undefined
// return isObject(input) && input.__proto__ === Object.prototype;
if (typeof input !== 'object' || input === null) {
return false;
}
const proto = Object.getPrototypeOf(input);
if (proto === null) { // edge case Object.create(null)
return true;
}
let baseProto = proto;
while (Object.getPrototypeOf(baseProto) !== null) {
baseProto = Object.getPrototypeOf(baseProto);
}
// 原型链第一个和最后一个比较
return proto === baseProto;
};
export const isArray = function (input: any) {
if (typeof Array.isArray === 'function') {
return Array.isArray(input);
}
return (Object as any).prototype.toString.call(input).match(/^\[object (.*)\]$/)[1].toLowerCase() === 'array';
};
export const isPrivateKey = function (key: string) {
return key.startsWith('_');
};
export const isUrl = function (url: string) {
return /^(https?:\/\/(([a-zA-Z0-9]+-?)+[a-zA-Z0-9]+\.)+[a-zA-Z]+)(:\d+)?(\/.*)?(\?.*)?(#.*)?$/.test(url);
};
export const calculateTimeAgo = function (dateTimeStamp: number, t: func): string {
const minute = 1000 * 60;
const hour = minute * 60;
const day = hour * 24;
const week = day * 7;
const now = new Date().getTime();
const diffValue = now - dateTimeStamp;
let result = '';
if (diffValue < 0) {
return result;
}
const minC = diffValue / minute;
const hourC = diffValue / hour;
const dayC = diffValue / day;
const weekC = diffValue / week;
if (weekC >= 1 && weekC <= 4) {
result = ` ${parseInt(`${weekC}`, 10)} ${t('time.周')}${t('time.前')}`;
} else if (dayC >= 1 && dayC <= 6) {
result = ` ${parseInt(`${dayC}`, 10)} ${t('time.天')}${t('time.前')}`;
} else if (hourC >= 1 && hourC <= 23) {
result = ` ${parseInt(`${hourC}`, 10)} ${t('time.小时')}${t('time.前')}`;
} else if (minC >= 1 && minC <= 59) {
result = ` ${parseInt(`${minC}`, 10)} ${t('time.分钟')}${t('time.前')}`;
} else if (diffValue >= 0 && diffValue <= minute) {
result = `${t('time.刚刚')}`;
} else {
const dateTime = new Date();
dateTime.setTime(dateTimeStamp);
const _year = dateTime.getFullYear();
const _month = dateTime.getMonth() + 1 < 10 ? `0${dateTime.getMonth() + 1}` : dateTime.getMonth() + 1;
const _date = dateTime.getDate() < 10 ? `0${dateTime.getDate()}` : dateTime.getDate();
result = `${_year}-${_month}-${_date}`;
}
return result;
};
export function formatTime(secondTime: number) {
const time: number = secondTime;
let newTime = '';
let hour: number | string;
let minute: number | string;
let seconds: any;
if (time >= 3600) {
hour = parseInt(`${time / 3600}`, 10) < 10 ? `0${parseInt(`${time / 3600}`, 10)}` : parseInt(`${time / 3600}`, 10);
minute = parseInt(`${(time % 60) / 60}`, 10) < 10 ? `0${parseInt(`${(time % 60) / 60}`, 10)}` : parseInt(`${(time % 60) / 60}`, 10);
seconds = time % 3600 < 10 ? `0${time % 3600}` : time % 3600;
if (seconds > 60) {
minute = parseInt(`${seconds / 60}`, 10) < 10 ? `0${parseInt(`${seconds / 60}`, 10)}` : parseInt(`${seconds / 60}`, 10);
seconds = seconds % 60 < 10 ? `0${seconds % 60}` : seconds % 60;
}
newTime = `${hour}:${minute}:${seconds}`;
} else if (time >= 60 && time < 3600) {
minute = parseInt(`${time / 60}`, 10) < 10 ? `0${parseInt(`${time / 60}`, 10)}` : parseInt(`${time / 60}`, 10);
seconds = time % 60 < 10 ? `0${time % 60}` : time % 60;
newTime = `00:${minute}:${seconds}`;
} else if (time < 60) {
seconds = time < 10 ? `0${time}` : time;
newTime = `00:00:${seconds}`;
}
return newTime;
}
// Determine if it is a JSON string
export function isJSON(str: string) {
if (typeof str === 'string') {
try {
const data = JSON.parse(str);
if (data) {
return true;
}
return false;
} catch (error) {
return false;
}
}
return false;
}
// Determine if it is a JSON string
export const JSONToObject = function (str: string) {
if (!str || !isJSON(str)) {
return str;
}
return JSON.parse(str);
};
// formate file size
export const formateFileSize = function (fileSize: number) {
let ret = '';
if (fileSize >= 1024 * 1024) {
ret = `${(fileSize / (1024 * 1024)).toFixed(2)} Mb`;
} else if (fileSize >= 1024) {
ret = `${(fileSize / 1024).toFixed(2)} Kb`;
} else {
ret = `${fileSize.toFixed(2)}B`;
}
return ret;
};
/**
* 重试函数, catch 时,重试
*
* @param {Promise} promise 需重试的函数
* @param {number} num 需要重试的次数
* @param {number} time 间隔时间(s
* @returns {Promise<any>} im 接口的 response 原样返回
*/
export const retryPromise = (promise: Promise<any>, num = 6, time = 0.5) => {
let n = num;
const func = () => promise;
return func()
.catch((error: any) => {
if (n === 0) {
throw error;
}
const timer = setTimeout(() => {
func();
clearTimeout(timer);
n--;
}, time * 1000);
});
};
@@ -0,0 +1,65 @@
declare const wx: any;
declare const qq: any;
declare const tt: any;
declare const swan: any;
declare const my: any;
declare const jd: any;
declare const uni: any;
declare const window: any;
export const IN_WX_MINI_APP_DESK = (typeof wx !== 'undefined' && typeof wx.getSystemInfoSync === 'function' && (wx.getSystemInfoSync().platform === 'mac' || wx.getSystemInfoSync().platform === 'windows'));
export const IN_WX_MINI_APP = (typeof wx !== 'undefined' && typeof wx.getSystemInfoSync === 'function' && Boolean(wx.getSystemInfoSync().fontSizeSetting)) || IN_WX_MINI_APP_DESK;
export const IN_QQ_MINI_APP = (typeof qq !== 'undefined' && typeof qq.getSystemInfoSync === 'function' && Boolean(qq.getSystemInfoSync().fontSizeSetting));
export const IN_TT_MINI_APP = (typeof tt !== 'undefined' && typeof tt.getSystemInfoSync === 'function' && Boolean(tt.getSystemInfoSync().fontSizeSetting));
export const IN_BAIDU_MINI_APP = (typeof swan !== 'undefined' && typeof swan.getSystemInfoSync === 'function' && Boolean(swan.getSystemInfoSync().fontSizeSetting));
export const IN_ALIPAY_MINI_APP = (typeof my !== 'undefined' && typeof my.getSystemInfoSync === 'function' && Boolean(my.getSystemInfoSync().fontSizeSetting));
export const IN_JD_MINI_APP = (typeof jd !== 'undefined' && typeof jd.getSystemInfoSync === 'function');
export const IN_UNI_NATIVE_APP = (typeof uni !== 'undefined' && typeof window === 'undefined');
// eslint-disable-next-line @stylistic/max-len
export const IN_MINI_APP = IN_WX_MINI_APP || IN_QQ_MINI_APP || IN_TT_MINI_APP || IN_BAIDU_MINI_APP || IN_ALIPAY_MINI_APP || IN_JD_MINI_APP || IN_UNI_NATIVE_APP;
export const IN_UNI_APP = (typeof uni !== 'undefined');
export const IN_BROWSER = (function () {
if (typeof uni !== 'undefined') {
return !IN_MINI_APP;
}
return (typeof window !== 'undefined') && !IN_MINI_APP;
})();
// runtime env
export const APP_NAMESPACE = (() => {
if (IN_QQ_MINI_APP) {
return qq;
}
if (IN_TT_MINI_APP) {
return tt;
}
if (IN_BAIDU_MINI_APP) {
return swan;
}
if (IN_ALIPAY_MINI_APP) {
return my;
}
if (IN_WX_MINI_APP) {
return wx;
}
if (IN_UNI_NATIVE_APP) {
return uni;
}
if (IN_JD_MINI_APP) {
return jd;
}
if (IN_BROWSER) {
return window;
}
return {};
})();
const USER_AGENT = (IN_BROWSER && window && window.navigator && window.navigator.userAgent) || '';
const IS_ANDROID = /Android/i.test(USER_AGENT);
const IS_WIN_PHONE = /(?:Windows Phone)/.test(USER_AGENT);
const IS_SYMBIAN = /(?:SymbianOS)/.test(USER_AGENT);
const IS_IOS = /iPad/i.test(USER_AGENT) || /iPhone/i.test(USER_AGENT) || /iPod/i.test(USER_AGENT);
export const IS_H5 = IS_ANDROID || IS_WIN_PHONE || IS_SYMBIAN || IS_IOS;
export const IS_PC = IN_BROWSER && !IS_H5;
@@ -0,0 +1,30 @@
import { isPlainObject } from './common-utils';
const isEmpty = function (input: any) {
// Null and Undefined...
if (input === null || typeof (input) === 'undefined') return true;
// Booleans...
if (typeof input === 'boolean') return false;
// Numbers...
if (typeof input === 'number') return input === 0;
// Strings...
if (typeof input === 'string') return input.length === 0;
// Functions...
if (typeof input === 'function') return input.length === 0;
// Arrays...
if (Array.isArray(input)) return input.length === 0;
// Errors...
if (input instanceof Error) return input.message === '';
// plain object
if (isPlainObject(input)) {
for (const key in input) {
if (Object.prototype.hasOwnProperty.call(input, key)) {
return false;
}
}
return true;
}
return false;
};
export default isEmpty;
@@ -0,0 +1,40 @@
import type { func } from '../type';
class Middleware {
private cache: func[];
private middlewares: func[];
private options: any;
constructor() {
this.cache = [];
this.middlewares = [];
this.options = null; // 缓存options
}
use(fn: func) {
if (typeof fn !== 'function') {
console.error('middleware must be a function');
}
this.cache.push(fn);
return this;
}
next(): any {
if (this.middlewares && this.middlewares.length > 0) {
const ware: any = this.middlewares.shift();
return ware.call(this, this.options, this.next.bind(this));
}
return undefined;
}
/**
* @param {any} options - 数据的入口
* @returns {Function}
*/
run(options: any): any {
this.middlewares = this.cache.map(fn => fn);
this.options = options; // 缓存数据
return this.next();
}
}
export default Middleware;
@@ -0,0 +1,85 @@
import { IN_MINI_APP, APP_NAMESPACE } from './env';
/**
* storage 中写入一条数据。若key已存在,则会覆盖已有数据。
* @param {String} key - 缓存的key
* @param {*} value - 任何可JSON序列化的数据
* @param {Boolean} withPrefix 是否需要拼接 prefix 和 key,默认为 true,即需要拼接。
*/
export function setStorageItem(key: string, value: any, withPrefix = true) {
const realKey = withPrefix ? _getKey(key) : key;
_setStorageSync(realKey, value);
}
/**
* 获取storage中的一条数据
* @param {String} key - 缓存的key
* @param {Boolean} withPrefix 是否需要拼接 prefix 和 key,默认为 true,即需要拼接。
* @returns {any} 返回指定key的数据
*/
export function getStorageItem(key: string, withPrefix = true): any {
try {
const realKey: string = withPrefix ? _getKey(key) : key;
return _getStorageSync(realKey);
} catch (error) {
console.warn('Storage.getStorageItem error:', error);
return undefined;
}
}
/**
* 删除指定key的数据
* @param {String} key - 缓存的key
* @param {Boolean} withPrefix 是否需要拼接 prefix 和 key,默认为 true,即需要拼接。
*/
export function removeStorageItem(key: string, withPrefix = true) {
try {
const realKey = withPrefix ? _getKey(key) : key;
_removeStorageSync(realKey);
} catch (error) {
console.warn('Storage.removeStorageItem error:', error);
}
}
function _setStorageSync(key: string, data: string) {
if (IN_MINI_APP) {
APP_NAMESPACE.setStorageSync(key, data);
} else if (_canIUseCookies()) {
localStorage.setItem(key, JSON.stringify(data));
}
}
function _getStorageSync(key: string): any {
if (IN_MINI_APP) {
return APP_NAMESPACE.getStorageSync(key);
}
if (_canIUseCookies()) {
const data: any = localStorage.getItem(key);
if (data !== 'undefined') {
return JSON.parse(data);
}
}
return undefined;
}
function _removeStorageSync(key: string) {
if (IN_MINI_APP) {
APP_NAMESPACE.removeStorageSync(key);
} else if (_canIUseCookies()) {
localStorage.removeItem(key);
}
}
function _getKey(key: string) {
return `chat_engine_${key}`;
}
// 如果用户选择 block cookies,此时访问 localStorage 浏览器会抛错
// Uncaught SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document
// 通过 navigator.cookieEnabled 短路逻辑规避
function _canIUseCookies() {
// When the browser is configured to block third-party cookies, and navigator.cookieEnabled is invoked inside a third-party iframe,
// it returns true in Safari, Edge Spartan and IE (while trying to set a cookie in such scenario would fail).
// It returns false in Firefox and Chromium-based browsers.
return navigator && navigator.cookieEnabled && localStorage;
}
@@ -0,0 +1,35 @@
/* eslint-disable prefer-rest-params */
import type { ITUIChatEngine } from '../interface/engine';
import Middleware from './middleware';
import { ERROR_CODE_ENGINE, ERROR_MSG_ENGINE } from '../const';
export default function validateInitialization(
TUIChatEngine: ITUIChatEngine,
target: any,
APIList: object,
) {
const obj = Object.create(null);
Object.keys(APIList).forEach((api) => {
if (!target[api]) {
return;
}
obj[api] = target[api];
const validateMiddleware = new Middleware();
target[api] = function () {
const args = Array.from(arguments);
validateMiddleware
.use((options: any, next: any) => {
if (TUIChatEngine.isInited) {
return next();
}
return Promise.reject({
code: ERROR_CODE_ENGINE.NOT_INIT,
message: `${api} | ${ERROR_MSG_ENGINE.NOT_INIT}`,
});
})
.use((options: any) => obj[api].apply(target, options));
return validateMiddleware.run(args);
};
});
}