ToolsHelper.ets 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. import promptAction from '@ohos.promptAction';
  2. import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
  3. import { buffer, HashMap, util } from '@kit.ArkTS';
  4. import { DeviceInfo } from '../bean/DeviceInfo';
  5. import { common } from '@kit.AbilityKit';
  6. import { md5_hex } from '../util/md5';
  7. import { GlobalContext, LogHelper } from '../../../../Index';
  8. import { ComponentContent } from '@kit.ArkUI';
  9. export class AlertBean {
  10. options: ConfirmOptions
  11. dialogTag: string
  12. constructor(options: ConfirmOptions, dialogTag: string) {
  13. this.options = options
  14. this.dialogTag = dialogTag
  15. }
  16. }
  17. export interface Btn {
  18. text?: string | Resource;
  19. color?: string | Resource;
  20. bgColor?: string | Resource;
  21. onClick?: () => void
  22. }
  23. export interface AlertOptions {
  24. title?: string,
  25. msg?: string,
  26. action?: Btn
  27. }
  28. export interface ConfirmOptions {
  29. title?: string
  30. msg?: string
  31. confirm?: Btn
  32. cancel?: Btn
  33. autoCancel?: boolean
  34. }
  35. export interface ListOptions<T> {
  36. title?: string
  37. cancel?: Btn
  38. autoCancel?: boolean
  39. index?: number
  40. alignment?: DialogAlignment
  41. values: Array<T>
  42. onSelected: (index: number, value: T) => void
  43. onError?: (msg: string) => void
  44. }
  45. interface ListItem {
  46. content: string
  47. }
  48. @Builder
  49. function customDialogBuilder<T>(option: ListOptions<T>, dialogTag: string) {
  50. Column() {
  51. Text(option.title)
  52. .fontSize(16)
  53. .fontColor('#00BE87')
  54. .textAlign(TextAlign.Center)
  55. .width('100%')
  56. .height(60)
  57. .backgroundColor('#F0FFFA')
  58. .borderRadius({
  59. topLeft: 10,
  60. topRight: 10
  61. })
  62. .visibility(option.title ? Visibility.Visible : Visibility.None)
  63. Column() {
  64. List() {
  65. ForEach(option.values, (item: T, index: number) => {
  66. ListItem() {
  67. Row() {
  68. Text(typeof item === "string" ? item : (item as ListItem).content)
  69. .fontSize(option.index === index ? 16 : 14)
  70. .fontWeight(option.index === index ? FontWeight.Bold : FontWeight.Normal)
  71. .maxLines(1)
  72. .width('70%')
  73. .ellipsisMode(EllipsisMode.CENTER)
  74. .textOverflow({
  75. overflow: TextOverflow.Ellipsis
  76. })
  77. .textAlign(TextAlign.Center)
  78. .align(Alignment.Center)
  79. .fontColor('#11102C')
  80. }
  81. .alignItems(VerticalAlign.Center)
  82. .justifyContent(FlexAlign.Center)
  83. .height(60)
  84. .width('100%')
  85. .onClick(() => {
  86. if (ToolsHelper.mapDialog.get(dialogTag)) {
  87. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  88. ToolsHelper.mapDialog.remove(dialogTag)
  89. }
  90. option.onSelected(index, item)
  91. })
  92. }
  93. }, (item: T) => typeof item === "string" ? item : (item as ListItem).content)
  94. }
  95. .listDirection(Axis.Vertical) // 排列方向
  96. .scrollBar(BarState.Off)
  97. .friction(0.6)
  98. .divider({
  99. strokeWidth: 1,
  100. color: '#F6F6F6',
  101. }) // 每行之间的分界线
  102. .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
  103. .width('100%')
  104. .height(option.values === undefined ? '20%' : option.values.length < 5 ? option.values.length * 60 : 300)
  105. if (option.cancel) {
  106. Column() {
  107. Text(option.cancel.text ?? '取消')
  108. .fontSize(16)
  109. .fontColor(option.cancel.color ?? '#777777')
  110. .textAlign(TextAlign.Center)
  111. .width(325)
  112. .height(44)
  113. .backgroundColor('white')
  114. .borderRadius(22)
  115. .borderWidth(1)
  116. .borderColor('#D7D7D7')
  117. }
  118. .onClick(() => {
  119. if (ToolsHelper.mapDialog.get(dialogTag)) {
  120. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  121. ToolsHelper.mapDialog.remove(dialogTag)
  122. }
  123. option.cancel?.onClick && option.cancel.onClick()
  124. })
  125. .height(71)
  126. .width('100%')
  127. .alignItems(HorizontalAlign.Center)
  128. .justifyContent(FlexAlign.Center)
  129. }
  130. }.justifyContent(FlexAlign.End)
  131. }.justifyContent(FlexAlign.Start)
  132. }
  133. @Builder
  134. function alertDialogBuilder(options: AlertBean) {
  135. Column() {
  136. Row() {
  137. Image($r('app.media.dialog_confirm_close'))
  138. .width(17)
  139. .height(17)
  140. .visibility(options.options.cancel ? Visibility.Hidden : Visibility.None)
  141. Text(options.options.title ? !options.options.msg ? '提示' : options.options.title : '提示')
  142. .fontSize(16)
  143. .fontColor($r('sys.color.black'))
  144. .textAlign(TextAlign.Center)
  145. .layoutWeight(1)
  146. .height('100%')
  147. .fontWeight(FontWeight.Bold)
  148. .maxLines(1)
  149. .padding({
  150. left: 20,
  151. right: 20
  152. })
  153. .ellipsisMode(EllipsisMode.CENTER)
  154. .textOverflow({
  155. overflow: TextOverflow.Ellipsis
  156. })
  157. Image($r('app.media.dialog_confirm_close'))
  158. .width(17)
  159. .height(17)
  160. .visibility(options.options.cancel ? Visibility.Visible : Visibility.None)
  161. .onClick(() => {
  162. options.options.cancel?.onClick && options.options.cancel.onClick()
  163. ToolsHelper.closeAlertDialog(options.dialogTag)
  164. })
  165. }
  166. .width('100%')
  167. .height(60)
  168. .justifyContent(FlexAlign.SpaceBetween)
  169. .alignItems(VerticalAlign.Top)
  170. .padding(9)
  171. Scroll() {
  172. Text(options.options.msg ?? options.options.title)
  173. .fontSize(14)
  174. .fontWeight(FontWeight.Medium)
  175. .fontColor($r('sys.color.black'))
  176. .textAlign(TextAlign.Center)
  177. .lineHeight(20)
  178. .padding({
  179. left: 19,
  180. right: 19
  181. })
  182. .width('100%')
  183. }.scrollable(ScrollDirection.Vertical)
  184. .constraintSize({
  185. maxHeight: 220
  186. })
  187. Text(options.options.confirm?.text ?? '确定')
  188. .fontSize(14)
  189. .fontWeight(FontWeight.Medium)
  190. .fontColor($r('sys.color.white'))
  191. .textAlign(TextAlign.Center)
  192. .margin({
  193. top: 40,
  194. bottom: 40,
  195. left: 18,
  196. right: 18
  197. })
  198. .width(215)
  199. .backgroundColor('#0E84FA')
  200. .borderRadius(5)
  201. .height(34)
  202. .onClick(() => {
  203. options.options.confirm?.onClick && options.options.confirm.onClick()
  204. ToolsHelper.closeAlertDialog(options.dialogTag)
  205. })
  206. }
  207. .width('66%')
  208. .borderRadius(5)
  209. .justifyContent(FlexAlign.Start)
  210. .constraintSize({
  211. minHeight: 194
  212. })
  213. .linearGradient({
  214. // 0点方向顺时针旋转为正向角度,线性渐变起始角度的默认值为180°
  215. colors: [
  216. [0xE6F6FA, 0], // 颜色断点1的颜色和比重,对应组件在180°方向上的起始位置
  217. [0xffffff, 1.0],// 颜色断点2的颜色和比重,对应组件在180°方向上的终点位置
  218. ]
  219. })
  220. }
  221. interface ThrottleInterface {
  222. startTime: number; //调用的时间
  223. timeoutNumber: number; //setTimeout的句柄
  224. }
  225. /**
  226. * 常用方法
  227. */
  228. export class ToolsHelper {
  229. private constructor() {
  230. }
  231. /**
  232. * 弹出Toast
  233. * @param msg
  234. */
  235. static log(...args: ESObject[]) {
  236. const k = ToolsHelper.getStackKey()?.split('/')
  237. LogHelper.info(`${k ? k[k.length-1].split('.')[0] : ''}::\n`, ...args)
  238. }
  239. /**
  240. * 弹出Toast
  241. * @param msg
  242. */
  243. static showMessage(msg: string) {
  244. const pa = GlobalContext.getUiContext()?.getPromptAction()
  245. if (pa) {
  246. pa.showToast({
  247. message: msg,
  248. duration: 1500
  249. });
  250. } else {
  251. promptAction.showToast({
  252. message: msg,
  253. duration: 1500
  254. });
  255. }
  256. }
  257. private static oTime: number = 0
  258. /**
  259. * 双击退出
  260. * @param msg
  261. */
  262. static doubleAndExit(event?: () => void) {
  263. const cTime = new Date().getTime()
  264. console.log('=====>', cTime)
  265. console.log('=====>', cTime - ToolsHelper.oTime)
  266. if (cTime - ToolsHelper.oTime > 800) {
  267. ToolsHelper.oTime = cTime
  268. ToolsHelper.showMessage('双击退出')
  269. } else {
  270. if (event) {
  271. event()
  272. } else {
  273. (getContext() as common.UIAbilityContext).terminateSelf()
  274. // getContext().getApplicationContext().killAllProcesses();
  275. }
  276. }
  277. return true
  278. }
  279. static closeAlertDialog(dialogTag: string) {
  280. if (ToolsHelper.mapAlertDialog.get(dialogTag)) {
  281. try {
  282. GlobalContext.getUiContext()?.getPromptAction().closeCustomDialog(ToolsHelper.mapAlertDialog.get(dialogTag))
  283. } catch (err) {
  284. }
  285. ToolsHelper.mapAlertDialog.remove(dialogTag)
  286. }
  287. }
  288. /**
  289. * 弹出Alert弹窗
  290. * 第二个参数可以自定义布局,自定义布局接收的参数为AlertBean
  291. * @Builder
  292. * function alertDialogBuilder(options: AlertBean) {}
  293. *
  294. * @param options
  295. * @param builder wrapBuilder(alertDialogBuilder)
  296. */
  297. static showAlertDialog(options: AlertOptions, builder?: WrappedBuilder<[Object]>) {
  298. const dialogTag = ToolsHelper.getUuid()
  299. const ui = GlobalContext.getUiContext()
  300. if (ui) {
  301. const c = new ComponentContent(ui, builder ?? wrapBuilder(alertDialogBuilder),
  302. new AlertBean({ title: options.title, msg: options.msg, confirm: options.action }, dialogTag))
  303. ui.getPromptAction().openCustomDialog(c, {
  304. autoCancel: false
  305. }).then(() => {
  306. ToolsHelper.mapAlertDialog.set(dialogTag, c)
  307. }).catch(() => {
  308. ToolsHelper.showCommonAlert(options)
  309. })
  310. } else {
  311. ToolsHelper.showCommonAlert(options)
  312. }
  313. }
  314. private static showCommonAlert(options: AlertOptions) {
  315. try {
  316. promptAction.showDialog({
  317. alignment: DialogAlignment.Center,
  318. title: options.title,
  319. message: options.msg,
  320. buttons: [{
  321. text: options.action?.text ?? "确定",
  322. color: options.action?.color ?? "#000000",
  323. }]
  324. })
  325. .then(() => {
  326. options.action?.onClick && options.action?.onClick()
  327. })
  328. .catch((err: Error) => {
  329. if (err.message === 'cancel') {
  330. } else {
  331. ToolsHelper.showMessage(err.message)
  332. }
  333. })
  334. } catch (error) {
  335. let message = (error as BusinessError).message
  336. ToolsHelper.showMessage(message)
  337. }
  338. }
  339. /**
  340. * 弹出Confirm弹窗
  341. * 第二个参数可以自定义布局,自定义布局接收的参数为AlertBean
  342. * @Builder
  343. * function alertDialogBuilder(options: AlertBean) {}
  344. *
  345. * @param options
  346. * @param builder wrapBuilder(alertDialogBuilder)
  347. */
  348. static showConfirmDialog(options: ConfirmOptions, builder?: WrappedBuilder<[Object]>) {
  349. const dialogTag = ToolsHelper.getUuid()
  350. const ui = GlobalContext.getUiContext()
  351. if (ui) {
  352. const c = new ComponentContent(ui, builder ?? wrapBuilder(alertDialogBuilder),
  353. new AlertBean({
  354. title: options.title,
  355. msg: options.msg,
  356. cancel: options.cancel ?? {},
  357. confirm: options.confirm
  358. }, dialogTag))
  359. ui.getPromptAction().openCustomDialog(c, {
  360. autoCancel: options.autoCancel
  361. }).then(() => {
  362. ToolsHelper.mapAlertDialog.set(dialogTag, c)
  363. }).catch(() => {
  364. ToolsHelper.showCommonConfirm(options)
  365. })
  366. } else {
  367. ToolsHelper.showCommonConfirm(options)
  368. }
  369. }
  370. static showCommonConfirm(options: ConfirmOptions) {
  371. try {
  372. promptAction.showDialog({
  373. alignment: 1,
  374. title: options.title,
  375. message: options.msg,
  376. buttons: [{
  377. text: options.cancel?.text ?? "取消",
  378. color: options.cancel?.color ?? "#666666",
  379. }, {
  380. text: options.confirm?.text ?? "确定",
  381. color: options.confirm?.color ?? "#000000",
  382. },]
  383. })
  384. .then((data) => {
  385. if (data.index === 0) {
  386. options.cancel?.onClick && options.cancel.onClick()
  387. } else {
  388. options.confirm?.onClick && options.confirm.onClick()
  389. }
  390. })
  391. .catch((err: Error) => {
  392. if (err.message === 'cancel') {
  393. options.cancel?.onClick && options.cancel.onClick()
  394. } else {
  395. ToolsHelper.showMessage(err.message)
  396. }
  397. })
  398. } catch (error) {
  399. let message = (error as BusinessError).message
  400. ToolsHelper.showMessage(message)
  401. }
  402. }
  403. public static mapDialog = new HashMap<string, number>()
  404. public static mapAlertDialog = new HashMap<string, ComponentContent<Object>>()
  405. /**
  406. * 弹出List弹窗
  407. * @param options values 如果是非string列表的话,需要存在content字段
  408. * @param p 调用页面,直接this 即可
  409. */
  410. static showListDialog<T = string>(options: ListOptions<T>, p: object) {
  411. let isSuccess: Array<number> = []
  412. options.values.forEach((item, index) => {
  413. if (typeof item !== 'string') {
  414. if (!(item as ListItem).content) {
  415. isSuccess.push(index)
  416. }
  417. }
  418. })
  419. if (isSuccess.length > 0) {
  420. options.onError && options.onError(`第(${isSuccess.join("、")})个数据中,没有content字段。`)
  421. } else {
  422. const dialogTag = ToolsHelper.getUuid()
  423. promptAction.openCustomDialog({
  424. cornerRadius: 0,
  425. autoCancel: options.autoCancel ?? false,
  426. width: '100%',
  427. // height: options.values === undefined ? '20%' :
  428. // options.values?.length < 8 ? `${options.values?.length / 16 * 100+10}%` : '50%',
  429. alignment: options.alignment ?? DialogAlignment.Bottom,
  430. builder: customDialogBuilder.bind(p, options, dialogTag),
  431. backgroundColor: 'white'
  432. }).then((dialogId: number) => {
  433. ToolsHelper.mapDialog.set(dialogTag, dialogId)
  434. })
  435. }
  436. }
  437. /**
  438. * 弹出自定义弹窗
  439. * @param alignment 弹窗在竖直方向上的对齐方式
  440. */
  441. static showCustomDialog(dialogTag: string, b: CustomBuilder, alignment?: DialogAlignment) {
  442. promptAction.openCustomDialog({
  443. alignment: alignment ?? DialogAlignment.Center,
  444. builder: b,
  445. cornerRadius: 3,
  446. width: '100%',
  447. }).then((dialogId: number) => {
  448. ToolsHelper.mapDialog.set(dialogTag, dialogId)
  449. }).catch((error: Error) => {
  450. console.log('>>>>>', JSON.stringify(error))
  451. })
  452. }
  453. /**
  454. * 关闭自定义弹窗
  455. * @param dialogTag 开启时的tag
  456. */
  457. static closeCustomDialog(dialogTag: string) {
  458. if (ToolsHelper.mapDialog.get(dialogTag)) {
  459. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  460. ToolsHelper.mapDialog.remove(dialogTag)
  461. }
  462. }
  463. static encryptStringToNumber(str: string): number {
  464. let result = 0;
  465. for (let i = 0; i < str.length; i++) {
  466. result = result * 256 + str.charCodeAt(i);
  467. }
  468. return result;
  469. }
  470. static decryptNumberToString(num: number): string {
  471. let result = '';
  472. while (num > 0) {
  473. result = String.fromCharCode(num & 255) + result;
  474. num >>>= 8;
  475. }
  476. return result.replace(/[\s\0]+$/, ''); // 移除结尾的空白字符
  477. }
  478. /**
  479. * 获取调用栈第一个类
  480. */
  481. static getStackKey() {
  482. let stack = new Error().stack
  483. if (stack) {
  484. let list = JSON.stringify(stack).split('\\n')
  485. let a = list[list.length-2].split(':')[0].split('(')[1]
  486. return a
  487. }
  488. return undefined
  489. }
  490. private static deviceInfo: DeviceInfo
  491. /**
  492. * 获取设备信息
  493. * @returns {@link DeviceInfo}
  494. */
  495. static getDeviceInfo() {
  496. if (!ToolsHelper.deviceInfo) {
  497. ToolsHelper.deviceInfo = new DeviceInfo()
  498. ToolsHelper.deviceInfo.ODID = deviceInfo.ODID
  499. ToolsHelper.deviceInfo.manufacture = deviceInfo.manufacture
  500. ToolsHelper.deviceInfo.productModel = deviceInfo.productModel
  501. ToolsHelper.deviceInfo.brand = deviceInfo.brand
  502. ToolsHelper.deviceInfo.osFullName = deviceInfo.osFullName
  503. ToolsHelper.logInfo()
  504. }
  505. return ToolsHelper.deviceInfo
  506. }
  507. private static logInfo() {
  508. // ToolsHelper.log('deviceType-----', deviceInfo.deviceType)
  509. // ToolsHelper.log('manufacture-----', deviceInfo.manufacture)
  510. // ToolsHelper.log('brand-----', deviceInfo.brand)
  511. // ToolsHelper.log('marketName-----', deviceInfo.marketName)
  512. // ToolsHelper.log('productSeries-----', deviceInfo.productSeries)
  513. // ToolsHelper.log('productModel-----', deviceInfo.productModel)
  514. // ToolsHelper.log('softwareModel-----', deviceInfo.softwareModel)
  515. // ToolsHelper.log('hardwareModel-----', deviceInfo.hardwareModel)
  516. // ToolsHelper.log('hardwareProfile-----', deviceInfo.hardwareProfile)
  517. // ToolsHelper.log('serial-----', deviceInfo.serial)
  518. // ToolsHelper.log('bootloaderVersion-----', deviceInfo.bootloaderVersion)
  519. // ToolsHelper.log('abiList-----', deviceInfo.abiList)
  520. // ToolsHelper.log('securityPatchTag-----', deviceInfo.securityPatchTag)
  521. // ToolsHelper.log('displayVersion-----', deviceInfo.displayVersion)
  522. // ToolsHelper.log('incrementalVersion-----', deviceInfo.incrementalVersion)
  523. // ToolsHelper.log('osReleaseType-----', deviceInfo.osReleaseType)
  524. // ToolsHelper.log('osFullName-----', deviceInfo.osFullName)
  525. // ToolsHelper.log('majorVersion-----', deviceInfo.majorVersion)
  526. // ToolsHelper.log('seniorVersion-----', deviceInfo.seniorVersion)
  527. // ToolsHelper.log('featureVersion-----', deviceInfo.featureVersion)
  528. // ToolsHelper.log('buildVersion-----', deviceInfo.buildVersion)
  529. // ToolsHelper.log('sdkApiVersion-----', deviceInfo.sdkApiVersion)
  530. // ToolsHelper.log('firstApiVersion-----', deviceInfo.firstApiVersion)
  531. // ToolsHelper.log('versionId-----', deviceInfo.versionId)
  532. // ToolsHelper.log('buildType-----', deviceInfo.buildType)
  533. // ToolsHelper.log('buildUser-----', deviceInfo.buildUser)
  534. // ToolsHelper.log('buildHost-----', deviceInfo.buildHost)
  535. // ToolsHelper.log('buildTime-----', deviceInfo.buildTime)
  536. // ToolsHelper.log('buildRootHash-----', deviceInfo.buildRootHash)
  537. // ToolsHelper.log('distributionOSName-----', deviceInfo.distributionOSName)
  538. // ToolsHelper.log('distributionOSVersion-----', deviceInfo.distributionOSVersion)
  539. // ToolsHelper.log('distributionOSApiVersion-----', deviceInfo.distributionOSApiVersion)
  540. // ToolsHelper.log('distributionOSApiName-----', deviceInfo.distributionOSApiName)
  541. // ToolsHelper.log('distributionOSReleaseType-----', deviceInfo.distributionOSReleaseType)
  542. }
  543. /**
  544. * 防抖动函数,调用后会延迟wait时间执行,当在wait时间内再次对同一函数调用,则会取消之前的定时器,重新定时
  545. * @param fun
  546. * @param wait
  547. */
  548. static throttleHold(fun: Function, wait: number = 1500) {
  549. let funcValue1 = ToolsHelper.getUniqueId(fun)
  550. let hash = md5_hex(funcValue1)
  551. if (ToolsHelper.setTimeOutMap.get(hash)) {
  552. clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  553. ToolsHelper.setTimeOutMap.delete(hash)
  554. }
  555. // ToolsHelper.checkTimeOutNumber()
  556. let timeoutNumber = setTimeout(() => {
  557. ToolsHelper.setTimeOutMap.get(hash) && clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  558. ToolsHelper.setTimeOutMap.delete(hash)
  559. // 执行函数调用
  560. fun()
  561. }, wait)
  562. ToolsHelper.setTimeOutMap.set(hash, {
  563. timeoutNumber: timeoutNumber,
  564. startTime: new Date().getTime(),
  565. })
  566. }
  567. /**
  568. * 防抖函数(调用会立即触发,在wait时间内不再触发)
  569. * @param fun
  570. * @param wait
  571. */
  572. static debounceHold(fun: Function, wait: number = 1500) {
  573. let funcValue1 = ToolsHelper.getUniqueId(fun)
  574. let hash = md5_hex(funcValue1)
  575. const func = ToolsHelper.setTimeOutMap.get(hash)
  576. if (func) {
  577. if (func.startTime + func.timeoutNumber <= new Date().getTime()) {
  578. ToolsHelper.setTimeOutMap.delete(hash)
  579. } else {
  580. return
  581. }
  582. }
  583. ToolsHelper.setTimeOutMap.set(hash, {
  584. timeoutNumber: wait,
  585. startTime: new Date().getTime(),
  586. })
  587. // 执行函数调用
  588. fun()
  589. // 拦截在wait期间的函数再次调用,在超时后,将限制解除
  590. setTimeout(() => {
  591. ToolsHelper.setTimeOutMap.get(hash) && clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  592. ToolsHelper.setTimeOutMap.delete(hash)
  593. }, wait)
  594. }
  595. static toString(arrayBuffer: ArrayBuffer) {
  596. let decoder = util.TextDecoder.create('utf-8');
  597. return decoder.decodeToString(new Uint8Array(arrayBuffer))
  598. }
  599. static stringToArrayBuffer(str: string): ArrayBuffer {
  600. let buf = buffer.from(str, 'utf-8'); // 使用 UTF-8 编码
  601. return buf.buffer;
  602. }
  603. private static setTimeOutMap: Map<string, ThrottleInterface> = new Map()
  604. private static uniqueIdMap = new WeakMap<Function, string>();
  605. public static getUuid() {
  606. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
  607. let r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
  608. return v.toString(16);
  609. });
  610. }
  611. private static getUniqueId(fun: Function): string {
  612. // ToolsHelper.log('', ToolsHelper.getStackKey())
  613. if (!ToolsHelper.uniqueIdMap.has(fun)) {
  614. ToolsHelper.uniqueIdMap.set(fun, ToolsHelper.getUuid());
  615. }
  616. return ToolsHelper.uniqueIdMap.get(fun)!;
  617. }
  618. }