a2bei4-utils 1.0.2 → 1.0.3
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/LICENSE +21 -21
- package/README.md +2 -2
- package/dist/a2bei4.utils.cjs.js +1985 -1842
- package/dist/a2bei4.utils.cjs.js.map +1 -1
- package/dist/a2bei4.utils.cjs.min.js +1 -1
- package/dist/a2bei4.utils.cjs.min.js.map +1 -1
- package/dist/a2bei4.utils.esm.js +1984 -1843
- package/dist/a2bei4.utils.esm.js.map +1 -1
- package/dist/a2bei4.utils.esm.min.js +1 -1
- package/dist/a2bei4.utils.esm.min.js.map +1 -1
- package/dist/a2bei4.utils.umd.js +1985 -1842
- package/dist/a2bei4.utils.umd.js.map +1 -1
- package/dist/a2bei4.utils.umd.min.js +1 -1
- package/dist/a2bei4.utils.umd.min.js.map +1 -1
- package/dist/arr.cjs +27 -27
- package/dist/arr.cjs.map +1 -1
- package/dist/arr.js +27 -27
- package/dist/arr.js.map +1 -1
- package/dist/audio.cjs +274 -274
- package/dist/audio.cjs.map +1 -1
- package/dist/audio.js +274 -274
- package/dist/audio.js.map +1 -1
- package/dist/browser.cjs +52 -52
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +52 -52
- package/dist/browser.js.map +1 -1
- package/dist/common.cjs +369 -369
- package/dist/common.cjs.map +1 -1
- package/dist/common.js +369 -369
- package/dist/common.js.map +1 -1
- package/dist/date.cjs +326 -184
- package/dist/date.cjs.map +1 -1
- package/dist/date.js +325 -185
- package/dist/date.js.map +1 -1
- package/dist/download.cjs +102 -102
- package/dist/download.cjs.map +1 -1
- package/dist/download.js +102 -102
- package/dist/download.js.map +1 -1
- package/dist/evt.cjs +148 -148
- package/dist/evt.cjs.map +1 -1
- package/dist/evt.js +148 -148
- package/dist/evt.js.map +1 -1
- package/dist/id.cjs +68 -68
- package/dist/id.cjs.map +1 -1
- package/dist/id.js +68 -68
- package/dist/id.js.map +1 -1
- package/dist/timer.cjs +51 -50
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.js +51 -50
- package/dist/timer.js.map +1 -1
- package/dist/tree.cjs +165 -165
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.js +165 -165
- package/dist/tree.js.map +1 -1
- package/dist/webSocket.cjs +403 -403
- package/dist/webSocket.cjs.map +1 -1
- package/dist/webSocket.js +403 -403
- package/dist/webSocket.js.map +1 -1
- package/package.json +1 -1
- package/readme.txt +21 -11
- package/types/date.d.ts +60 -1
- package/types/index.d.ts +60 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";function t(){const t=new URLSearchParams(location.search);return Object.fromEntries(t.entries())}function e(t){return Object.prototype.toString.call(t).replace(/^\[object\s(\w+)\]$/,"$1").toLowerCase()}function n(t,e){if(!Number.isInteger(t)||!Number.isInteger(e))throw new TypeError("Arguments must be integers");return t>e&&([t,e]=[e,t]),Math.floor(Math.random()*(e-t+1))+t}function s(t=!0,e=!1,s=!1){const o=[];if(t&&o.push({min:19968,max:40869,surrogate:!1}),e&&o.push({min:13312,max:19903,surrogate:!1}),s&&o.push({min:131072,max:191471,surrogate:!0}),0===o.length)throw new RangeError("At least one range must be enabled");let i=n(0,o.reduce((t,e)=>t+(e.max-e.min+1),0)-1);for(const{min:t,max:e,surrogate:n}of o){const s=e-t+1;if(i<s){const e=t+i;if(!n)return String.fromCharCode(e);const s=e-65536,o=55296+(s>>10),r=56320+(1023&s);return String.fromCharCode(o,r)}i-=s}}function o(t){const e="abcdefghijklmnopqrstuvwxyz",s="ABCDEFGHIJKLMNOPQRSTUVWXYZ",o=n(0,25);switch(t){case"lower":return e[o];case"upper":return s[o];default:return(Math.random()<.5?e:s)[o]}}function i(t,e={}){if("number"!=typeof t||t<0||!isFinite(t))throw new TypeError("totalSeconds 必须是非负数字");const n=[{key:"year",seconds:31536e3},{key:"month",seconds:2592e3},{key:"day",seconds:86400},{key:"hour",seconds:3600},{key:"minute",seconds:60},{key:"second",seconds:1}],s=Object.assign({},{year:"年",month:"月",day:"天",hour:"小时",minute:"分钟",second:"秒"},e.labels);let o=0,i=n.length;if(e.maxUnit){const t=n.findIndex(t=>t.key===e.maxUnit);-1!==t&&(o=t)}if(e.minUnit){const t=n.findIndex(t=>t.key===e.minUnit);-1!==t&&(i=t+1)}const r=n.slice(o,i);r.length||r.push(n[n.length-1]);let a=Math.floor(t);const c=[];for(const{key:t,seconds:n}of r){const o=Math.floor(a/n);a%=n;(o>0||e.showZero&&"second"===t||0===c.length&&0===a)&&c.push(`${o}${s[t]}`)}return 0===c.length&&c.push(`0${s[r[r.length-1].key]}`),c.join("")}function r(t,e){const n=document.createElement("a");n.style.display="none",n.rel="noopener",n.href=t,n.download=e||Date.now(),document.body.appendChild(n),n.click(),document.body.removeChild(n)}function a(t,e){const n=URL.createObjectURL(t);r(n,e),setTimeout(()=>URL.revokeObjectURL(n),0)}function c(t,e,n="application/octet-stream"){a(new Blob([t],{type:n}),e)}const h=(()=>{const t=new WeakSet;return{install(e,n={}){if(t.has(e))return;t.add(e);const s=`___my-event-cross-page-${n.namespace||"default"}___`,o=n.throttle||16;let i=0;const r=e.emit;function a(t){if(!t.key||!t.key.startsWith(s))return;let n;try{n=JSON.parse(t.newValue||"{}")}catch{return}!n.ts||n.ts<=i||r.call(e,t.key.slice(s.length),n.data)}e.emit=function(t,n,a){r.call(e,t,n,a);const c=Date.now();if(c-i<o)return;i=c;const h=s+t;try{localStorage.setItem(h,JSON.stringify({name:t,data:n,ts:c})),localStorage.removeItem(h)}catch(t){}},addEventListener("storage",a),e._uninstallCrossPage=()=>{removeEventListener("storage",a),e.emit=r,t.delete(e)}},uninstall(t){"function"==typeof t._uninstallCrossPage&&t._uninstallCrossPage()}}})();exports.AudioStreamResampler=class{constructor(t){this.onData=t.onData||(()=>{}),this.onStateChange=t.onStateChange||(()=>{}),this.processorOptions=t.processorOptions||{},this.saveFullPcm=t.saveFullPcm??!1,this.audioContext=null,this.workletNode=null,this.source=null,this.workletUrl=null,this.fullPcmData=this.saveFullPcm?[]:null,this.isInitialized=!1,this.isProcessing=!1}async init(){this.onStateChange("initializing","正在初始化音频环境...");try{this.audioContext=new(window.AudioContext||window.webkitAudioContext);const t=new Blob(["\nclass AudioStreamResamplerProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n const config = options.processorOptions || {};\n this.targetSampleRate = config.targetSampleRate || 16000;\n this.sourceSampleRate = sampleRate;\n this.downsampleRatio = this.sourceSampleRate / this.targetSampleRate;\n\n // 16000Hz 用 60ms chunk (960 samples),其他用 1024\n this.chunkSize = this.targetSampleRate === 16000 ? 960 : 1024;\n\n const sourceBufferSize = config.sourceBufferSize || 16384; // ~340ms @48kHz\n const pcmBufferSize = config.pcmBufferSize || (this.chunkSize * 10); // 更大缓冲,减少溢出概率\n\n this.sourceBuffer = new Float32Array(sourceBufferSize);\n this.sourceBufferLength = 0;\n\n this.pcmBuffer = new Int16Array(pcmBufferSize);\n this.pcmBufferIndex = 0;\n }\n\n process(inputs, outputs, parameters) {\n const input = inputs[0];\n if (!input || input.length === 0 || input[0].length === 0) return true;\n const inputChannel = input[0];\n\n // 1. 写入源缓冲区(溢出时覆盖最旧数据)\n const newLength = this.sourceBufferLength + inputChannel.length;\n if (newLength > this.sourceBuffer.length) {\n const overflow = newLength - this.sourceBuffer.length;\n this.sourceBuffer.copyWithin(0, overflow);\n this.sourceBufferLength = this.sourceBuffer.length - inputChannel.length;\n }\n this.sourceBuffer.set(inputChannel, this.sourceBufferLength);\n this.sourceBufferLength += inputChannel.length;\n\n // 2. 计算可降采样样本数\n const availableOutputSamples = Math.floor(this.sourceBufferLength / this.downsampleRatio);\n if (availableOutputSamples === 0) return true;\n\n // 3. 线性插值降采样\n const downsampled = new Float32Array(availableOutputSamples);\n for (let i = 0; i < availableOutputSamples; i++) {\n const srcIndex = i * this.downsampleRatio;\n const srcIndexInt = Math.floor(srcIndex);\n const fraction = srcIndex - srcIndexInt;\n const val0 = this.sourceBuffer[srcIndexInt];\n const val1 = srcIndexInt + 1 < this.sourceBufferLength ? this.sourceBuffer[srcIndexInt + 1] : val0;\n downsampled[i] = val0 + (val1 - val0) * fraction;\n }\n\n // 4. Float32 → Int16 PCM\n const pcmData = this.floatTo16BitPCM(downsampled);\n\n // 5. 写入 PCM 缓冲区(空间不足时直接覆盖最旧,缓冲区足够大基本不会触发)\n if (this.pcmBufferIndex + pcmData.length > this.pcmBuffer.length) {\n // 简单策略:从头覆盖(丢弃最旧数据)\n this.pcmBufferIndex = 0;\n }\n this.pcmBuffer.set(pcmData, this.pcmBufferIndex);\n this.pcmBufferIndex += pcmData.length;\n\n // 6. 发送所有完整的 chunk(关键:复制到新数组再转移)\n while (this.pcmBufferIndex >= this.chunkSize) {\n // 方法1:推荐,使用 slice(隐式复制到新 ArrayBuffer)\n const chunk = this.pcmBuffer.slice(0, this.chunkSize);\n\n // 方法2:等价写法\n // const chunk = new Int16Array(this.pcmBuffer.subarray(0, this.chunkSize));\n\n this.port.postMessage(chunk, [chunk.buffer]); // 转移新缓冲区,安全!\n\n // 移动剩余数据到开头\n this.pcmBuffer.copyWithin(0, this.chunkSize, this.pcmBufferIndex);\n this.pcmBufferIndex -= this.chunkSize;\n }\n\n // 7. 清理已消费的源数据\n const consumedSrc = Math.floor(availableOutputSamples * this.downsampleRatio + 0.5); // 四舍五入更准\n if (consumedSrc > 0) {\n this.sourceBuffer.copyWithin(0, consumedSrc, this.sourceBufferLength);\n this.sourceBufferLength -= consumedSrc;\n }\n\n return true;\n }\n\n floatTo16BitPCM(input) {\n const output = new Int16Array(input.length);\n for (let i = 0; i < input.length; i++) {\n const s = Math.max(-1, Math.min(1, input[i]));\n output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;\n }\n return output;\n }\n}\n\nregisterProcessor('audio-stream-resampler-processor', AudioStreamResamplerProcessor);\n"],{type:"application/javascript"});this.workletUrl=URL.createObjectURL(t),await this.audioContext.audioWorklet.addModule(this.workletUrl),this.workletNode=new AudioWorkletNode(this.audioContext,"audio-stream-resampler-processor",{processorOptions:this.processorOptions}),this.workletNode.port.onmessage=t=>{const e=t.data;this.onData(e),this.saveFullPcm&&this.fullPcmData.push(e)},this.isInitialized=!0,this.onStateChange("ready","音频环境已就绪")}catch(t){console.error("AudioStreamResampler init error:",t),this.onStateChange("error",`初始化失败: ${t.message}`)}}setMediaStream(t){this.isInitialized?(this.source&&this.source.disconnect(),this.source=this.audioContext.createMediaStreamSource(t),this.source.connect(this.workletNode),this.isProcessing=!0,this.onStateChange("processing","正在处理音频流...")):console.error("请先调用 init()")}stop(t){if(this.isProcessing&&(this.onStateChange("stopping","正在停止..."),this.source&&(this.source.disconnect(),this.source=null),this._cleanup(),this.onStateChange("stopped","已停止"),this.saveFullPcm&&t&&"function"==typeof t)){const e=this.fullPcmData.reduce((t,e)=>t+e.length,0),n=new Int16Array(e);let s=0;for(const t of this.fullPcmData)n.set(t,s),s+=t.length;t(n)}}_cleanup(){this.workletNode&&(this.workletNode.disconnect(),this.workletNode.port.close(),this.workletNode=null),this.audioContext&&"closed"!==this.audioContext.state&&(this.audioContext.close(),this.audioContext=null),this.workletUrl&&(URL.revokeObjectURL(this.workletUrl),this.workletUrl=null),this.isProcessing=!1,this.isInitialized=!1,this.fullPcmData&&(this.fullPcmData.length=0)}},exports.IntervalTimer=class{constructor(t,e=1e3){if("function"!=typeof t)throw new TypeError("IntervalTimer: 必须传入一个函数");this._fn=t,this._ms=e,this._timerId=null}start(){this.stop();const t=()=>{this._fn(),this._timerId=setTimeout(t,this._ms)};t()}stop(){null!==this._timerId&&(clearTimeout(this._timerId),this._timerId=null)}isRunning(){return null!==this._timerId}},exports.MyEvent=class{constructor(){this.evtPool=new Map}on(t,e){let n=Date.now()+"_"+parseInt(1e8*Math.random());const s={flag:n,fn:e};return this.evtPool.has(t)?this.evtPool.get(t).push(s):this.evtPool.set(t,[s]),n}once(t,e){const n=this;let s;return s=function(o){n.off(t,s),e.call(this,o)},this.on(t,s)}off(t,e){if(!this.evtPool.has(t))return;const n=this.evtPool.get(t).filter(t=>t.fn!==e&&t.flag!==e);0===n.length?this.evtPool.delete(t):this.evtPool.set(t,n)}emit(t,e,n){if(!this.evtPool.has(t))return;this.evtPool.get(t).forEach(s=>{try{s.fn.call(n,e)}catch(e){console.error(`Error in event listener for "${t}":`,e)}})}},exports.MyEvent_CrossPagePlugin=h,exports.MyId=class{#t=Date.now();#e=0;#n="";#s=5;constructor(t={}){t&&("string"==typeof t.flag&&(this.#n=t.flag),Number.isSafeInteger(t.len)&&len>=0&&(this.#s=t.len))}nextId(){let t=Date.now();return t===this.#t?(this.#e++,this.#e>=10**this.#s&&console.log("长度不够用了!!!")):(this.#e=0,this.#t=t),t.toString()+this.#n+this.#e.toString().padStart(this.#s,"0")}},exports.WebSocketManager=class{constructor(t,e={}){this.url=t;this.options={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectBaseInterval:1e3,maxReconnectInterval:3e4,maxReconnectAttempts:1/0,autoConnect:!0,serializeData:!1,deserializeData:!1,getPingMessage:()=>JSON.stringify({type:"ping"}),isPongMessage:t=>{try{return"pong"===JSON.parse(t.data).type}catch(t){return!1}},...e},this.ws=null,this.readyState=WebSocket.CLOSED,this.reconnectAttempts=0,this.forcedClose=!1,this.isReconnecting=!1,this.heartbeatTimer=null,this.heartbeatTimeoutTimer=null,this.reconnectTimer=null,this.messageQueue=[],this.listeners=new Map,this._onOpen=this._onOpen.bind(this),this._onMessage=this._onMessage.bind(this),this._onClose=this._onClose.bind(this),this._onError=this._onError.bind(this),this._handleVisibilityChange=this._handleVisibilityChange.bind(this),this._handleOnline=this._handleOnline.bind(this),this._handleOffline=this._handleOffline.bind(this),this._setupEventListeners(),this.options.autoConnect&&this.connect()}connect(){if(!this.ws||this.ws.readyState!==WebSocket.CONNECTING&&this.ws.readyState!==WebSocket.OPEN){this.forcedClose=!1,this._updateReadyState(WebSocket.CONNECTING),console.log(`[WS] 正在连接到 ${this.url}...`),this._emit("connecting");try{this.ws=new WebSocket(this.url,this.options.protocols),this.ws.onopen=this._onOpen,this.ws.onmessage=this._onMessage,this.ws.onclose=this._onClose,this.ws.onerror=this._onError}catch(t){console.error("[WS] 连接失败:",t),this._onError(t)}}}send(t){if(this.readyState===WebSocket.OPEN){let e;e=this.options.serializeData?JSON.stringify(t):t,this.ws.send(e),console.log("[WS] 消息已发送:",e)}else console.warn("[WS] 连接未打开,消息已加入队列:",t),this.messageQueue.push(t)}close(t=1e3,e="Normal closure"){this.forcedClose=!0,this._stopHeartbeat(),this._clearReconnectTimer(),this.ws&&this.ws.readyState===WebSocket.OPEN?this.ws.close(t,e):(this._updateReadyState(WebSocket.CLOSED),this._emit("close",{code:t,reason:e,wasClean:!0}))}destroy(){console.log("[WS] 正在销毁实例..."),this.close(1e3,"Instance destroyed"),this._removeEventListeners(),this.messageQueue=[],this.listeners.clear(),this.ws=null}on(t,e){this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(e)}off(t,e){if(this.listeners.has(t)){const n=this.listeners.get(t),s=n.indexOf(e);s>-1&&n.splice(s,1)}}_onOpen(t){console.log("[WS] 连接已建立"),this._updateReadyState(WebSocket.OPEN),this.reconnectAttempts=0,this.isReconnecting=!1,this.options.getPingMessage&&this._startHeartbeat(),this._flushMessageQueue(),this._emit("open",t)}_onMessage(t){if(this.options.isPongMessage&&this.options.isPongMessage(t))this._handlePong();else if(this.options.deserializeData)try{const e=JSON.parse(t.data);this._emit("message",e,t)}catch(e){this._emit("message",t.data,t)}else this._emit("message",t.data,t)}_onClose(t){console.log("[WS] 连接已关闭",t),this._updateReadyState(WebSocket.CLOSED),this._stopHeartbeat(),this._emit("close",t),this.forcedClose||this._scheduleReconnect()}_onError(t){console.error("[WS] 连接发生错误:",t),this._emit("error",t)}_startHeartbeat(){this.options.getPingMessage&&(this._stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{const t=this.options.getPingMessage();this.ws.send(t),console.log("[WS] 发送 Ping:",t),this._setHeartbeatTimeout()}catch(t){console.error("[WS] 发送 Ping 消息失败:",t)}},this.options.heartbeatInterval))}_stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this._clearHeartbeatTimeout()}_setHeartbeatTimeout(){this._clearHeartbeatTimeout(),this.heartbeatTimeoutTimer=setTimeout(()=>{console.error("[WS] 心跳超时,主动断开连接"),this.ws.close(1006,"Heartbeat timeout")},this.options.heartbeatTimeout)}_clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null)}_handlePong(){console.log("[WS] 收到 Pong"),this._clearHeartbeatTimeout()}_scheduleReconnect(){if(this.forcedClose||this.isReconnecting||this.reconnectAttempts>=this.options.maxReconnectAttempts)return void(this.reconnectAttempts>=this.options.maxReconnectAttempts&&(console.error("[WS] 已达到最大重连次数,停止重连"),this._emit("reconnect-failed")));this.isReconnecting=!0;const t=Math.min(this.options.reconnectBaseInterval*Math.pow(2,this.reconnectAttempts),this.options.maxReconnectInterval);console.log(`[WS] ${t/1e3}秒后将尝试第 ${this.reconnectAttempts+1} 次重连...`),this._emit("reconnect-attempt",{attempt:this.reconnectAttempts+1,interval:t}),this.reconnectTimer=setTimeout(()=>{this.reconnectAttempts++,this.connect()},t)}_clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}_flushMessageQueue(){if(0===this.messageQueue.length)return;console.log(`[WS] 发送队列中的 ${this.messageQueue.length} 条消息`);const t=[...this.messageQueue];this.messageQueue=[],t.forEach(t=>this.send(t))}_emit(t,...e){this.listeners.has(t)&&this.listeners.get(t).forEach(t=>t(...e))}_updateReadyState(t){this.readyState=t,this._emit("ready-state-change",t)}_setupEventListeners(){document.addEventListener("visibilitychange",this._handleVisibilityChange),window.addEventListener("online",this._handleOnline),window.addEventListener("offline",this._handleOffline)}_removeEventListeners(){document.removeEventListener("visibilitychange",this._handleVisibilityChange),window.removeEventListener("online",this._handleOnline),window.removeEventListener("offline",this._handleOffline)}_handleVisibilityChange(){this.options.getPingMessage&&(document.hidden?(console.log("[WS] 页面隐藏,停止心跳"),this._stopHeartbeat()):(console.log("[WS] 页面可见,检查连接状态"),this.ws&&this.ws.readyState===WebSocket.OPEN?this._startHeartbeat():this.forcedClose||this.isReconnecting||this.connect()))}_handleOnline(){console.log("[WS] 网络已恢复,尝试重连"),this.forcedClose||this.readyState===WebSocket.OPEN||(this._clearReconnectTimer(),this.connect())}_handleOffline(){console.log("[WS] 网络已断开"),this._clearReconnectTimer(),this.ws&&this.ws.onclose({code:1006,reason:"Network offline"})}},exports.assignExisting=function(t,...e){return e.forEach(e=>{Object.keys(e).forEach(n=>{t.hasOwnProperty(n)&&(t[n]=e[n])})}),t},exports.calcTimeDifference=function(t,e=new Date){const n=e-new Date(t),s=Math.floor(n/1e3),o=Math.floor(s/86400),i=Math.floor(s%86400/3600),r=Math.floor(s%3600/60),a=s%60,c=t=>String(t).padStart(2,"0");return{days:o,hours:c(i),minutes:c(r),seconds:c(a)}},exports.debounce=function(t,e,n=!1){if("function"!=typeof t)throw new TypeError("fn must be function");let s;e=Math.max(0,Number(e)||0);let o=0;function i(...i){const r=0===o,a=Date.now()-o>=e;if(clearTimeout(s),n&&(r||a))return o=Date.now(),t.apply(this,i);s=setTimeout(()=>{o=Date.now(),t.apply(this,i)},e)}return i.cancel=()=>{clearTimeout(s),o=0},i},exports.deepCloneByJSON=function(t){return JSON.parse(JSON.stringify(t))},exports.downloadByBlob=a,exports.downloadByData=c,exports.downloadByUrl=r,exports.downloadExcel=function(t,e){c(t,e,"application/vnd.ms-excel")},exports.downloadJSON=function(t,e){c(t,e,"application/json")},exports.extractFullyCheckedKeys=function(t,e,n="id",s="children"){const o=new Set(e),i=new Set,r=new Set;return t.forEach(function t(e){const a=e[n],c=e[s]||[];if(!c.length)return o.has(a)?(i.add(a),2):0;let h=!0,l=!1;return c.forEach(e=>{const n=t(e);2!==n&&(h=!1),n>=1&&(l=!0)}),o.has(a)?h?(i.add(a),2):(r.add(a),1):h?(i.add(a),2):l?(r.add(a),1):0}),{checked:[...i],halfChecked:[...r]}},exports.fetchOrDownloadByUrl=async function(t,e){if(!e){try{const n=new URL(t).pathname;e=n.substring(n.lastIndexOf("/")+1).split("?")[0]}catch(t){}e||(e=Date.now().toString())}try{const n=await fetch(t,{method:"GET",mode:"cors",cache:"no-cache"});if(!n.ok)throw new Error(`HTTP error! ${n.status}: ${n.statusText}`);a(await n.blob(),e)}catch(n){r(t,e)}},exports.findObjAttrValueById=function t(e,n,s="name",o="id",i="children"){if(Array.isArray(n)&&n.length>0)for(let r=0;r<n.length;r++){const a=n[r];if(a[o]?.toString()===e?.toString())return a[s];if(Array.isArray(a[i])&&a[i].length>0){const n=t(e,a[i],s,o,i);if(n)return n}}},exports.flatCompleteTree2NestedTree=function(t,e=0,{idKey:n="id",parentKey:s="parentId",childrenKey:o="children"}={}){const i=new Map,r=[];for(const e of t){const t={...e,[o]:[]};i.set(e[n],t)}for(const a of t){const t=i.get(a[n]),c=a[s];if(c===e)r.push(t);else{const e=i.get(c);e&&e[o].push(t)}}return r},exports.formatDuration=i,exports.formatDurationMaxDay=function(t,e={}){return i(t,{...e,maxUnit:"day"})},exports.formatDurationMaxHour=function(t,e={}){return i(t,{...e,maxUnit:"hour"})},exports.getAllSearchParams=t,exports.getDataType=e,exports.getFunctionArgNames=function(t){const e=/^\s*(_?)(\S+?)\1\s*$/,n=Function.prototype.toString.call(t).replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,""),s=n.match(/^([^(]+?)=>/)||n.match(/^[^(]*\(\s*([^)]*)\)/m),o=[];return[].forEach.call(s[1].split(/,/),function(t){t.replace(e,function(t,e,n){o.push(n)})}),o},exports.getGUID=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=16*Math.random()|0;return("x"==t?e:3&e|8).toString(16).toUpperCase()})},exports.getSearchParam=function(e){return t()[e]},exports.getViewportSize=function(){const t=document,e=t.documentElement,n=t.body;return{w:window.innerWidth||e.clientWidth||n.clientWidth,h:window.innerHeight||e.clientHeight||n.clientHeight}},exports.isBlob=function(t){return"blob"===e(t)},exports.isDate=function(t){return"date"===e(t)},exports.isFunction=function(t){return"function"==typeof t},exports.isNonEmptyString=function(t){return"string"===e(t)&&t.length>0},exports.isPlainObject=function(t){return"object"===e(t)},exports.isPromise=function(t){return"promise"===e(t)},exports.moveItem=function(t,e,n){t.splice(n,0,t.splice(e,1)[0])},exports.nestedTree2IdMap=function(t,e="id",n="children"){const s={};return function t(o){Array.isArray(o)&&o.length>0&&o.forEach(o=>{s[o[e]]={...o},s[o[e]][n]=null,t(o[n])})}(t),s},exports.pcmToWavBlob=function(t,e=16e3){const n=t.length,s=new ArrayBuffer(44+2*n),o=new DataView(s),i=(t,e)=>{for(let n=0;n<e.length;n++)o.setUint8(t+n,e.charCodeAt(n))};i(0,"RIFF"),o.setUint32(4,36+2*n,!0),i(8,"WAVE"),i(12,"fmt "),o.setUint32(16,16,!0),o.setUint16(20,1,!0),o.setUint16(22,1,!0),o.setUint32(24,e,!0),o.setUint32(28,2*e,!0),o.setUint16(32,2,!0),o.setUint16(34,16,!0),i(36,"data"),o.setUint32(40,2*n,!0);let r=44;for(let e=0;e<n;e++)o.setInt16(r,t[e],!0),r+=2;return new Blob([s],{type:"audio/wav"})},exports.randomDateInRange=function(t,e){let n=t.getTime(),s=e.getTime();return n>s&&([n,s]=[s,n]),new Date(n+Math.floor(Math.random()*(s-n+1)))},exports.randomEnLetter=o,exports.randomHan=s,exports.randomHanOrEn=function(t,e=.5){t=Math.max(1,Math.floor(t));const n=[];for(let i=0;i<t;i++)n.push(Math.random()<e?s():o());return n.join("")},exports.randomIntInRange=n,exports.readBlobAsText=function(t,e=!0){return new Promise((n,s)=>{const o=new FileReader;o.onload=t=>{const s=t.target.result;if(e)try{n(JSON.parse(s))}catch(t){console.error(t),n(s)}else n(s)},o.onerror=s,o.readAsText(t)})},exports.shuffle=function(t){for(let e=t.length-1;e>0;e--){const n=Math.floor(Math.random()*(e+1));[t[e],t[n]]=[t[n],t[e]]}return t},exports.throttle=function(t,e,{leading:n=!0,trailing:s=!0}={}){if("function"!=typeof t)throw new TypeError("fn must be function");e=Math.max(0,Number(e)||0);let o=null,i=0;function r(...r){const a=e-(Date.now()-i);n&&(0===i||a<=0)?(i=Date.now(),t.apply(this,r)):s&&!o&&(o=setTimeout(()=>{o=null,i=Date.now(),t.apply(this,r)},a>0?a:e))}return r.cancel=()=>{clearTimeout(o),o=null,i=0},r},exports.toDate=function(t){if(null==t)return null;if(t instanceof Date)return isNaN(t)?null:t;if("number"==typeof t||"string"==typeof t&&/^-?\d+(\.\d+)?$/.test(t.trim())){const e=new Date(+t);return isNaN(e)?null:e}if("string"==typeof t){const e=new Date(t);return isNaN(e)?null:e}if("object"==typeof t){const e=t.valueOf?t.valueOf():Object.prototype.valueOf.call(t);if("number"==typeof e&&!isNaN(e)){const t=new Date(e);return isNaN(t)?null:t}const n=t.toString?t.toString():String(t),s=new Date(n);return isNaN(s)?null:s}return null};
|
|
1
|
+
"use strict";function t(){const t=new URLSearchParams(location.search);return Object.fromEntries(t.entries())}function e(t){return Object.prototype.toString.call(t).replace(/^\[object\s(\w+)\]$/,"$1").toLowerCase()}function n(t,e){if(!Number.isInteger(t)||!Number.isInteger(e))throw new TypeError("Arguments must be integers");return t>e&&([t,e]=[e,t]),Math.floor(Math.random()*(e-t+1))+t}function s(t=!0,e=!1,s=!1){const o=[];if(t&&o.push({min:19968,max:40869,surrogate:!1}),e&&o.push({min:13312,max:19903,surrogate:!1}),s&&o.push({min:131072,max:191471,surrogate:!0}),0===o.length)throw new RangeError("At least one range must be enabled");let i=n(0,o.reduce((t,e)=>t+(e.max-e.min+1),0)-1);for(const{min:t,max:e,surrogate:n}of o){const s=e-t+1;if(i<s){const e=t+i;if(!n)return String.fromCharCode(e);const s=e-65536,o=55296+(s>>10),r=56320+(1023&s);return String.fromCharCode(o,r)}i-=s}}function o(t){const e="abcdefghijklmnopqrstuvwxyz",s="ABCDEFGHIJKLMNOPQRSTUVWXYZ",o=n(0,25);switch(t){case"lower":return e[o];case"upper":return s[o];default:return(Math.random()<.5?e:s)[o]}}function i(t,e={}){if("number"!=typeof t||t<0||!isFinite(t))throw new TypeError("totalSeconds 必须是非负数字");const n=[{key:"year",seconds:31536e3},{key:"month",seconds:2592e3},{key:"day",seconds:86400},{key:"hour",seconds:3600},{key:"minute",seconds:60},{key:"second",seconds:1}],s=Object.assign({},{year:"年",month:"月",day:"天",hour:"小时",minute:"分钟",second:"秒"},e.labels);let o=0,i=n.length;if(e.maxUnit){const t=n.findIndex(t=>t.key===e.maxUnit);-1!==t&&(o=t)}if(e.minUnit){const t=n.findIndex(t=>t.key===e.minUnit);-1!==t&&(i=t+1)}const r=n.slice(o,i);r.length||r.push(n[n.length-1]);let a=Math.floor(t);const c=[];for(const{key:t,seconds:n}of r){const o=Math.floor(a/n);a%=n;(o>0||e.showZero&&"second"===t||0===c.length&&0===a)&&c.push(`${o}${s[t]}`)}return 0===c.length&&c.push(`0${s[r[r.length-1].key]}`),c.join("")}function r(t,e={earlyMorning:"凌晨",morning:"上午",noon:"中午",afternoon:"下午",evening:"晚上"}){if(!Number.isInteger(t)||t<0||t>23)throw new RangeError("hour 必须是 0-23 的整数");return t>=0&&t<6?e.earlyMorning:t<12?e.morning:t<14?e.noon:t<18?e.afternoon:e.evening}function a(t,e){const n=document.createElement("a");n.style.display="none",n.rel="noopener",n.href=t,n.download=e||Date.now(),document.body.appendChild(n),n.click(),document.body.removeChild(n)}function c(t,e){const n=URL.createObjectURL(t);a(n,e),setTimeout(()=>URL.revokeObjectURL(n),0)}function h(t,e,n="application/octet-stream"){c(new Blob([t],{type:n}),e)}const l=(()=>{const t=new WeakSet;return{install(e,n={}){if(t.has(e))return;t.add(e);const s=`___my-event-cross-page-${n.namespace||"default"}___`,o=n.throttle||16;let i=0;const r=e.emit;function a(t){if(!t.key||!t.key.startsWith(s))return;let n;try{n=JSON.parse(t.newValue||"{}")}catch{return}!n.ts||n.ts<=i||r.call(e,t.key.slice(s.length),n.data)}e.emit=function(t,n,a){r.call(e,t,n,a);const c=Date.now();if(c-i<o)return;i=c;const h=s+t;try{localStorage.setItem(h,JSON.stringify({name:t,data:n,ts:c})),localStorage.removeItem(h)}catch(t){}},addEventListener("storage",a),e._uninstallCrossPage=()=>{removeEventListener("storage",a),e.emit=r,t.delete(e)}},uninstall(t){"function"==typeof t._uninstallCrossPage&&t._uninstallCrossPage()}}})();exports.AudioStreamResampler=class{constructor(t){this.onData=t.onData||(()=>{}),this.onStateChange=t.onStateChange||(()=>{}),this.processorOptions=t.processorOptions||{},this.saveFullPcm=t.saveFullPcm??!1,this.audioContext=null,this.workletNode=null,this.source=null,this.workletUrl=null,this.fullPcmData=this.saveFullPcm?[]:null,this.isInitialized=!1,this.isProcessing=!1}async init(){this.onStateChange("initializing","正在初始化音频环境...");try{this.audioContext=new(window.AudioContext||window.webkitAudioContext);const t=new Blob(["\nclass AudioStreamResamplerProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n const config = options.processorOptions || {};\n this.targetSampleRate = config.targetSampleRate || 16000;\n this.sourceSampleRate = sampleRate;\n this.downsampleRatio = this.sourceSampleRate / this.targetSampleRate;\n\n // 16000Hz 用 60ms chunk (960 samples),其他用 1024\n this.chunkSize = this.targetSampleRate === 16000 ? 960 : 1024;\n\n const sourceBufferSize = config.sourceBufferSize || 16384; // ~340ms @48kHz\n const pcmBufferSize = config.pcmBufferSize || (this.chunkSize * 10); // 更大缓冲,减少溢出概率\n\n this.sourceBuffer = new Float32Array(sourceBufferSize);\n this.sourceBufferLength = 0;\n\n this.pcmBuffer = new Int16Array(pcmBufferSize);\n this.pcmBufferIndex = 0;\n }\n\n process(inputs, outputs, parameters) {\n const input = inputs[0];\n if (!input || input.length === 0 || input[0].length === 0) return true;\n const inputChannel = input[0];\n\n // 1. 写入源缓冲区(溢出时覆盖最旧数据)\n const newLength = this.sourceBufferLength + inputChannel.length;\n if (newLength > this.sourceBuffer.length) {\n const overflow = newLength - this.sourceBuffer.length;\n this.sourceBuffer.copyWithin(0, overflow);\n this.sourceBufferLength = this.sourceBuffer.length - inputChannel.length;\n }\n this.sourceBuffer.set(inputChannel, this.sourceBufferLength);\n this.sourceBufferLength += inputChannel.length;\n\n // 2. 计算可降采样样本数\n const availableOutputSamples = Math.floor(this.sourceBufferLength / this.downsampleRatio);\n if (availableOutputSamples === 0) return true;\n\n // 3. 线性插值降采样\n const downsampled = new Float32Array(availableOutputSamples);\n for (let i = 0; i < availableOutputSamples; i++) {\n const srcIndex = i * this.downsampleRatio;\n const srcIndexInt = Math.floor(srcIndex);\n const fraction = srcIndex - srcIndexInt;\n const val0 = this.sourceBuffer[srcIndexInt];\n const val1 = srcIndexInt + 1 < this.sourceBufferLength ? this.sourceBuffer[srcIndexInt + 1] : val0;\n downsampled[i] = val0 + (val1 - val0) * fraction;\n }\n\n // 4. Float32 → Int16 PCM\n const pcmData = this.floatTo16BitPCM(downsampled);\n\n // 5. 写入 PCM 缓冲区(空间不足时直接覆盖最旧,缓冲区足够大基本不会触发)\n if (this.pcmBufferIndex + pcmData.length > this.pcmBuffer.length) {\n // 简单策略:从头覆盖(丢弃最旧数据)\n this.pcmBufferIndex = 0;\n }\n this.pcmBuffer.set(pcmData, this.pcmBufferIndex);\n this.pcmBufferIndex += pcmData.length;\n\n // 6. 发送所有完整的 chunk(关键:复制到新数组再转移)\n while (this.pcmBufferIndex >= this.chunkSize) {\n // 方法1:推荐,使用 slice(隐式复制到新 ArrayBuffer)\n const chunk = this.pcmBuffer.slice(0, this.chunkSize);\n\n // 方法2:等价写法\n // const chunk = new Int16Array(this.pcmBuffer.subarray(0, this.chunkSize));\n\n this.port.postMessage(chunk, [chunk.buffer]); // 转移新缓冲区,安全!\n\n // 移动剩余数据到开头\n this.pcmBuffer.copyWithin(0, this.chunkSize, this.pcmBufferIndex);\n this.pcmBufferIndex -= this.chunkSize;\n }\n\n // 7. 清理已消费的源数据\n const consumedSrc = Math.floor(availableOutputSamples * this.downsampleRatio + 0.5); // 四舍五入更准\n if (consumedSrc > 0) {\n this.sourceBuffer.copyWithin(0, consumedSrc, this.sourceBufferLength);\n this.sourceBufferLength -= consumedSrc;\n }\n\n return true;\n }\n\n floatTo16BitPCM(input) {\n const output = new Int16Array(input.length);\n for (let i = 0; i < input.length; i++) {\n const s = Math.max(-1, Math.min(1, input[i]));\n output[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;\n }\n return output;\n }\n}\n\nregisterProcessor('audio-stream-resampler-processor', AudioStreamResamplerProcessor);\n"],{type:"application/javascript"});this.workletUrl=URL.createObjectURL(t),await this.audioContext.audioWorklet.addModule(this.workletUrl),this.workletNode=new AudioWorkletNode(this.audioContext,"audio-stream-resampler-processor",{processorOptions:this.processorOptions}),this.workletNode.port.onmessage=t=>{const e=t.data;this.onData(e),this.saveFullPcm&&this.fullPcmData.push(e)},this.isInitialized=!0,this.onStateChange("ready","音频环境已就绪")}catch(t){console.error("AudioStreamResampler init error:",t),this.onStateChange("error",`初始化失败: ${t.message}`)}}setMediaStream(t){this.isInitialized?(this.source&&this.source.disconnect(),this.source=this.audioContext.createMediaStreamSource(t),this.source.connect(this.workletNode),this.isProcessing=!0,this.onStateChange("processing","正在处理音频流...")):console.error("请先调用 init()")}stop(t){if(this.isProcessing&&(this.onStateChange("stopping","正在停止..."),this.source&&(this.source.disconnect(),this.source=null),this._cleanup(),this.onStateChange("stopped","已停止"),this.saveFullPcm&&t&&"function"==typeof t)){const e=this.fullPcmData.reduce((t,e)=>t+e.length,0),n=new Int16Array(e);let s=0;for(const t of this.fullPcmData)n.set(t,s),s+=t.length;t(n)}}_cleanup(){this.workletNode&&(this.workletNode.disconnect(),this.workletNode.port.close(),this.workletNode=null),this.audioContext&&"closed"!==this.audioContext.state&&(this.audioContext.close(),this.audioContext=null),this.workletUrl&&(URL.revokeObjectURL(this.workletUrl),this.workletUrl=null),this.isProcessing=!1,this.isInitialized=!1,this.fullPcmData&&(this.fullPcmData.length=0)}},exports.IntervalTimer=class{constructor(t,e=1e3){if("function"!=typeof t)throw new TypeError("IntervalTimer: 必须传入一个函数");this._fn=t,this._ms=e,this._timerId=null}start(){this.stop();const t=()=>{this._fn(),this._timerId=setTimeout(t,this._ms)};t()}stop(){null!==this._timerId&&(clearTimeout(this._timerId),this._timerId=null)}isRunning(){return null!==this._timerId}},exports.MyEvent=class{constructor(){this.evtPool=new Map}on(t,e){let n=Date.now()+"_"+parseInt(1e8*Math.random());const s={flag:n,fn:e};return this.evtPool.has(t)?this.evtPool.get(t).push(s):this.evtPool.set(t,[s]),n}once(t,e){const n=this;let s;return s=function(o){n.off(t,s),e.call(this,o)},this.on(t,s)}off(t,e){if(!this.evtPool.has(t))return;const n=this.evtPool.get(t).filter(t=>t.fn!==e&&t.flag!==e);0===n.length?this.evtPool.delete(t):this.evtPool.set(t,n)}emit(t,e,n){if(!this.evtPool.has(t))return;this.evtPool.get(t).forEach(s=>{try{s.fn.call(n,e)}catch(e){console.error(`Error in event listener for "${t}":`,e)}})}},exports.MyEvent_CrossPagePlugin=l,exports.MyId=class{#t=Date.now();#e=0;#n="";#s=5;constructor(t={}){t&&("string"==typeof t.flag&&(this.#n=t.flag),Number.isSafeInteger(t.len)&&len>=0&&(this.#s=t.len))}nextId(){let t=Date.now();return t===this.#t?(this.#e++,this.#e>=10**this.#s&&console.log("长度不够用了!!!")):(this.#e=0,this.#t=t),t.toString()+this.#n+this.#e.toString().padStart(this.#s,"0")}},exports.WebSocketManager=class{constructor(t,e={}){this.url=t;this.options={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectBaseInterval:1e3,maxReconnectInterval:3e4,maxReconnectAttempts:1/0,autoConnect:!0,serializeData:!1,deserializeData:!1,getPingMessage:()=>JSON.stringify({type:"ping"}),isPongMessage:t=>{try{return"pong"===JSON.parse(t.data).type}catch(t){return!1}},...e},this.ws=null,this.readyState=WebSocket.CLOSED,this.reconnectAttempts=0,this.forcedClose=!1,this.isReconnecting=!1,this.heartbeatTimer=null,this.heartbeatTimeoutTimer=null,this.reconnectTimer=null,this.messageQueue=[],this.listeners=new Map,this._onOpen=this._onOpen.bind(this),this._onMessage=this._onMessage.bind(this),this._onClose=this._onClose.bind(this),this._onError=this._onError.bind(this),this._handleVisibilityChange=this._handleVisibilityChange.bind(this),this._handleOnline=this._handleOnline.bind(this),this._handleOffline=this._handleOffline.bind(this),this._setupEventListeners(),this.options.autoConnect&&this.connect()}connect(){if(!this.ws||this.ws.readyState!==WebSocket.CONNECTING&&this.ws.readyState!==WebSocket.OPEN){this.forcedClose=!1,this._updateReadyState(WebSocket.CONNECTING),console.log(`[WS] 正在连接到 ${this.url}...`),this._emit("connecting");try{this.ws=new WebSocket(this.url,this.options.protocols),this.ws.onopen=this._onOpen,this.ws.onmessage=this._onMessage,this.ws.onclose=this._onClose,this.ws.onerror=this._onError}catch(t){console.error("[WS] 连接失败:",t),this._onError(t)}}}send(t){if(this.readyState===WebSocket.OPEN){let e;e=this.options.serializeData?JSON.stringify(t):t,this.ws.send(e),console.log("[WS] 消息已发送:",e)}else console.warn("[WS] 连接未打开,消息已加入队列:",t),this.messageQueue.push(t)}close(t=1e3,e="Normal closure"){this.forcedClose=!0,this._stopHeartbeat(),this._clearReconnectTimer(),this.ws&&this.ws.readyState===WebSocket.OPEN?this.ws.close(t,e):(this._updateReadyState(WebSocket.CLOSED),this._emit("close",{code:t,reason:e,wasClean:!0}))}destroy(){console.log("[WS] 正在销毁实例..."),this.close(1e3,"Instance destroyed"),this._removeEventListeners(),this.messageQueue=[],this.listeners.clear(),this.ws=null}on(t,e){this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(e)}off(t,e){if(this.listeners.has(t)){const n=this.listeners.get(t),s=n.indexOf(e);s>-1&&n.splice(s,1)}}_onOpen(t){console.log("[WS] 连接已建立"),this._updateReadyState(WebSocket.OPEN),this.reconnectAttempts=0,this.isReconnecting=!1,this.options.getPingMessage&&this._startHeartbeat(),this._flushMessageQueue(),this._emit("open",t)}_onMessage(t){if(this.options.isPongMessage&&this.options.isPongMessage(t))this._handlePong();else if(this.options.deserializeData)try{const e=JSON.parse(t.data);this._emit("message",e,t)}catch(e){this._emit("message",t.data,t)}else this._emit("message",t.data,t)}_onClose(t){console.log("[WS] 连接已关闭",t),this._updateReadyState(WebSocket.CLOSED),this._stopHeartbeat(),this._emit("close",t),this.forcedClose||this._scheduleReconnect()}_onError(t){console.error("[WS] 连接发生错误:",t),this._emit("error",t)}_startHeartbeat(){this.options.getPingMessage&&(this._stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{const t=this.options.getPingMessage();this.ws.send(t),console.log("[WS] 发送 Ping:",t),this._setHeartbeatTimeout()}catch(t){console.error("[WS] 发送 Ping 消息失败:",t)}},this.options.heartbeatInterval))}_stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this._clearHeartbeatTimeout()}_setHeartbeatTimeout(){this._clearHeartbeatTimeout(),this.heartbeatTimeoutTimer=setTimeout(()=>{console.error("[WS] 心跳超时,主动断开连接"),this.ws.close(1006,"Heartbeat timeout")},this.options.heartbeatTimeout)}_clearHeartbeatTimeout(){this.heartbeatTimeoutTimer&&(clearTimeout(this.heartbeatTimeoutTimer),this.heartbeatTimeoutTimer=null)}_handlePong(){console.log("[WS] 收到 Pong"),this._clearHeartbeatTimeout()}_scheduleReconnect(){if(this.forcedClose||this.isReconnecting||this.reconnectAttempts>=this.options.maxReconnectAttempts)return void(this.reconnectAttempts>=this.options.maxReconnectAttempts&&(console.error("[WS] 已达到最大重连次数,停止重连"),this._emit("reconnect-failed")));this.isReconnecting=!0;const t=Math.min(this.options.reconnectBaseInterval*Math.pow(2,this.reconnectAttempts),this.options.maxReconnectInterval);console.log(`[WS] ${t/1e3}秒后将尝试第 ${this.reconnectAttempts+1} 次重连...`),this._emit("reconnect-attempt",{attempt:this.reconnectAttempts+1,interval:t}),this.reconnectTimer=setTimeout(()=>{this.reconnectAttempts++,this.connect()},t)}_clearReconnectTimer(){this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}_flushMessageQueue(){if(0===this.messageQueue.length)return;console.log(`[WS] 发送队列中的 ${this.messageQueue.length} 条消息`);const t=[...this.messageQueue];this.messageQueue=[],t.forEach(t=>this.send(t))}_emit(t,...e){this.listeners.has(t)&&this.listeners.get(t).forEach(t=>t(...e))}_updateReadyState(t){this.readyState=t,this._emit("ready-state-change",t)}_setupEventListeners(){document.addEventListener("visibilitychange",this._handleVisibilityChange),window.addEventListener("online",this._handleOnline),window.addEventListener("offline",this._handleOffline)}_removeEventListeners(){document.removeEventListener("visibilitychange",this._handleVisibilityChange),window.removeEventListener("online",this._handleOnline),window.removeEventListener("offline",this._handleOffline)}_handleVisibilityChange(){this.options.getPingMessage&&(document.hidden?(console.log("[WS] 页面隐藏,停止心跳"),this._stopHeartbeat()):(console.log("[WS] 页面可见,检查连接状态"),this.ws&&this.ws.readyState===WebSocket.OPEN?this._startHeartbeat():this.forcedClose||this.isReconnecting||this.connect()))}_handleOnline(){console.log("[WS] 网络已恢复,尝试重连"),this.forcedClose||this.readyState===WebSocket.OPEN||(this._clearReconnectTimer(),this.connect())}_handleOffline(){console.log("[WS] 网络已断开"),this._clearReconnectTimer(),this.ws&&this.ws.onclose({code:1006,reason:"Network offline"})}},exports.assignExisting=function(t,...e){return e.forEach(e=>{Object.keys(e).forEach(n=>{t.hasOwnProperty(n)&&(t[n]=e[n])})}),t},exports.calcTimeDifference=function(t,e=new Date){const n=e-new Date(t),s=Math.floor(n/1e3),o=Math.floor(s/86400),i=Math.floor(s%86400/3600),r=Math.floor(s%3600/60),a=s%60,c=t=>String(t).padStart(2,"0");return{days:o,hours:c(i),minutes:c(r),seconds:c(a)}},exports.debounce=function(t,e,n=!1){if("function"!=typeof t)throw new TypeError("fn must be function");let s;e=Math.max(0,Number(e)||0);let o=0;function i(...i){const r=0===o,a=Date.now()-o>=e;if(clearTimeout(s),n&&(r||a))return o=Date.now(),t.apply(this,i);s=setTimeout(()=>{o=Date.now(),t.apply(this,i)},e)}return i.cancel=()=>{clearTimeout(s),o=0},i},exports.deepCloneByJSON=function(t){return JSON.parse(JSON.stringify(t))},exports.downloadByBlob=c,exports.downloadByData=h,exports.downloadByUrl=a,exports.downloadExcel=function(t,e){h(t,e,"application/vnd.ms-excel")},exports.downloadJSON=function(t,e){h(t,e,"application/json")},exports.extractFullyCheckedKeys=function(t,e,n="id",s="children"){const o=new Set(e),i=new Set,r=new Set;return t.forEach(function t(e){const a=e[n],c=e[s]||[];if(!c.length)return o.has(a)?(i.add(a),2):0;let h=!0,l=!1;return c.forEach(e=>{const n=t(e);2!==n&&(h=!1),n>=1&&(l=!0)}),o.has(a)?h?(i.add(a),2):(r.add(a),1):h?(i.add(a),2):l?(r.add(a),1):0}),{checked:[...i],halfChecked:[...r]}},exports.fetchOrDownloadByUrl=async function(t,e){if(!e){try{const n=new URL(t).pathname;e=n.substring(n.lastIndexOf("/")+1).split("?")[0]}catch(t){}e||(e=Date.now().toString())}try{const n=await fetch(t,{method:"GET",mode:"cors",cache:"no-cache"});if(!n.ok)throw new Error(`HTTP error! ${n.status}: ${n.statusText}`);c(await n.blob(),e)}catch(n){a(t,e)}},exports.findObjAttrValueById=function t(e,n,s="name",o="id",i="children"){if(Array.isArray(n)&&n.length>0)for(let r=0;r<n.length;r++){const a=n[r];if(a[o]?.toString()===e?.toString())return a[s];if(Array.isArray(a[i])&&a[i].length>0){const n=t(e,a[i],s,o,i);if(n)return n}}},exports.flatCompleteTree2NestedTree=function(t,e=0,{idKey:n="id",parentKey:s="parentId",childrenKey:o="children"}={}){const i=new Map,r=[];for(const e of t){const t={...e,[o]:[]};i.set(e[n],t)}for(const a of t){const t=i.get(a[n]),c=a[s];if(c===e)r.push(t);else{const e=i.get(c);e&&e[o].push(t)}}return r},exports.formatDuration=i,exports.formatDurationMaxDay=function(t,e={}){return i(t,{...e,maxUnit:"day"})},exports.formatDurationMaxHour=function(t,e={}){return i(t,{...e,maxUnit:"hour"})},exports.formatTimeForLocale=function(t,e={justNow:"刚刚",today:"今天",yesterday:"昨天",beforeYesterday:"前天",year:"年",month:"月",day:"日",timePeriod:{earlyMorning:"凌晨",morning:"上午",noon:"中午",afternoon:"下午",evening:"晚上"},weekDays:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]}){const n=new Date,s=new Date(t),o=n.getTime()-s.getTime(),i=Math.floor(o/6e4),a=s.getFullYear(),c=s.getMonth()+1,h=s.getDate(),l=s.getHours(),u=s.getMinutes().toString().padStart(2,"0");if(i<1)return e.justNow;const f=new Date(n.getFullYear(),n.getMonth(),n.getDate()),d=new Date(a,c-1,h),p=Math.floor((f.getTime()-d.getTime())/864e5),m=r(l,e.timePeriod),g=`${l}:${u}`;if(0===p)return`${e.today} ${m}${g}`;if(1===p)return`${e.yesterday} ${m}${g}`;if(2===p)return`${e.beforeYesterday} ${m}${g}`;const w=n.getDay()||7,y=s.getDay()||7,x=new Date(f.getTime()-24*(w-1)*60*60*1e3),S=new Date(d.getTime()-24*(y-1)*60*60*1e3);if(x.getTime()===S.getTime()&&p<7){return`${e.weekDays[s.getDay()]}${m} ${g}`}const b=n.getFullYear(),_=n.getMonth();return a===b&&s.getMonth()===_||a===b?`${c}${e.month}${h}${e.day} ${m}${g}`:`${a}${e.year}${c}${e.month}${h}${e.day} ${m}${g}`},exports.getAllSearchParams=t,exports.getDataType=e,exports.getFunctionArgNames=function(t){const e=/^\s*(_?)(\S+?)\1\s*$/,n=Function.prototype.toString.call(t).replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,""),s=n.match(/^([^(]+?)=>/)||n.match(/^[^(]*\(\s*([^)]*)\)/m),o=[];return[].forEach.call(s[1].split(/,/),function(t){t.replace(e,function(t,e,n){o.push(n)})}),o},exports.getGUID=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=16*Math.random()|0;return("x"==t?e:3&e|8).toString(16).toUpperCase()})},exports.getSearchParam=function(e){return t()[e]},exports.getTimePeriodName=r,exports.getViewportSize=function(){const t=document,e=t.documentElement,n=t.body;return{w:window.innerWidth||e.clientWidth||n.clientWidth,h:window.innerHeight||e.clientHeight||n.clientHeight}},exports.isBlob=function(t){return"blob"===e(t)},exports.isDate=function(t){return"date"===e(t)},exports.isFunction=function(t){return"function"==typeof t},exports.isNonEmptyString=function(t){return"string"===e(t)&&t.length>0},exports.isPlainObject=function(t){return"object"===e(t)},exports.isPromise=function(t){return"promise"===e(t)},exports.moveItem=function(t,e,n){t.splice(n,0,t.splice(e,1)[0])},exports.nestedTree2IdMap=function(t,e="id",n="children"){const s={};return function t(o){Array.isArray(o)&&o.length>0&&o.forEach(o=>{s[o[e]]={...o},s[o[e]][n]=null,t(o[n])})}(t),s},exports.pcmToWavBlob=function(t,e=16e3){const n=t.length,s=new ArrayBuffer(44+2*n),o=new DataView(s),i=(t,e)=>{for(let n=0;n<e.length;n++)o.setUint8(t+n,e.charCodeAt(n))};i(0,"RIFF"),o.setUint32(4,36+2*n,!0),i(8,"WAVE"),i(12,"fmt "),o.setUint32(16,16,!0),o.setUint16(20,1,!0),o.setUint16(22,1,!0),o.setUint32(24,e,!0),o.setUint32(28,2*e,!0),o.setUint16(32,2,!0),o.setUint16(34,16,!0),i(36,"data"),o.setUint32(40,2*n,!0);let r=44;for(let e=0;e<n;e++)o.setInt16(r,t[e],!0),r+=2;return new Blob([s],{type:"audio/wav"})},exports.randomDateInRange=function(t,e){let n=t.getTime(),s=e.getTime();return n>s&&([n,s]=[s,n]),new Date(n+Math.floor(Math.random()*(s-n+1)))},exports.randomEnLetter=o,exports.randomHan=s,exports.randomHanOrEn=function(t,e=.5){t=Math.max(1,Math.floor(t));const n=[];for(let i=0;i<t;i++)n.push(Math.random()<e?s():o());return n.join("")},exports.randomIntInRange=n,exports.readBlobAsText=function(t,e=!0){return new Promise((n,s)=>{const o=new FileReader;o.onload=t=>{const s=t.target.result;if(e)try{n(JSON.parse(s))}catch(t){console.error(t),n(s)}else n(s)},o.onerror=s,o.readAsText(t)})},exports.shuffle=function(t){for(let e=t.length-1;e>0;e--){const n=Math.floor(Math.random()*(e+1));[t[e],t[n]]=[t[n],t[e]]}return t},exports.throttle=function(t,e,{leading:n=!0,trailing:s=!0}={}){if("function"!=typeof t)throw new TypeError("fn must be function");e=Math.max(0,Number(e)||0);let o=null,i=0;function r(...r){const a=e-(Date.now()-i);n&&(0===i||a<=0)?(i=Date.now(),t.apply(this,r)):s&&!o&&(o=setTimeout(()=>{o=null,i=Date.now(),t.apply(this,r)},a>0?a:e))}return r.cancel=()=>{clearTimeout(o),o=null,i=0},r},exports.toDate=function(t){if(null==t)return null;if(t instanceof Date)return isNaN(t)?null:t;if("number"==typeof t||"string"==typeof t&&/^-?\d+(\.\d+)?$/.test(t.trim())){const e=new Date(+t);return isNaN(e)?null:e}if("string"==typeof t){const e=new Date(t);return isNaN(e)?null:e}if("object"==typeof t){const e=t.valueOf?t.valueOf():Object.prototype.valueOf.call(t);if("number"==typeof e&&!isNaN(e)){const t=new Date(e);return isNaN(t)?null:t}const n=t.toString?t.toString():String(t),s=new Date(n);return isNaN(s)?null:s}return null};
|
|
2
2
|
//# sourceMappingURL=a2bei4.utils.cjs.min.js.map
|