collabdocchat 2.5.13 → 2.5.14

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.
@@ -1,9 +1,9 @@
1
- (function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const m of document.querySelectorAll('link[rel="modulepreload"]'))s(m);new MutationObserver(m=>{for(const l of m)if(l.type==="childList")for(const c of l.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&s(c)}).observe(document,{childList:!0,subtree:!0});function i(m){const l={};return m.integrity&&(l.integrity=m.integrity),m.referrerPolicy&&(l.referrerPolicy=m.referrerPolicy),m.crossOrigin==="use-credentials"?l.credentials="include":m.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function s(m){if(m.ep)return;m.ep=!0;const l=i(m);fetch(m.href,l)}})();function on(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var zt={},Ke={};Ke.byteLength=ln;Ke.toByteArray=pn;Ke.fromByteArray=mn;var Le=[],ke=[],sn=typeof Uint8Array<"u"?Uint8Array:Array,Xe="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var ze=0,dn=Xe.length;ze<dn;++ze)Le[ze]=Xe[ze],ke[Xe.charCodeAt(ze)]=ze;ke[45]=62;ke[95]=63;function Dt(r){var t=r.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var i=r.indexOf("=");i===-1&&(i=t);var s=i===t?0:4-i%4;return[i,s]}function ln(r){var t=Dt(r),i=t[0],s=t[1];return(i+s)*3/4-s}function cn(r,t,i){return(t+i)*3/4-i}function pn(r){var t,i=Dt(r),s=i[0],m=i[1],l=new sn(cn(r,s,m)),c=0,u=m>0?s-4:s,P;for(P=0;P<u;P+=4)t=ke[r.charCodeAt(P)]<<18|ke[r.charCodeAt(P+1)]<<12|ke[r.charCodeAt(P+2)]<<6|ke[r.charCodeAt(P+3)],l[c++]=t>>16&255,l[c++]=t>>8&255,l[c++]=t&255;return m===2&&(t=ke[r.charCodeAt(P)]<<2|ke[r.charCodeAt(P+1)]>>4,l[c++]=t&255),m===1&&(t=ke[r.charCodeAt(P)]<<10|ke[r.charCodeAt(P+1)]<<4|ke[r.charCodeAt(P+2)]>>2,l[c++]=t>>8&255,l[c++]=t&255),l}function un(r){return Le[r>>18&63]+Le[r>>12&63]+Le[r>>6&63]+Le[r&63]}function gn(r,t,i){for(var s,m=[],l=t;l<i;l+=3)s=(r[l]<<16&16711680)+(r[l+1]<<8&65280)+(r[l+2]&255),m.push(un(s));return m.join("")}function mn(r){for(var t,i=r.length,s=i%3,m=[],l=16383,c=0,u=i-s;c<u;c+=l)m.push(gn(r,c,c+l>u?u:c+l));return s===1?(t=r[i-1],m.push(Le[t>>2]+Le[t<<4&63]+"==")):s===2&&(t=(r[i-2]<<8)+r[i-1],m.push(Le[t>>10]+Le[t>>4&63]+Le[t<<2&63]+"=")),m.join("")}var yt={};/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */yt.read=function(r,t,i,s,m){var l,c,u=m*8-s-1,P=(1<<u)-1,A=P>>1,D=-7,R=i?m-1:0,F=i?-1:1,W=r[t+R];for(R+=F,l=W&(1<<-D)-1,W>>=-D,D+=u;D>0;l=l*256+r[t+R],R+=F,D-=8);for(c=l&(1<<-D)-1,l>>=-D,D+=s;D>0;c=c*256+r[t+R],R+=F,D-=8);if(l===0)l=1-A;else{if(l===P)return c?NaN:(W?-1:1)*(1/0);c=c+Math.pow(2,s),l=l-A}return(W?-1:1)*c*Math.pow(2,l-s)};yt.write=function(r,t,i,s,m,l){var c,u,P,A=l*8-m-1,D=(1<<A)-1,R=D>>1,F=m===23?Math.pow(2,-24)-Math.pow(2,-77):0,W=s?0:l-1,ue=s?1:-1,oe=t<0||t===0&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(u=isNaN(t)?1:0,c=D):(c=Math.floor(Math.log(t)/Math.LN2),t*(P=Math.pow(2,-c))<1&&(c--,P*=2),c+R>=1?t+=F/P:t+=F*Math.pow(2,1-R),t*P>=2&&(c++,P/=2),c+R>=D?(u=0,c=D):c+R>=1?(u=(t*P-1)*Math.pow(2,m),c=c+R):(u=t*Math.pow(2,R-1)*Math.pow(2,m),c=0));m>=8;r[i+W]=u&255,W+=ue,u/=256,m-=8);for(c=c<<m|u,A+=m;A>0;r[i+W]=c&255,W+=ue,c/=256,A-=8);r[i+W-ue]|=oe*128};(function(r){/*!
1
+ (function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const m of document.querySelectorAll('link[rel="modulepreload"]'))s(m);new MutationObserver(m=>{for(const l of m)if(l.type==="childList")for(const c of l.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&s(c)}).observe(document,{childList:!0,subtree:!0});function i(m){const l={};return m.integrity&&(l.integrity=m.integrity),m.referrerPolicy&&(l.referrerPolicy=m.referrerPolicy),m.crossOrigin==="use-credentials"?l.credentials="include":m.crossOrigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function s(m){if(m.ep)return;m.ep=!0;const l=i(m);fetch(m.href,l)}})();function on(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var At={},Ke={};Ke.byteLength=ln;Ke.toByteArray=pn;Ke.fromByteArray=mn;var Le=[],ke=[],sn=typeof Uint8Array<"u"?Uint8Array:Array,Xe="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";for(var Ae=0,dn=Xe.length;Ae<dn;++Ae)Le[Ae]=Xe[Ae],ke[Xe.charCodeAt(Ae)]=Ae;ke[45]=62;ke[95]=63;function zt(r){var t=r.length;if(t%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var i=r.indexOf("=");i===-1&&(i=t);var s=i===t?0:4-i%4;return[i,s]}function ln(r){var t=zt(r),i=t[0],s=t[1];return(i+s)*3/4-s}function cn(r,t,i){return(t+i)*3/4-i}function pn(r){var t,i=zt(r),s=i[0],m=i[1],l=new sn(cn(r,s,m)),c=0,u=m>0?s-4:s,F;for(F=0;F<u;F+=4)t=ke[r.charCodeAt(F)]<<18|ke[r.charCodeAt(F+1)]<<12|ke[r.charCodeAt(F+2)]<<6|ke[r.charCodeAt(F+3)],l[c++]=t>>16&255,l[c++]=t>>8&255,l[c++]=t&255;return m===2&&(t=ke[r.charCodeAt(F)]<<2|ke[r.charCodeAt(F+1)]>>4,l[c++]=t&255),m===1&&(t=ke[r.charCodeAt(F)]<<10|ke[r.charCodeAt(F+1)]<<4|ke[r.charCodeAt(F+2)]>>2,l[c++]=t>>8&255,l[c++]=t&255),l}function un(r){return Le[r>>18&63]+Le[r>>12&63]+Le[r>>6&63]+Le[r&63]}function gn(r,t,i){for(var s,m=[],l=t;l<i;l+=3)s=(r[l]<<16&16711680)+(r[l+1]<<8&65280)+(r[l+2]&255),m.push(un(s));return m.join("")}function mn(r){for(var t,i=r.length,s=i%3,m=[],l=16383,c=0,u=i-s;c<u;c+=l)m.push(gn(r,c,c+l>u?u:c+l));return s===1?(t=r[i-1],m.push(Le[t>>2]+Le[t<<4&63]+"==")):s===2&&(t=(r[i-2]<<8)+r[i-1],m.push(Le[t>>10]+Le[t>>4&63]+Le[t<<2&63]+"=")),m.join("")}var yt={};/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */yt.read=function(r,t,i,s,m){var l,c,u=m*8-s-1,F=(1<<u)-1,D=F>>1,z=-7,R=i?m-1:0,U=i?-1:1,W=r[t+R];for(R+=U,l=W&(1<<-z)-1,W>>=-z,z+=u;z>0;l=l*256+r[t+R],R+=U,z-=8);for(c=l&(1<<-z)-1,l>>=-z,z+=s;z>0;c=c*256+r[t+R],R+=U,z-=8);if(l===0)l=1-D;else{if(l===F)return c?NaN:(W?-1:1)*(1/0);c=c+Math.pow(2,s),l=l-D}return(W?-1:1)*c*Math.pow(2,l-s)};yt.write=function(r,t,i,s,m,l){var c,u,F,D=l*8-m-1,z=(1<<D)-1,R=z>>1,U=m===23?Math.pow(2,-24)-Math.pow(2,-77):0,W=s?0:l-1,ue=s?1:-1,oe=t<0||t===0&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(u=isNaN(t)?1:0,c=z):(c=Math.floor(Math.log(t)/Math.LN2),t*(F=Math.pow(2,-c))<1&&(c--,F*=2),c+R>=1?t+=U/F:t+=U*Math.pow(2,1-R),t*F>=2&&(c++,F/=2),c+R>=z?(u=0,c=z):c+R>=1?(u=(t*F-1)*Math.pow(2,m),c=c+R):(u=t*Math.pow(2,R-1)*Math.pow(2,m),c=0));m>=8;r[i+W]=u&255,W+=ue,u/=256,m-=8);for(c=c<<m|u,D+=m;D>0;r[i+W]=c&255,W+=ue,c/=256,D-=8);r[i+W-ue]|=oe*128};/*!
2
2
  * The buffer module from node.js, for the browser.
3
3
  *
4
4
  * @author Feross Aboukhadijeh <https://feross.org>
5
5
  * @license MIT
6
- */const t=Ke,i=yt,s=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;r.Buffer=u,r.SlowBuffer=K,r.INSPECT_MAX_BYTES=50;const m=2147483647;r.kMaxLength=m,u.TYPED_ARRAY_SUPPORT=l(),!u.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function l(){try{const a=new Uint8Array(1),e={foo:function(){return 42}};return Object.setPrototypeOf(e,Uint8Array.prototype),Object.setPrototypeOf(a,e),a.foo()===42}catch{return!1}}Object.defineProperty(u.prototype,"parent",{enumerable:!0,get:function(){if(u.isBuffer(this))return this.buffer}}),Object.defineProperty(u.prototype,"offset",{enumerable:!0,get:function(){if(u.isBuffer(this))return this.byteOffset}});function c(a){if(a>m)throw new RangeError('The value "'+a+'" is invalid for option "size"');const e=new Uint8Array(a);return Object.setPrototypeOf(e,u.prototype),e}function u(a,e,n){if(typeof a=="number"){if(typeof e=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return R(a)}return P(a,e,n)}u.poolSize=8192;function P(a,e,n){if(typeof a=="string")return F(a,e);if(ArrayBuffer.isView(a))return ue(a);if(a==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof a);if(q(a,ArrayBuffer)||a&&q(a.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(q(a,SharedArrayBuffer)||a&&q(a.buffer,SharedArrayBuffer)))return oe(a,e,n);if(typeof a=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');const d=a.valueOf&&a.valueOf();if(d!=null&&d!==a)return u.from(d,e,n);const y=be(a);if(y)return y;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof a[Symbol.toPrimitive]=="function")return u.from(a[Symbol.toPrimitive]("string"),e,n);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof a)}u.from=function(a,e,n){return P(a,e,n)},Object.setPrototypeOf(u.prototype,Uint8Array.prototype),Object.setPrototypeOf(u,Uint8Array);function A(a){if(typeof a!="number")throw new TypeError('"size" argument must be of type number');if(a<0)throw new RangeError('The value "'+a+'" is invalid for option "size"')}function D(a,e,n){return A(a),a<=0?c(a):e!==void 0?typeof n=="string"?c(a).fill(e,n):c(a).fill(e):c(a)}u.alloc=function(a,e,n){return D(a,e,n)};function R(a){return A(a),c(a<0?0:xe(a)|0)}u.allocUnsafe=function(a){return R(a)},u.allocUnsafeSlow=function(a){return R(a)};function F(a,e){if((typeof e!="string"||e==="")&&(e="utf8"),!u.isEncoding(e))throw new TypeError("Unknown encoding: "+e);const n=te(a,e)|0;let d=c(n);const y=d.write(a,e);return y!==n&&(d=d.slice(0,y)),d}function W(a){const e=a.length<0?0:xe(a.length)|0,n=c(e);for(let d=0;d<e;d+=1)n[d]=a[d]&255;return n}function ue(a){if(q(a,Uint8Array)){const e=new Uint8Array(a);return oe(e.buffer,e.byteOffset,e.byteLength)}return W(a)}function oe(a,e,n){if(e<0||a.byteLength<e)throw new RangeError('"offset" is outside of buffer bounds');if(a.byteLength<e+(n||0))throw new RangeError('"length" is outside of buffer bounds');let d;return e===void 0&&n===void 0?d=new Uint8Array(a):n===void 0?d=new Uint8Array(a,e):d=new Uint8Array(a,e,n),Object.setPrototypeOf(d,u.prototype),d}function be(a){if(u.isBuffer(a)){const e=xe(a.length)|0,n=c(e);return n.length===0||a.copy(n,0,0,e),n}if(a.length!==void 0)return typeof a.length!="number"||re(a.length)?c(0):W(a);if(a.type==="Buffer"&&Array.isArray(a.data))return W(a.data)}function xe(a){if(a>=m)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+m.toString(16)+" bytes");return a|0}function K(a){return+a!=a&&(a=0),u.alloc(+a)}u.isBuffer=function(e){return e!=null&&e._isBuffer===!0&&e!==u.prototype},u.compare=function(e,n){if(q(e,Uint8Array)&&(e=u.from(e,e.offset,e.byteLength)),q(n,Uint8Array)&&(n=u.from(n,n.offset,n.byteLength)),!u.isBuffer(e)||!u.isBuffer(n))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(e===n)return 0;let d=e.length,y=n.length;for(let f=0,I=Math.min(d,y);f<I;++f)if(e[f]!==n[f]){d=e[f],y=n[f];break}return d<y?-1:y<d?1:0},u.isEncoding=function(e){switch(String(e).toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"latin1":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},u.concat=function(e,n){if(!Array.isArray(e))throw new TypeError('"list" argument must be an Array of Buffers');if(e.length===0)return u.alloc(0);let d;if(n===void 0)for(n=0,d=0;d<e.length;++d)n+=e[d].length;const y=u.allocUnsafe(n);let f=0;for(d=0;d<e.length;++d){let I=e[d];if(q(I,Uint8Array))f+I.length>y.length?(u.isBuffer(I)||(I=u.from(I)),I.copy(y,f)):Uint8Array.prototype.set.call(y,I,f);else if(u.isBuffer(I))I.copy(y,f);else throw new TypeError('"list" argument must be an Array of Buffers');f+=I.length}return y};function te(a,e){if(u.isBuffer(a))return a.length;if(ArrayBuffer.isView(a)||q(a,ArrayBuffer))return a.byteLength;if(typeof a!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof a);const n=a.length,d=arguments.length>2&&arguments[2]===!0;if(!d&&n===0)return 0;let y=!1;for(;;)switch(e){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":return ee(a).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return n*2;case"hex":return n>>>1;case"base64":return T(a).length;default:if(y)return d?-1:ee(a).length;e=(""+e).toLowerCase(),y=!0}}u.byteLength=te;function me(a,e,n){let d=!1;if((e===void 0||e<0)&&(e=0),e>this.length||((n===void 0||n>this.length)&&(n=this.length),n<=0)||(n>>>=0,e>>>=0,n<=e))return"";for(a||(a="utf8");;)switch(a){case"hex":return ie(this,e,n);case"utf8":case"utf-8":return _(this,e,n);case"ascii":return Y(this,e,n);case"latin1":case"binary":return fe(this,e,n);case"base64":return H(this,e,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return we(this,e,n);default:if(d)throw new TypeError("Unknown encoding: "+a);a=(a+"").toLowerCase(),d=!0}}u.prototype._isBuffer=!0;function se(a,e,n){const d=a[e];a[e]=a[n],a[n]=d}u.prototype.swap16=function(){const e=this.length;if(e%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let n=0;n<e;n+=2)se(this,n,n+1);return this},u.prototype.swap32=function(){const e=this.length;if(e%4!==0)throw new RangeError("Buffer size must be a multiple of 32-bits");for(let n=0;n<e;n+=4)se(this,n,n+3),se(this,n+1,n+2);return this},u.prototype.swap64=function(){const e=this.length;if(e%8!==0)throw new RangeError("Buffer size must be a multiple of 64-bits");for(let n=0;n<e;n+=8)se(this,n,n+7),se(this,n+1,n+6),se(this,n+2,n+5),se(this,n+3,n+4);return this},u.prototype.toString=function(){const e=this.length;return e===0?"":arguments.length===0?_(this,0,e):me.apply(this,arguments)},u.prototype.toLocaleString=u.prototype.toString,u.prototype.equals=function(e){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e?!0:u.compare(this,e)===0},u.prototype.inspect=function(){let e="";const n=r.INSPECT_MAX_BYTES;return e=this.toString("hex",0,n).replace(/(.{2})/g,"$1 ").trim(),this.length>n&&(e+=" ... "),"<Buffer "+e+">"},s&&(u.prototype[s]=u.prototype.inspect),u.prototype.compare=function(e,n,d,y,f){if(q(e,Uint8Array)&&(e=u.from(e,e.offset,e.byteLength)),!u.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(n===void 0&&(n=0),d===void 0&&(d=e?e.length:0),y===void 0&&(y=0),f===void 0&&(f=this.length),n<0||d>e.length||y<0||f>this.length)throw new RangeError("out of range index");if(y>=f&&n>=d)return 0;if(y>=f)return-1;if(n>=d)return 1;if(n>>>=0,d>>>=0,y>>>=0,f>>>=0,this===e)return 0;let I=f-y,Q=d-n;const ge=Math.min(I,Q),ce=this.slice(y,f),ye=e.slice(n,d);for(let le=0;le<ge;++le)if(ce[le]!==ye[le]){I=ce[le],Q=ye[le];break}return I<Q?-1:Q<I?1:0};function ve(a,e,n,d,y){if(a.length===0)return-1;if(typeof n=="string"?(d=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,re(n)&&(n=y?0:a.length-1),n<0&&(n=a.length+n),n>=a.length){if(y)return-1;n=a.length-1}else if(n<0)if(y)n=0;else return-1;if(typeof e=="string"&&(e=u.from(e,d)),u.isBuffer(e))return e.length===0?-1:U(a,e,n,d,y);if(typeof e=="number")return e=e&255,typeof Uint8Array.prototype.indexOf=="function"?y?Uint8Array.prototype.indexOf.call(a,e,n):Uint8Array.prototype.lastIndexOf.call(a,e,n):U(a,[e],n,d,y);throw new TypeError("val must be string, number or Buffer")}function U(a,e,n,d,y){let f=1,I=a.length,Q=e.length;if(d!==void 0&&(d=String(d).toLowerCase(),d==="ucs2"||d==="ucs-2"||d==="utf16le"||d==="utf-16le")){if(a.length<2||e.length<2)return-1;f=2,I/=2,Q/=2,n/=2}function ge(ye,le){return f===1?ye[le]:ye.readUInt16BE(le*f)}let ce;if(y){let ye=-1;for(ce=n;ce<I;ce++)if(ge(a,ce)===ge(e,ye===-1?0:ce-ye)){if(ye===-1&&(ye=ce),ce-ye+1===Q)return ye*f}else ye!==-1&&(ce-=ce-ye),ye=-1}else for(n+Q>I&&(n=I-Q),ce=n;ce>=0;ce--){let ye=!0;for(let le=0;le<Q;le++)if(ge(a,ce+le)!==ge(e,le)){ye=!1;break}if(ye)return ce}return-1}u.prototype.includes=function(e,n,d){return this.indexOf(e,n,d)!==-1},u.prototype.indexOf=function(e,n,d){return ve(this,e,n,d,!0)},u.prototype.lastIndexOf=function(e,n,d){return ve(this,e,n,d,!1)};function z(a,e,n,d){n=Number(n)||0;const y=a.length-n;d?(d=Number(d),d>y&&(d=y)):d=y;const f=e.length;d>f/2&&(d=f/2);let I;for(I=0;I<d;++I){const Q=parseInt(e.substr(I*2,2),16);if(re(Q))return I;a[n+I]=Q}return I}function V(a,e,n,d){return X(ee(e,a.length-n),a,n,d)}function $(a,e,n,d){return X(S(e),a,n,d)}function M(a,e,n,d){return X(T(e),a,n,d)}function N(a,e,n,d){return X(j(e,a.length-n),a,n,d)}u.prototype.write=function(e,n,d,y){if(n===void 0)y="utf8",d=this.length,n=0;else if(d===void 0&&typeof n=="string")y=n,d=this.length,n=0;else if(isFinite(n))n=n>>>0,isFinite(d)?(d=d>>>0,y===void 0&&(y="utf8")):(y=d,d=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");const f=this.length-n;if((d===void 0||d>f)&&(d=f),e.length>0&&(d<0||n<0)||n>this.length)throw new RangeError("Attempt to write outside buffer bounds");y||(y="utf8");let I=!1;for(;;)switch(y){case"hex":return z(this,e,n,d);case"utf8":case"utf-8":return V(this,e,n,d);case"ascii":case"latin1":case"binary":return $(this,e,n,d);case"base64":return M(this,e,n,d);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return N(this,e,n,d);default:if(I)throw new TypeError("Unknown encoding: "+y);y=(""+y).toLowerCase(),I=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function H(a,e,n){return e===0&&n===a.length?t.fromByteArray(a):t.fromByteArray(a.slice(e,n))}function _(a,e,n){n=Math.min(a.length,n);const d=[];let y=e;for(;y<n;){const f=a[y];let I=null,Q=f>239?4:f>223?3:f>191?2:1;if(y+Q<=n){let ge,ce,ye,le;switch(Q){case 1:f<128&&(I=f);break;case 2:ge=a[y+1],(ge&192)===128&&(le=(f&31)<<6|ge&63,le>127&&(I=le));break;case 3:ge=a[y+1],ce=a[y+2],(ge&192)===128&&(ce&192)===128&&(le=(f&15)<<12|(ge&63)<<6|ce&63,le>2047&&(le<55296||le>57343)&&(I=le));break;case 4:ge=a[y+1],ce=a[y+2],ye=a[y+3],(ge&192)===128&&(ce&192)===128&&(ye&192)===128&&(le=(f&15)<<18|(ge&63)<<12|(ce&63)<<6|ye&63,le>65535&&le<1114112&&(I=le))}}I===null?(I=65533,Q=1):I>65535&&(I-=65536,d.push(I>>>10&1023|55296),I=56320|I&1023),d.push(I),y+=Q}return Z(d)}const O=4096;function Z(a){const e=a.length;if(e<=O)return String.fromCharCode.apply(String,a);let n="",d=0;for(;d<e;)n+=String.fromCharCode.apply(String,a.slice(d,d+=O));return n}function Y(a,e,n){let d="";n=Math.min(a.length,n);for(let y=e;y<n;++y)d+=String.fromCharCode(a[y]&127);return d}function fe(a,e,n){let d="";n=Math.min(a.length,n);for(let y=e;y<n;++y)d+=String.fromCharCode(a[y]);return d}function ie(a,e,n){const d=a.length;(!e||e<0)&&(e=0),(!n||n<0||n>d)&&(n=d);let y="";for(let f=e;f<n;++f)y+=de[a[f]];return y}function we(a,e,n){const d=a.slice(e,n);let y="";for(let f=0;f<d.length-1;f+=2)y+=String.fromCharCode(d[f]+d[f+1]*256);return y}u.prototype.slice=function(e,n){const d=this.length;e=~~e,n=n===void 0?d:~~n,e<0?(e+=d,e<0&&(e=0)):e>d&&(e=d),n<0?(n+=d,n<0&&(n=0)):n>d&&(n=d),n<e&&(n=e);const y=this.subarray(e,n);return Object.setPrototypeOf(y,u.prototype),y};function ae(a,e,n){if(a%1!==0||a<0)throw new RangeError("offset is not uint");if(a+e>n)throw new RangeError("Trying to access beyond buffer length")}u.prototype.readUintLE=u.prototype.readUIntLE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=this[e],f=1,I=0;for(;++I<n&&(f*=256);)y+=this[e+I]*f;return y},u.prototype.readUintBE=u.prototype.readUIntBE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=this[e+--n],f=1;for(;n>0&&(f*=256);)y+=this[e+--n]*f;return y},u.prototype.readUint8=u.prototype.readUInt8=function(e,n){return e=e>>>0,n||ae(e,1,this.length),this[e]},u.prototype.readUint16LE=u.prototype.readUInt16LE=function(e,n){return e=e>>>0,n||ae(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUint16BE=u.prototype.readUInt16BE=function(e,n){return e=e>>>0,n||ae(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUint32LE=u.prototype.readUInt32LE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+this[e+3]*16777216},u.prototype.readUint32BE=u.prototype.readUInt32BE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),this[e]*16777216+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readBigUInt64LE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=n+this[++e]*2**8+this[++e]*2**16+this[++e]*2**24,f=this[++e]+this[++e]*2**8+this[++e]*2**16+d*2**24;return BigInt(y)+(BigInt(f)<<BigInt(32))}),u.prototype.readBigUInt64BE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=n*2**24+this[++e]*2**16+this[++e]*2**8+this[++e],f=this[++e]*2**24+this[++e]*2**16+this[++e]*2**8+d;return(BigInt(y)<<BigInt(32))+BigInt(f)}),u.prototype.readIntLE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=this[e],f=1,I=0;for(;++I<n&&(f*=256);)y+=this[e+I]*f;return f*=128,y>=f&&(y-=Math.pow(2,8*n)),y},u.prototype.readIntBE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=n,f=1,I=this[e+--y];for(;y>0&&(f*=256);)I+=this[e+--y]*f;return f*=128,I>=f&&(I-=Math.pow(2,8*n)),I},u.prototype.readInt8=function(e,n){return e=e>>>0,n||ae(e,1,this.length),this[e]&128?(255-this[e]+1)*-1:this[e]},u.prototype.readInt16LE=function(e,n){e=e>>>0,n||ae(e,2,this.length);const d=this[e]|this[e+1]<<8;return d&32768?d|4294901760:d},u.prototype.readInt16BE=function(e,n){e=e>>>0,n||ae(e,2,this.length);const d=this[e+1]|this[e]<<8;return d&32768?d|4294901760:d},u.prototype.readInt32LE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readBigInt64LE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=this[e+4]+this[e+5]*2**8+this[e+6]*2**16+(d<<24);return(BigInt(y)<<BigInt(32))+BigInt(n+this[++e]*2**8+this[++e]*2**16+this[++e]*2**24)}),u.prototype.readBigInt64BE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=(n<<24)+this[++e]*2**16+this[++e]*2**8+this[++e];return(BigInt(y)<<BigInt(32))+BigInt(this[++e]*2**24+this[++e]*2**16+this[++e]*2**8+d)}),u.prototype.readFloatLE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),i.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),i.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,n){return e=e>>>0,n||ae(e,8,this.length),i.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,n){return e=e>>>0,n||ae(e,8,this.length),i.read(this,e,!1,52,8)};function v(a,e,n,d,y,f){if(!u.isBuffer(a))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>y||e<f)throw new RangeError('"value" argument is out of bounds');if(n+d>a.length)throw new RangeError("Index out of range")}u.prototype.writeUintLE=u.prototype.writeUIntLE=function(e,n,d,y){if(e=+e,n=n>>>0,d=d>>>0,!y){const Q=Math.pow(2,8*d)-1;v(this,e,n,d,Q,0)}let f=1,I=0;for(this[n]=e&255;++I<d&&(f*=256);)this[n+I]=e/f&255;return n+d},u.prototype.writeUintBE=u.prototype.writeUIntBE=function(e,n,d,y){if(e=+e,n=n>>>0,d=d>>>0,!y){const Q=Math.pow(2,8*d)-1;v(this,e,n,d,Q,0)}let f=d-1,I=1;for(this[n+f]=e&255;--f>=0&&(I*=256);)this[n+f]=e/I&255;return n+d},u.prototype.writeUint8=u.prototype.writeUInt8=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,1,255,0),this[n]=e&255,n+1},u.prototype.writeUint16LE=u.prototype.writeUInt16LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,65535,0),this[n]=e&255,this[n+1]=e>>>8,n+2},u.prototype.writeUint16BE=u.prototype.writeUInt16BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,65535,0),this[n]=e>>>8,this[n+1]=e&255,n+2},u.prototype.writeUint32LE=u.prototype.writeUInt32LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,4294967295,0),this[n+3]=e>>>24,this[n+2]=e>>>16,this[n+1]=e>>>8,this[n]=e&255,n+4},u.prototype.writeUint32BE=u.prototype.writeUInt32BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,4294967295,0),this[n]=e>>>24,this[n+1]=e>>>16,this[n+2]=e>>>8,this[n+3]=e&255,n+4};function x(a,e,n,d,y){b(e,d,y,a,n,7);let f=Number(e&BigInt(4294967295));a[n++]=f,f=f>>8,a[n++]=f,f=f>>8,a[n++]=f,f=f>>8,a[n++]=f;let I=Number(e>>BigInt(32)&BigInt(4294967295));return a[n++]=I,I=I>>8,a[n++]=I,I=I>>8,a[n++]=I,I=I>>8,a[n++]=I,n}function w(a,e,n,d,y){b(e,d,y,a,n,7);let f=Number(e&BigInt(4294967295));a[n+7]=f,f=f>>8,a[n+6]=f,f=f>>8,a[n+5]=f,f=f>>8,a[n+4]=f;let I=Number(e>>BigInt(32)&BigInt(4294967295));return a[n+3]=I,I=I>>8,a[n+2]=I,I=I>>8,a[n+1]=I,I=I>>8,a[n]=I,n+8}u.prototype.writeBigUInt64LE=ne(function(e,n=0){return x(this,e,n,BigInt(0),BigInt("0xffffffffffffffff"))}),u.prototype.writeBigUInt64BE=ne(function(e,n=0){return w(this,e,n,BigInt(0),BigInt("0xffffffffffffffff"))}),u.prototype.writeIntLE=function(e,n,d,y){if(e=+e,n=n>>>0,!y){const ge=Math.pow(2,8*d-1);v(this,e,n,d,ge-1,-ge)}let f=0,I=1,Q=0;for(this[n]=e&255;++f<d&&(I*=256);)e<0&&Q===0&&this[n+f-1]!==0&&(Q=1),this[n+f]=(e/I>>0)-Q&255;return n+d},u.prototype.writeIntBE=function(e,n,d,y){if(e=+e,n=n>>>0,!y){const ge=Math.pow(2,8*d-1);v(this,e,n,d,ge-1,-ge)}let f=d-1,I=1,Q=0;for(this[n+f]=e&255;--f>=0&&(I*=256);)e<0&&Q===0&&this[n+f+1]!==0&&(Q=1),this[n+f]=(e/I>>0)-Q&255;return n+d},u.prototype.writeInt8=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,1,127,-128),e<0&&(e=255+e+1),this[n]=e&255,n+1},u.prototype.writeInt16LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,32767,-32768),this[n]=e&255,this[n+1]=e>>>8,n+2},u.prototype.writeInt16BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,32767,-32768),this[n]=e>>>8,this[n+1]=e&255,n+2},u.prototype.writeInt32LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,2147483647,-2147483648),this[n]=e&255,this[n+1]=e>>>8,this[n+2]=e>>>16,this[n+3]=e>>>24,n+4},u.prototype.writeInt32BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[n]=e>>>24,this[n+1]=e>>>16,this[n+2]=e>>>8,this[n+3]=e&255,n+4},u.prototype.writeBigInt64LE=ne(function(e,n=0){return x(this,e,n,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))}),u.prototype.writeBigInt64BE=ne(function(e,n=0){return w(this,e,n,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))});function B(a,e,n,d,y,f){if(n+d>a.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(a,e,n,d,y){return e=+e,n=n>>>0,y||B(a,e,n,4),i.write(a,e,n,d,23,4),n+4}u.prototype.writeFloatLE=function(e,n,d){return L(this,e,n,!0,d)},u.prototype.writeFloatBE=function(e,n,d){return L(this,e,n,!1,d)};function k(a,e,n,d,y){return e=+e,n=n>>>0,y||B(a,e,n,8),i.write(a,e,n,d,52,8),n+8}u.prototype.writeDoubleLE=function(e,n,d){return k(this,e,n,!0,d)},u.prototype.writeDoubleBE=function(e,n,d){return k(this,e,n,!1,d)},u.prototype.copy=function(e,n,d,y){if(!u.isBuffer(e))throw new TypeError("argument should be a Buffer");if(d||(d=0),!y&&y!==0&&(y=this.length),n>=e.length&&(n=e.length),n||(n=0),y>0&&y<d&&(y=d),y===d||e.length===0||this.length===0)return 0;if(n<0)throw new RangeError("targetStart out of bounds");if(d<0||d>=this.length)throw new RangeError("Index out of range");if(y<0)throw new RangeError("sourceEnd out of bounds");y>this.length&&(y=this.length),e.length-n<y-d&&(y=e.length-n+d);const f=y-d;return this===e&&typeof Uint8Array.prototype.copyWithin=="function"?this.copyWithin(n,d,y):Uint8Array.prototype.set.call(e,this.subarray(d,y),n),f},u.prototype.fill=function(e,n,d,y){if(typeof e=="string"){if(typeof n=="string"?(y=n,n=0,d=this.length):typeof d=="string"&&(y=d,d=this.length),y!==void 0&&typeof y!="string")throw new TypeError("encoding must be a string");if(typeof y=="string"&&!u.isEncoding(y))throw new TypeError("Unknown encoding: "+y);if(e.length===1){const I=e.charCodeAt(0);(y==="utf8"&&I<128||y==="latin1")&&(e=I)}}else typeof e=="number"?e=e&255:typeof e=="boolean"&&(e=Number(e));if(n<0||this.length<n||this.length<d)throw new RangeError("Out of range index");if(d<=n)return this;n=n>>>0,d=d===void 0?this.length:d>>>0,e||(e=0);let f;if(typeof e=="number")for(f=n;f<d;++f)this[f]=e;else{const I=u.isBuffer(e)?e:u.from(e,y),Q=I.length;if(Q===0)throw new TypeError('The value "'+e+'" is invalid for argument "value"');for(f=0;f<d-n;++f)this[f+n]=I[f%Q]}return this};const p={};function h(a,e,n){p[a]=class extends n{constructor(){super(),Object.defineProperty(this,"message",{value:e.apply(this,arguments),writable:!0,configurable:!0}),this.name=`${this.name} [${a}]`,this.stack,delete this.name}get code(){return a}set code(y){Object.defineProperty(this,"code",{configurable:!0,enumerable:!0,value:y,writable:!0})}toString(){return`${this.name} [${a}]: ${this.message}`}}}h("ERR_BUFFER_OUT_OF_BOUNDS",function(a){return a?`${a} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"},RangeError),h("ERR_INVALID_ARG_TYPE",function(a,e){return`The "${a}" argument must be of type number. Received type ${typeof e}`},TypeError),h("ERR_OUT_OF_RANGE",function(a,e,n){let d=`The value of "${a}" is out of range.`,y=n;return Number.isInteger(n)&&Math.abs(n)>2**32?y=o(String(n)):typeof n=="bigint"&&(y=String(n),(n>BigInt(2)**BigInt(32)||n<-(BigInt(2)**BigInt(32)))&&(y=o(y)),y+="n"),d+=` It must be ${e}. Received ${y}`,d},RangeError);function o(a){let e="",n=a.length;const d=a[0]==="-"?1:0;for(;n>=d+4;n-=3)e=`_${a.slice(n-3,n)}${e}`;return`${a.slice(0,n)}${e}`}function g(a,e,n){E(e,"offset"),(a[e]===void 0||a[e+n]===void 0)&&C(e,a.length-(n+1))}function b(a,e,n,d,y,f){if(a>n||a<e){const I=typeof e=="bigint"?"n":"";let Q;throw e===0||e===BigInt(0)?Q=`>= 0${I} and < 2${I} ** ${(f+1)*8}${I}`:Q=`>= -(2${I} ** ${(f+1)*8-1}${I}) and < 2 ** ${(f+1)*8-1}${I}`,new p.ERR_OUT_OF_RANGE("value",Q,a)}g(d,y,f)}function E(a,e){if(typeof a!="number")throw new p.ERR_INVALID_ARG_TYPE(e,"number",a)}function C(a,e,n){throw Math.floor(a)!==a?(E(a,n),new p.ERR_OUT_OF_RANGE("offset","an integer",a)):e<0?new p.ERR_BUFFER_OUT_OF_BOUNDS:new p.ERR_OUT_OF_RANGE("offset",`>= 0 and <= ${e}`,a)}const G=/[^+/0-9A-Za-z-_]/g;function J(a){if(a=a.split("=")[0],a=a.trim().replace(G,""),a.length<2)return"";for(;a.length%4!==0;)a=a+"=";return a}function ee(a,e){e=e||1/0;let n;const d=a.length;let y=null;const f=[];for(let I=0;I<d;++I){if(n=a.charCodeAt(I),n>55295&&n<57344){if(!y){if(n>56319){(e-=3)>-1&&f.push(239,191,189);continue}else if(I+1===d){(e-=3)>-1&&f.push(239,191,189);continue}y=n;continue}if(n<56320){(e-=3)>-1&&f.push(239,191,189),y=n;continue}n=(y-55296<<10|n-56320)+65536}else y&&(e-=3)>-1&&f.push(239,191,189);if(y=null,n<128){if((e-=1)<0)break;f.push(n)}else if(n<2048){if((e-=2)<0)break;f.push(n>>6|192,n&63|128)}else if(n<65536){if((e-=3)<0)break;f.push(n>>12|224,n>>6&63|128,n&63|128)}else if(n<1114112){if((e-=4)<0)break;f.push(n>>18|240,n>>12&63|128,n>>6&63|128,n&63|128)}else throw new Error("Invalid code point")}return f}function S(a){const e=[];for(let n=0;n<a.length;++n)e.push(a.charCodeAt(n)&255);return e}function j(a,e){let n,d,y;const f=[];for(let I=0;I<a.length&&!((e-=2)<0);++I)n=a.charCodeAt(I),d=n>>8,y=n%256,f.push(y),f.push(d);return f}function T(a){return t.toByteArray(J(a))}function X(a,e,n,d){let y;for(y=0;y<d&&!(y+n>=e.length||y>=a.length);++y)e[y+n]=a[y];return y}function q(a,e){return a instanceof e||a!=null&&a.constructor!=null&&a.constructor.name!=null&&a.constructor.name===e.name}function re(a){return a!==a}const de=function(){const a="0123456789abcdef",e=new Array(256);for(let n=0;n<16;++n){const d=n*16;for(let y=0;y<16;++y)e[d+y]=a[n]+a[y]}return e}();function ne(a){return typeof BigInt>"u"?pe:a}function pe(){throw new Error("BigInt not supported")}})(zt);var _t={exports:{}},he=_t.exports={},Be,Ie;function dt(){throw new Error("setTimeout has not been defined")}function lt(){throw new Error("clearTimeout has not been defined")}(function(){try{typeof setTimeout=="function"?Be=setTimeout:Be=dt}catch{Be=dt}try{typeof clearTimeout=="function"?Ie=clearTimeout:Ie=lt}catch{Ie=lt}})();function jt(r){if(Be===setTimeout)return setTimeout(r,0);if((Be===dt||!Be)&&setTimeout)return Be=setTimeout,setTimeout(r,0);try{return Be(r,0)}catch{try{return Be.call(null,r,0)}catch{return Be.call(this,r,0)}}}function yn(r){if(Ie===clearTimeout)return clearTimeout(r);if((Ie===lt||!Ie)&&clearTimeout)return Ie=clearTimeout,clearTimeout(r);try{return Ie(r)}catch{try{return Ie.call(null,r)}catch{return Ie.call(this,r)}}}var $e=[],De=!1,Me,He=-1;function hn(){!De||!Me||(De=!1,Me.length?$e=Me.concat($e):He=-1,$e.length&&Pt())}function Pt(){if(!De){var r=jt(hn);De=!0;for(var t=$e.length;t;){for(Me=$e,$e=[];++He<t;)Me&&Me[He].run();He=-1,t=$e.length}Me=null,De=!1,yn(r)}}he.nextTick=function(r){var t=new Array(arguments.length-1);if(arguments.length>1)for(var i=1;i<arguments.length;i++)t[i-1]=arguments[i];$e.push(new Ut(r,t)),$e.length===1&&!De&&jt(Pt)};function Ut(r,t){this.fun=r,this.array=t}Ut.prototype.run=function(){this.fun.apply(null,this.array)};he.title="browser";he.browser=!0;he.env={};he.argv=[];he.version="";he.versions={};function Te(){}he.on=Te;he.addListener=Te;he.once=Te;he.off=Te;he.removeListener=Te;he.removeAllListeners=Te;he.emit=Te;he.prependListener=Te;he.prependOnceListener=Te;he.listeners=function(r){return[]};he.binding=function(r){throw new Error("process.binding is not supported")};he.cwd=function(){return"/"};he.chdir=function(r){throw new Error("process.chdir is not supported")};he.umask=function(){return 0};var bn=_t.exports;const fn=on(bn);window.Buffer=zt.Buffer;window.process=fn;window.global=window;const Ze="http://localhost:3000/api";class Je{async login(t,i){const s=await fetch(`${Ze}/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:t,password:i})});if(!s.ok){const m=await s.json();throw new Error(m.message)}return await s.json()}async register(t,i){const s=await fetch(`${Ze}/auth/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:t,password:i})});if(!s.ok){const m=await s.json();throw new Error(m.message)}return await s.json()}async getCurrentUser(){const t=localStorage.getItem("token"),i=await fetch(`${Ze}/auth/me`,{headers:{Authorization:`Bearer ${t}`}});if(!i.ok)throw new Error("获取用户信息失败");return(await i.json()).user}logout(){localStorage.removeItem("token"),window.location.reload()}}class xn{constructor(){this.ws=null,this.listeners=new Map}connect(t){this.ws=new WebSocket("ws://localhost:3000"),this.ws.onopen=()=>{console.log("✅ WebSocket 连接成功"),this.send({type:"auth",token:t})},this.ws.onmessage=i=>{const s=JSON.parse(i.data);this.notifyListeners(s.type,s)},this.ws.onerror=i=>{console.error("❌ WebSocket 错误:",i)},this.ws.onclose=()=>{console.log("🔌 WebSocket 连接关闭"),setTimeout(()=>this.connect(t),3e3)}}send(t){this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(t))}on(t,i){this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(i)}off(t,i){if(this.listeners.has(t)){const s=this.listeners.get(t),m=s.indexOf(i);m>-1&&s.splice(m,1)}}notifyListeners(t,i){this.listeners.has(t)&&this.listeners.get(t).forEach(s=>s(i))}joinGroup(t){this.send({type:"join_group",groupId:t})}sendChatMessage(t,i,s){this.send({type:"chat_message",groupId:t,username:i,content:s})}syncDocument(t,i,s){this.send({type:"document_sync",documentId:t,content:i,cursorPosition:s})}respondToCall(t,i){this.send({type:"call_response",groupId:t,username:i})}sendTyping(t,i,s){this.send({type:"typing",documentId:t,username:i,isTyping:s})}sendWhiteboardDraw(t,i){this.send({type:"whiteboard_draw",groupId:t,...i})}sendWhiteboardClear(t){this.send({type:"whiteboard_clear",groupId:t})}}function vn(r){const t=document.getElementById("app"),i=new Je;t.innerHTML=`
6
+ */(function(r){const t=Ke,i=yt,s=typeof Symbol=="function"&&typeof Symbol.for=="function"?Symbol.for("nodejs.util.inspect.custom"):null;r.Buffer=u,r.SlowBuffer=K,r.INSPECT_MAX_BYTES=50;const m=2147483647;r.kMaxLength=m,u.TYPED_ARRAY_SUPPORT=l(),!u.TYPED_ARRAY_SUPPORT&&typeof console<"u"&&typeof console.error=="function"&&console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.");function l(){try{const a=new Uint8Array(1),e={foo:function(){return 42}};return Object.setPrototypeOf(e,Uint8Array.prototype),Object.setPrototypeOf(a,e),a.foo()===42}catch{return!1}}Object.defineProperty(u.prototype,"parent",{enumerable:!0,get:function(){if(u.isBuffer(this))return this.buffer}}),Object.defineProperty(u.prototype,"offset",{enumerable:!0,get:function(){if(u.isBuffer(this))return this.byteOffset}});function c(a){if(a>m)throw new RangeError('The value "'+a+'" is invalid for option "size"');const e=new Uint8Array(a);return Object.setPrototypeOf(e,u.prototype),e}function u(a,e,n){if(typeof a=="number"){if(typeof e=="string")throw new TypeError('The "string" argument must be of type string. Received type number');return R(a)}return F(a,e,n)}u.poolSize=8192;function F(a,e,n){if(typeof a=="string")return U(a,e);if(ArrayBuffer.isView(a))return ue(a);if(a==null)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof a);if(q(a,ArrayBuffer)||a&&q(a.buffer,ArrayBuffer)||typeof SharedArrayBuffer<"u"&&(q(a,SharedArrayBuffer)||a&&q(a.buffer,SharedArrayBuffer)))return oe(a,e,n);if(typeof a=="number")throw new TypeError('The "value" argument must not be of type number. Received type number');const d=a.valueOf&&a.valueOf();if(d!=null&&d!==a)return u.from(d,e,n);const y=fe(a);if(y)return y;if(typeof Symbol<"u"&&Symbol.toPrimitive!=null&&typeof a[Symbol.toPrimitive]=="function")return u.from(a[Symbol.toPrimitive]("string"),e,n);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof a)}u.from=function(a,e,n){return F(a,e,n)},Object.setPrototypeOf(u.prototype,Uint8Array.prototype),Object.setPrototypeOf(u,Uint8Array);function D(a){if(typeof a!="number")throw new TypeError('"size" argument must be of type number');if(a<0)throw new RangeError('The value "'+a+'" is invalid for option "size"')}function z(a,e,n){return D(a),a<=0?c(a):e!==void 0?typeof n=="string"?c(a).fill(e,n):c(a).fill(e):c(a)}u.alloc=function(a,e,n){return z(a,e,n)};function R(a){return D(a),c(a<0?0:be(a)|0)}u.allocUnsafe=function(a){return R(a)},u.allocUnsafeSlow=function(a){return R(a)};function U(a,e){if((typeof e!="string"||e==="")&&(e="utf8"),!u.isEncoding(e))throw new TypeError("Unknown encoding: "+e);const n=te(a,e)|0;let d=c(n);const y=d.write(a,e);return y!==n&&(d=d.slice(0,y)),d}function W(a){const e=a.length<0?0:be(a.length)|0,n=c(e);for(let d=0;d<e;d+=1)n[d]=a[d]&255;return n}function ue(a){if(q(a,Uint8Array)){const e=new Uint8Array(a);return oe(e.buffer,e.byteOffset,e.byteLength)}return W(a)}function oe(a,e,n){if(e<0||a.byteLength<e)throw new RangeError('"offset" is outside of buffer bounds');if(a.byteLength<e+(n||0))throw new RangeError('"length" is outside of buffer bounds');let d;return e===void 0&&n===void 0?d=new Uint8Array(a):n===void 0?d=new Uint8Array(a,e):d=new Uint8Array(a,e,n),Object.setPrototypeOf(d,u.prototype),d}function fe(a){if(u.isBuffer(a)){const e=be(a.length)|0,n=c(e);return n.length===0||a.copy(n,0,0,e),n}if(a.length!==void 0)return typeof a.length!="number"||re(a.length)?c(0):W(a);if(a.type==="Buffer"&&Array.isArray(a.data))return W(a.data)}function be(a){if(a>=m)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+m.toString(16)+" bytes");return a|0}function K(a){return+a!=a&&(a=0),u.alloc(+a)}u.isBuffer=function(e){return e!=null&&e._isBuffer===!0&&e!==u.prototype},u.compare=function(e,n){if(q(e,Uint8Array)&&(e=u.from(e,e.offset,e.byteLength)),q(n,Uint8Array)&&(n=u.from(n,n.offset,n.byteLength)),!u.isBuffer(e)||!u.isBuffer(n))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(e===n)return 0;let d=e.length,y=n.length;for(let x=0,I=Math.min(d,y);x<I;++x)if(e[x]!==n[x]){d=e[x],y=n[x];break}return d<y?-1:y<d?1:0},u.isEncoding=function(e){switch(String(e).toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"latin1":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},u.concat=function(e,n){if(!Array.isArray(e))throw new TypeError('"list" argument must be an Array of Buffers');if(e.length===0)return u.alloc(0);let d;if(n===void 0)for(n=0,d=0;d<e.length;++d)n+=e[d].length;const y=u.allocUnsafe(n);let x=0;for(d=0;d<e.length;++d){let I=e[d];if(q(I,Uint8Array))x+I.length>y.length?(u.isBuffer(I)||(I=u.from(I)),I.copy(y,x)):Uint8Array.prototype.set.call(y,I,x);else if(u.isBuffer(I))I.copy(y,x);else throw new TypeError('"list" argument must be an Array of Buffers');x+=I.length}return y};function te(a,e){if(u.isBuffer(a))return a.length;if(ArrayBuffer.isView(a)||q(a,ArrayBuffer))return a.byteLength;if(typeof a!="string")throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof a);const n=a.length,d=arguments.length>2&&arguments[2]===!0;if(!d&&n===0)return 0;let y=!1;for(;;)switch(e){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":return ee(a).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return n*2;case"hex":return n>>>1;case"base64":return T(a).length;default:if(y)return d?-1:ee(a).length;e=(""+e).toLowerCase(),y=!0}}u.byteLength=te;function me(a,e,n){let d=!1;if((e===void 0||e<0)&&(e=0),e>this.length||((n===void 0||n>this.length)&&(n=this.length),n<=0)||(n>>>=0,e>>>=0,n<=e))return"";for(a||(a="utf8");;)switch(a){case"hex":return ie(this,e,n);case"utf8":case"utf-8":return _(this,e,n);case"ascii":return Y(this,e,n);case"latin1":case"binary":return xe(this,e,n);case"base64":return H(this,e,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return we(this,e,n);default:if(d)throw new TypeError("Unknown encoding: "+a);a=(a+"").toLowerCase(),d=!0}}u.prototype._isBuffer=!0;function se(a,e,n){const d=a[e];a[e]=a[n],a[n]=d}u.prototype.swap16=function(){const e=this.length;if(e%2!==0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let n=0;n<e;n+=2)se(this,n,n+1);return this},u.prototype.swap32=function(){const e=this.length;if(e%4!==0)throw new RangeError("Buffer size must be a multiple of 32-bits");for(let n=0;n<e;n+=4)se(this,n,n+3),se(this,n+1,n+2);return this},u.prototype.swap64=function(){const e=this.length;if(e%8!==0)throw new RangeError("Buffer size must be a multiple of 64-bits");for(let n=0;n<e;n+=8)se(this,n,n+7),se(this,n+1,n+6),se(this,n+2,n+5),se(this,n+3,n+4);return this},u.prototype.toString=function(){const e=this.length;return e===0?"":arguments.length===0?_(this,0,e):me.apply(this,arguments)},u.prototype.toLocaleString=u.prototype.toString,u.prototype.equals=function(e){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e?!0:u.compare(this,e)===0},u.prototype.inspect=function(){let e="";const n=r.INSPECT_MAX_BYTES;return e=this.toString("hex",0,n).replace(/(.{2})/g,"$1 ").trim(),this.length>n&&(e+=" ... "),"<Buffer "+e+">"},s&&(u.prototype[s]=u.prototype.inspect),u.prototype.compare=function(e,n,d,y,x){if(q(e,Uint8Array)&&(e=u.from(e,e.offset,e.byteLength)),!u.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(n===void 0&&(n=0),d===void 0&&(d=e?e.length:0),y===void 0&&(y=0),x===void 0&&(x=this.length),n<0||d>e.length||y<0||x>this.length)throw new RangeError("out of range index");if(y>=x&&n>=d)return 0;if(y>=x)return-1;if(n>=d)return 1;if(n>>>=0,d>>>=0,y>>>=0,x>>>=0,this===e)return 0;let I=x-y,Q=d-n;const ge=Math.min(I,Q),ce=this.slice(y,x),ye=e.slice(n,d);for(let le=0;le<ge;++le)if(ce[le]!==ye[le]){I=ce[le],Q=ye[le];break}return I<Q?-1:Q<I?1:0};function ve(a,e,n,d,y){if(a.length===0)return-1;if(typeof n=="string"?(d=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,re(n)&&(n=y?0:a.length-1),n<0&&(n=a.length+n),n>=a.length){if(y)return-1;n=a.length-1}else if(n<0)if(y)n=0;else return-1;if(typeof e=="string"&&(e=u.from(e,d)),u.isBuffer(e))return e.length===0?-1:P(a,e,n,d,y);if(typeof e=="number")return e=e&255,typeof Uint8Array.prototype.indexOf=="function"?y?Uint8Array.prototype.indexOf.call(a,e,n):Uint8Array.prototype.lastIndexOf.call(a,e,n):P(a,[e],n,d,y);throw new TypeError("val must be string, number or Buffer")}function P(a,e,n,d,y){let x=1,I=a.length,Q=e.length;if(d!==void 0&&(d=String(d).toLowerCase(),d==="ucs2"||d==="ucs-2"||d==="utf16le"||d==="utf-16le")){if(a.length<2||e.length<2)return-1;x=2,I/=2,Q/=2,n/=2}function ge(ye,le){return x===1?ye[le]:ye.readUInt16BE(le*x)}let ce;if(y){let ye=-1;for(ce=n;ce<I;ce++)if(ge(a,ce)===ge(e,ye===-1?0:ce-ye)){if(ye===-1&&(ye=ce),ce-ye+1===Q)return ye*x}else ye!==-1&&(ce-=ce-ye),ye=-1}else for(n+Q>I&&(n=I-Q),ce=n;ce>=0;ce--){let ye=!0;for(let le=0;le<Q;le++)if(ge(a,ce+le)!==ge(e,le)){ye=!1;break}if(ye)return ce}return-1}u.prototype.includes=function(e,n,d){return this.indexOf(e,n,d)!==-1},u.prototype.indexOf=function(e,n,d){return ve(this,e,n,d,!0)},u.prototype.lastIndexOf=function(e,n,d){return ve(this,e,n,d,!1)};function A(a,e,n,d){n=Number(n)||0;const y=a.length-n;d?(d=Number(d),d>y&&(d=y)):d=y;const x=e.length;d>x/2&&(d=x/2);let I;for(I=0;I<d;++I){const Q=parseInt(e.substr(I*2,2),16);if(re(Q))return I;a[n+I]=Q}return I}function V(a,e,n,d){return X(ee(e,a.length-n),a,n,d)}function $(a,e,n,d){return X(S(e),a,n,d)}function M(a,e,n,d){return X(T(e),a,n,d)}function N(a,e,n,d){return X(j(e,a.length-n),a,n,d)}u.prototype.write=function(e,n,d,y){if(n===void 0)y="utf8",d=this.length,n=0;else if(d===void 0&&typeof n=="string")y=n,d=this.length,n=0;else if(isFinite(n))n=n>>>0,isFinite(d)?(d=d>>>0,y===void 0&&(y="utf8")):(y=d,d=void 0);else throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");const x=this.length-n;if((d===void 0||d>x)&&(d=x),e.length>0&&(d<0||n<0)||n>this.length)throw new RangeError("Attempt to write outside buffer bounds");y||(y="utf8");let I=!1;for(;;)switch(y){case"hex":return A(this,e,n,d);case"utf8":case"utf-8":return V(this,e,n,d);case"ascii":case"latin1":case"binary":return $(this,e,n,d);case"base64":return M(this,e,n,d);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return N(this,e,n,d);default:if(I)throw new TypeError("Unknown encoding: "+y);y=(""+y).toLowerCase(),I=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function H(a,e,n){return e===0&&n===a.length?t.fromByteArray(a):t.fromByteArray(a.slice(e,n))}function _(a,e,n){n=Math.min(a.length,n);const d=[];let y=e;for(;y<n;){const x=a[y];let I=null,Q=x>239?4:x>223?3:x>191?2:1;if(y+Q<=n){let ge,ce,ye,le;switch(Q){case 1:x<128&&(I=x);break;case 2:ge=a[y+1],(ge&192)===128&&(le=(x&31)<<6|ge&63,le>127&&(I=le));break;case 3:ge=a[y+1],ce=a[y+2],(ge&192)===128&&(ce&192)===128&&(le=(x&15)<<12|(ge&63)<<6|ce&63,le>2047&&(le<55296||le>57343)&&(I=le));break;case 4:ge=a[y+1],ce=a[y+2],ye=a[y+3],(ge&192)===128&&(ce&192)===128&&(ye&192)===128&&(le=(x&15)<<18|(ge&63)<<12|(ce&63)<<6|ye&63,le>65535&&le<1114112&&(I=le))}}I===null?(I=65533,Q=1):I>65535&&(I-=65536,d.push(I>>>10&1023|55296),I=56320|I&1023),d.push(I),y+=Q}return Z(d)}const O=4096;function Z(a){const e=a.length;if(e<=O)return String.fromCharCode.apply(String,a);let n="",d=0;for(;d<e;)n+=String.fromCharCode.apply(String,a.slice(d,d+=O));return n}function Y(a,e,n){let d="";n=Math.min(a.length,n);for(let y=e;y<n;++y)d+=String.fromCharCode(a[y]&127);return d}function xe(a,e,n){let d="";n=Math.min(a.length,n);for(let y=e;y<n;++y)d+=String.fromCharCode(a[y]);return d}function ie(a,e,n){const d=a.length;(!e||e<0)&&(e=0),(!n||n<0||n>d)&&(n=d);let y="";for(let x=e;x<n;++x)y+=de[a[x]];return y}function we(a,e,n){const d=a.slice(e,n);let y="";for(let x=0;x<d.length-1;x+=2)y+=String.fromCharCode(d[x]+d[x+1]*256);return y}u.prototype.slice=function(e,n){const d=this.length;e=~~e,n=n===void 0?d:~~n,e<0?(e+=d,e<0&&(e=0)):e>d&&(e=d),n<0?(n+=d,n<0&&(n=0)):n>d&&(n=d),n<e&&(n=e);const y=this.subarray(e,n);return Object.setPrototypeOf(y,u.prototype),y};function ae(a,e,n){if(a%1!==0||a<0)throw new RangeError("offset is not uint");if(a+e>n)throw new RangeError("Trying to access beyond buffer length")}u.prototype.readUintLE=u.prototype.readUIntLE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=this[e],x=1,I=0;for(;++I<n&&(x*=256);)y+=this[e+I]*x;return y},u.prototype.readUintBE=u.prototype.readUIntBE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=this[e+--n],x=1;for(;n>0&&(x*=256);)y+=this[e+--n]*x;return y},u.prototype.readUint8=u.prototype.readUInt8=function(e,n){return e=e>>>0,n||ae(e,1,this.length),this[e]},u.prototype.readUint16LE=u.prototype.readUInt16LE=function(e,n){return e=e>>>0,n||ae(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUint16BE=u.prototype.readUInt16BE=function(e,n){return e=e>>>0,n||ae(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUint32LE=u.prototype.readUInt32LE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+this[e+3]*16777216},u.prototype.readUint32BE=u.prototype.readUInt32BE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),this[e]*16777216+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readBigUInt64LE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=n+this[++e]*2**8+this[++e]*2**16+this[++e]*2**24,x=this[++e]+this[++e]*2**8+this[++e]*2**16+d*2**24;return BigInt(y)+(BigInt(x)<<BigInt(32))}),u.prototype.readBigUInt64BE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=n*2**24+this[++e]*2**16+this[++e]*2**8+this[++e],x=this[++e]*2**24+this[++e]*2**16+this[++e]*2**8+d;return(BigInt(y)<<BigInt(32))+BigInt(x)}),u.prototype.readIntLE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=this[e],x=1,I=0;for(;++I<n&&(x*=256);)y+=this[e+I]*x;return x*=128,y>=x&&(y-=Math.pow(2,8*n)),y},u.prototype.readIntBE=function(e,n,d){e=e>>>0,n=n>>>0,d||ae(e,n,this.length);let y=n,x=1,I=this[e+--y];for(;y>0&&(x*=256);)I+=this[e+--y]*x;return x*=128,I>=x&&(I-=Math.pow(2,8*n)),I},u.prototype.readInt8=function(e,n){return e=e>>>0,n||ae(e,1,this.length),this[e]&128?(255-this[e]+1)*-1:this[e]},u.prototype.readInt16LE=function(e,n){e=e>>>0,n||ae(e,2,this.length);const d=this[e]|this[e+1]<<8;return d&32768?d|4294901760:d},u.prototype.readInt16BE=function(e,n){e=e>>>0,n||ae(e,2,this.length);const d=this[e+1]|this[e]<<8;return d&32768?d|4294901760:d},u.prototype.readInt32LE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readBigInt64LE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=this[e+4]+this[e+5]*2**8+this[e+6]*2**16+(d<<24);return(BigInt(y)<<BigInt(32))+BigInt(n+this[++e]*2**8+this[++e]*2**16+this[++e]*2**24)}),u.prototype.readBigInt64BE=ne(function(e){e=e>>>0,E(e,"offset");const n=this[e],d=this[e+7];(n===void 0||d===void 0)&&C(e,this.length-8);const y=(n<<24)+this[++e]*2**16+this[++e]*2**8+this[++e];return(BigInt(y)<<BigInt(32))+BigInt(this[++e]*2**24+this[++e]*2**16+this[++e]*2**8+d)}),u.prototype.readFloatLE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),i.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,n){return e=e>>>0,n||ae(e,4,this.length),i.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,n){return e=e>>>0,n||ae(e,8,this.length),i.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,n){return e=e>>>0,n||ae(e,8,this.length),i.read(this,e,!1,52,8)};function v(a,e,n,d,y,x){if(!u.isBuffer(a))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>y||e<x)throw new RangeError('"value" argument is out of bounds');if(n+d>a.length)throw new RangeError("Index out of range")}u.prototype.writeUintLE=u.prototype.writeUIntLE=function(e,n,d,y){if(e=+e,n=n>>>0,d=d>>>0,!y){const Q=Math.pow(2,8*d)-1;v(this,e,n,d,Q,0)}let x=1,I=0;for(this[n]=e&255;++I<d&&(x*=256);)this[n+I]=e/x&255;return n+d},u.prototype.writeUintBE=u.prototype.writeUIntBE=function(e,n,d,y){if(e=+e,n=n>>>0,d=d>>>0,!y){const Q=Math.pow(2,8*d)-1;v(this,e,n,d,Q,0)}let x=d-1,I=1;for(this[n+x]=e&255;--x>=0&&(I*=256);)this[n+x]=e/I&255;return n+d},u.prototype.writeUint8=u.prototype.writeUInt8=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,1,255,0),this[n]=e&255,n+1},u.prototype.writeUint16LE=u.prototype.writeUInt16LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,65535,0),this[n]=e&255,this[n+1]=e>>>8,n+2},u.prototype.writeUint16BE=u.prototype.writeUInt16BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,65535,0),this[n]=e>>>8,this[n+1]=e&255,n+2},u.prototype.writeUint32LE=u.prototype.writeUInt32LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,4294967295,0),this[n+3]=e>>>24,this[n+2]=e>>>16,this[n+1]=e>>>8,this[n]=e&255,n+4},u.prototype.writeUint32BE=u.prototype.writeUInt32BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,4294967295,0),this[n]=e>>>24,this[n+1]=e>>>16,this[n+2]=e>>>8,this[n+3]=e&255,n+4};function b(a,e,n,d,y){f(e,d,y,a,n,7);let x=Number(e&BigInt(4294967295));a[n++]=x,x=x>>8,a[n++]=x,x=x>>8,a[n++]=x,x=x>>8,a[n++]=x;let I=Number(e>>BigInt(32)&BigInt(4294967295));return a[n++]=I,I=I>>8,a[n++]=I,I=I>>8,a[n++]=I,I=I>>8,a[n++]=I,n}function w(a,e,n,d,y){f(e,d,y,a,n,7);let x=Number(e&BigInt(4294967295));a[n+7]=x,x=x>>8,a[n+6]=x,x=x>>8,a[n+5]=x,x=x>>8,a[n+4]=x;let I=Number(e>>BigInt(32)&BigInt(4294967295));return a[n+3]=I,I=I>>8,a[n+2]=I,I=I>>8,a[n+1]=I,I=I>>8,a[n]=I,n+8}u.prototype.writeBigUInt64LE=ne(function(e,n=0){return b(this,e,n,BigInt(0),BigInt("0xffffffffffffffff"))}),u.prototype.writeBigUInt64BE=ne(function(e,n=0){return w(this,e,n,BigInt(0),BigInt("0xffffffffffffffff"))}),u.prototype.writeIntLE=function(e,n,d,y){if(e=+e,n=n>>>0,!y){const ge=Math.pow(2,8*d-1);v(this,e,n,d,ge-1,-ge)}let x=0,I=1,Q=0;for(this[n]=e&255;++x<d&&(I*=256);)e<0&&Q===0&&this[n+x-1]!==0&&(Q=1),this[n+x]=(e/I>>0)-Q&255;return n+d},u.prototype.writeIntBE=function(e,n,d,y){if(e=+e,n=n>>>0,!y){const ge=Math.pow(2,8*d-1);v(this,e,n,d,ge-1,-ge)}let x=d-1,I=1,Q=0;for(this[n+x]=e&255;--x>=0&&(I*=256);)e<0&&Q===0&&this[n+x+1]!==0&&(Q=1),this[n+x]=(e/I>>0)-Q&255;return n+d},u.prototype.writeInt8=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,1,127,-128),e<0&&(e=255+e+1),this[n]=e&255,n+1},u.prototype.writeInt16LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,32767,-32768),this[n]=e&255,this[n+1]=e>>>8,n+2},u.prototype.writeInt16BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,2,32767,-32768),this[n]=e>>>8,this[n+1]=e&255,n+2},u.prototype.writeInt32LE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,2147483647,-2147483648),this[n]=e&255,this[n+1]=e>>>8,this[n+2]=e>>>16,this[n+3]=e>>>24,n+4},u.prototype.writeInt32BE=function(e,n,d){return e=+e,n=n>>>0,d||v(this,e,n,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[n]=e>>>24,this[n+1]=e>>>16,this[n+2]=e>>>8,this[n+3]=e&255,n+4},u.prototype.writeBigInt64LE=ne(function(e,n=0){return b(this,e,n,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))}),u.prototype.writeBigInt64BE=ne(function(e,n=0){return w(this,e,n,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))});function B(a,e,n,d,y,x){if(n+d>a.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(a,e,n,d,y){return e=+e,n=n>>>0,y||B(a,e,n,4),i.write(a,e,n,d,23,4),n+4}u.prototype.writeFloatLE=function(e,n,d){return L(this,e,n,!0,d)},u.prototype.writeFloatBE=function(e,n,d){return L(this,e,n,!1,d)};function k(a,e,n,d,y){return e=+e,n=n>>>0,y||B(a,e,n,8),i.write(a,e,n,d,52,8),n+8}u.prototype.writeDoubleLE=function(e,n,d){return k(this,e,n,!0,d)},u.prototype.writeDoubleBE=function(e,n,d){return k(this,e,n,!1,d)},u.prototype.copy=function(e,n,d,y){if(!u.isBuffer(e))throw new TypeError("argument should be a Buffer");if(d||(d=0),!y&&y!==0&&(y=this.length),n>=e.length&&(n=e.length),n||(n=0),y>0&&y<d&&(y=d),y===d||e.length===0||this.length===0)return 0;if(n<0)throw new RangeError("targetStart out of bounds");if(d<0||d>=this.length)throw new RangeError("Index out of range");if(y<0)throw new RangeError("sourceEnd out of bounds");y>this.length&&(y=this.length),e.length-n<y-d&&(y=e.length-n+d);const x=y-d;return this===e&&typeof Uint8Array.prototype.copyWithin=="function"?this.copyWithin(n,d,y):Uint8Array.prototype.set.call(e,this.subarray(d,y),n),x},u.prototype.fill=function(e,n,d,y){if(typeof e=="string"){if(typeof n=="string"?(y=n,n=0,d=this.length):typeof d=="string"&&(y=d,d=this.length),y!==void 0&&typeof y!="string")throw new TypeError("encoding must be a string");if(typeof y=="string"&&!u.isEncoding(y))throw new TypeError("Unknown encoding: "+y);if(e.length===1){const I=e.charCodeAt(0);(y==="utf8"&&I<128||y==="latin1")&&(e=I)}}else typeof e=="number"?e=e&255:typeof e=="boolean"&&(e=Number(e));if(n<0||this.length<n||this.length<d)throw new RangeError("Out of range index");if(d<=n)return this;n=n>>>0,d=d===void 0?this.length:d>>>0,e||(e=0);let x;if(typeof e=="number")for(x=n;x<d;++x)this[x]=e;else{const I=u.isBuffer(e)?e:u.from(e,y),Q=I.length;if(Q===0)throw new TypeError('The value "'+e+'" is invalid for argument "value"');for(x=0;x<d-n;++x)this[x+n]=I[x%Q]}return this};const p={};function h(a,e,n){p[a]=class extends n{constructor(){super(),Object.defineProperty(this,"message",{value:e.apply(this,arguments),writable:!0,configurable:!0}),this.name=`${this.name} [${a}]`,this.stack,delete this.name}get code(){return a}set code(y){Object.defineProperty(this,"code",{configurable:!0,enumerable:!0,value:y,writable:!0})}toString(){return`${this.name} [${a}]: ${this.message}`}}}h("ERR_BUFFER_OUT_OF_BOUNDS",function(a){return a?`${a} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"},RangeError),h("ERR_INVALID_ARG_TYPE",function(a,e){return`The "${a}" argument must be of type number. Received type ${typeof e}`},TypeError),h("ERR_OUT_OF_RANGE",function(a,e,n){let d=`The value of "${a}" is out of range.`,y=n;return Number.isInteger(n)&&Math.abs(n)>2**32?y=o(String(n)):typeof n=="bigint"&&(y=String(n),(n>BigInt(2)**BigInt(32)||n<-(BigInt(2)**BigInt(32)))&&(y=o(y)),y+="n"),d+=` It must be ${e}. Received ${y}`,d},RangeError);function o(a){let e="",n=a.length;const d=a[0]==="-"?1:0;for(;n>=d+4;n-=3)e=`_${a.slice(n-3,n)}${e}`;return`${a.slice(0,n)}${e}`}function g(a,e,n){E(e,"offset"),(a[e]===void 0||a[e+n]===void 0)&&C(e,a.length-(n+1))}function f(a,e,n,d,y,x){if(a>n||a<e){const I=typeof e=="bigint"?"n":"";let Q;throw e===0||e===BigInt(0)?Q=`>= 0${I} and < 2${I} ** ${(x+1)*8}${I}`:Q=`>= -(2${I} ** ${(x+1)*8-1}${I}) and < 2 ** ${(x+1)*8-1}${I}`,new p.ERR_OUT_OF_RANGE("value",Q,a)}g(d,y,x)}function E(a,e){if(typeof a!="number")throw new p.ERR_INVALID_ARG_TYPE(e,"number",a)}function C(a,e,n){throw Math.floor(a)!==a?(E(a,n),new p.ERR_OUT_OF_RANGE("offset","an integer",a)):e<0?new p.ERR_BUFFER_OUT_OF_BOUNDS:new p.ERR_OUT_OF_RANGE("offset",`>= 0 and <= ${e}`,a)}const G=/[^+/0-9A-Za-z-_]/g;function J(a){if(a=a.split("=")[0],a=a.trim().replace(G,""),a.length<2)return"";for(;a.length%4!==0;)a=a+"=";return a}function ee(a,e){e=e||1/0;let n;const d=a.length;let y=null;const x=[];for(let I=0;I<d;++I){if(n=a.charCodeAt(I),n>55295&&n<57344){if(!y){if(n>56319){(e-=3)>-1&&x.push(239,191,189);continue}else if(I+1===d){(e-=3)>-1&&x.push(239,191,189);continue}y=n;continue}if(n<56320){(e-=3)>-1&&x.push(239,191,189),y=n;continue}n=(y-55296<<10|n-56320)+65536}else y&&(e-=3)>-1&&x.push(239,191,189);if(y=null,n<128){if((e-=1)<0)break;x.push(n)}else if(n<2048){if((e-=2)<0)break;x.push(n>>6|192,n&63|128)}else if(n<65536){if((e-=3)<0)break;x.push(n>>12|224,n>>6&63|128,n&63|128)}else if(n<1114112){if((e-=4)<0)break;x.push(n>>18|240,n>>12&63|128,n>>6&63|128,n&63|128)}else throw new Error("Invalid code point")}return x}function S(a){const e=[];for(let n=0;n<a.length;++n)e.push(a.charCodeAt(n)&255);return e}function j(a,e){let n,d,y;const x=[];for(let I=0;I<a.length&&!((e-=2)<0);++I)n=a.charCodeAt(I),d=n>>8,y=n%256,x.push(y),x.push(d);return x}function T(a){return t.toByteArray(J(a))}function X(a,e,n,d){let y;for(y=0;y<d&&!(y+n>=e.length||y>=a.length);++y)e[y+n]=a[y];return y}function q(a,e){return a instanceof e||a!=null&&a.constructor!=null&&a.constructor.name!=null&&a.constructor.name===e.name}function re(a){return a!==a}const de=function(){const a="0123456789abcdef",e=new Array(256);for(let n=0;n<16;++n){const d=n*16;for(let y=0;y<16;++y)e[d+y]=a[n]+a[y]}return e}();function ne(a){return typeof BigInt>"u"?pe:a}function pe(){throw new Error("BigInt not supported")}})(At);var _t={exports:{}},he=_t.exports={},Be,Ie;function dt(){throw new Error("setTimeout has not been defined")}function lt(){throw new Error("clearTimeout has not been defined")}(function(){try{typeof setTimeout=="function"?Be=setTimeout:Be=dt}catch{Be=dt}try{typeof clearTimeout=="function"?Ie=clearTimeout:Ie=lt}catch{Ie=lt}})();function jt(r){if(Be===setTimeout)return setTimeout(r,0);if((Be===dt||!Be)&&setTimeout)return Be=setTimeout,setTimeout(r,0);try{return Be(r,0)}catch{try{return Be.call(null,r,0)}catch{return Be.call(this,r,0)}}}function yn(r){if(Ie===clearTimeout)return clearTimeout(r);if((Ie===lt||!Ie)&&clearTimeout)return Ie=clearTimeout,clearTimeout(r);try{return Ie(r)}catch{try{return Ie.call(null,r)}catch{return Ie.call(this,r)}}}var $e=[],ze=!1,Me,He=-1;function hn(){!ze||!Me||(ze=!1,Me.length?$e=Me.concat($e):He=-1,$e.length&&Ft())}function Ft(){if(!ze){var r=jt(hn);ze=!0;for(var t=$e.length;t;){for(Me=$e,$e=[];++He<t;)Me&&Me[He].run();He=-1,t=$e.length}Me=null,ze=!1,yn(r)}}he.nextTick=function(r){var t=new Array(arguments.length-1);if(arguments.length>1)for(var i=1;i<arguments.length;i++)t[i-1]=arguments[i];$e.push(new Pt(r,t)),$e.length===1&&!ze&&jt(Ft)};function Pt(r,t){this.fun=r,this.array=t}Pt.prototype.run=function(){this.fun.apply(null,this.array)};he.title="browser";he.browser=!0;he.env={};he.argv=[];he.version="";he.versions={};function Te(){}he.on=Te;he.addListener=Te;he.once=Te;he.off=Te;he.removeListener=Te;he.removeAllListeners=Te;he.emit=Te;he.prependListener=Te;he.prependOnceListener=Te;he.listeners=function(r){return[]};he.binding=function(r){throw new Error("process.binding is not supported")};he.cwd=function(){return"/"};he.chdir=function(r){throw new Error("process.chdir is not supported")};he.umask=function(){return 0};var fn=_t.exports;const xn=on(fn);window.Buffer=At.Buffer;window.process=xn;window.global=window;const Ze="http://localhost:3000/api";class Je{async login(t,i){const s=await fetch(`${Ze}/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:t,password:i})});if(!s.ok){const m=await s.json();throw new Error(m.message)}return await s.json()}async register(t,i){const s=await fetch(`${Ze}/auth/register`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:t,password:i})});if(!s.ok){const m=await s.json();throw new Error(m.message)}return await s.json()}async getCurrentUser(){const t=localStorage.getItem("token"),i=await fetch(`${Ze}/auth/me`,{headers:{Authorization:`Bearer ${t}`}});if(!i.ok)throw new Error("获取用户信息失败");return(await i.json()).user}logout(){localStorage.removeItem("token"),window.location.reload()}}class bn{constructor(){this.ws=null,this.listeners=new Map}connect(t){this.ws=new WebSocket("ws://localhost:3000"),this.ws.onopen=()=>{console.log("✅ WebSocket 连接成功"),this.send({type:"auth",token:t})},this.ws.onmessage=i=>{const s=JSON.parse(i.data);this.notifyListeners(s.type,s)},this.ws.onerror=i=>{console.error("❌ WebSocket 错误:",i)},this.ws.onclose=()=>{console.log("🔌 WebSocket 连接关闭"),setTimeout(()=>this.connect(t),3e3)}}send(t){this.ws&&this.ws.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(t))}on(t,i){this.listeners.has(t)||this.listeners.set(t,[]),this.listeners.get(t).push(i)}off(t,i){if(this.listeners.has(t)){const s=this.listeners.get(t),m=s.indexOf(i);m>-1&&s.splice(m,1)}}notifyListeners(t,i){this.listeners.has(t)&&this.listeners.get(t).forEach(s=>s(i))}joinGroup(t){this.send({type:"join_group",groupId:t})}sendChatMessage(t,i,s){this.send({type:"chat_message",groupId:t,username:i,content:s})}syncDocument(t,i,s){this.send({type:"document_sync",documentId:t,content:i,cursorPosition:s})}respondToCall(t,i){this.send({type:"call_response",groupId:t,username:i})}sendTyping(t,i,s){this.send({type:"typing",documentId:t,username:i,isTyping:s})}sendWhiteboardDraw(t,i){this.send({type:"whiteboard_draw",groupId:t,...i})}sendWhiteboardClear(t){this.send({type:"whiteboard_clear",groupId:t})}}function vn(r){const t=document.getElementById("app"),i=new Je;t.innerHTML=`
7
7
  <div class="login-container">
8
8
  <div class="login-card">
9
9
  <div class="login-header">
@@ -53,10 +53,10 @@
53
53
  </div>
54
54
  </div>
55
55
  </div>
56
- `,document.getElementById("showRegister").addEventListener("click",()=>{document.getElementById("loginSection").classList.add("hidden"),document.getElementById("registerSection").classList.remove("hidden")}),document.getElementById("showLogin").addEventListener("click",()=>{document.getElementById("registerSection").classList.add("hidden"),document.getElementById("loginSection").classList.remove("hidden")}),document.getElementById("loginForm").addEventListener("submit",async s=>{s.preventDefault();const m=new FormData(s.target),l=m.get("username"),c=m.get("password");try{const u=await i.login(l,c);r(u.user,u.token)}catch(u){document.getElementById("loginError").textContent=u.message}}),document.getElementById("registerForm").addEventListener("submit",async s=>{s.preventDefault();const m=new FormData(s.target),l=m.get("username"),c=m.get("password");try{const u=await i.register(l,c);r(u.user,u.token)}catch(u){document.getElementById("registerError").textContent=u.message}})}const Qe="http://localhost:3000/api";class Ft{constructor(){this.token=localStorage.getItem("token")}async request(t,i={}){const s=await fetch(`${Qe}${t}`,{...i,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`,...i.headers}});if(!s.ok){const m=await s.json().catch(()=>({message:"请求失败"}));throw console.error("API 错误:",{endpoint:t,status:s.status,error:m}),new Error(m.message||`请求失败: ${s.status}`)}return await s.json()}async getGroups(){return await this.request("/groups")}async getAllGroups(){return await this.request("/groups/all")}async getGroup(t){return await this.request(`/groups/${t}`)}async createGroup(t,i,s){return await this.request("/groups",{method:"POST",body:JSON.stringify({name:t,description:i,members:s})})}async joinGroup(t){return await this.request(`/groups/${t}/join`,{method:"POST"})}async leaveGroup(t){return await this.request(`/groups/${t}/leave`,{method:"POST"})}async addMember(t,i){return await this.request(`/groups/${t}/members`,{method:"POST",body:JSON.stringify({userId:i})})}async removeMember(t,i){return await this.request(`/groups/${t}/members/${i}`,{method:"DELETE"})}async setMuteAll(t,i){return await this.request(`/groups/${t}/mute/all`,{method:"POST",body:JSON.stringify({enabled:i})})}async setUserMute(t,i,s){return await this.request(`/groups/${t}/mute/users/${i}`,{method:"POST",body:JSON.stringify({muted:s})})}async getAllUsers(){return await this.request("/auth/users")}async getGroupMessages(t){return await this.request(`/groups/${t}/messages`)}async randomCall(t,i=1){return await this.request(`/groups/${t}/call`,{method:"POST",body:JSON.stringify({count:i})})}async clearGroupMessages(t){return await this.request(`/groups/${t}/messages`,{method:"DELETE",body:JSON.stringify({deleteAll:!0})})}async getTasks(t){return await this.request(`/tasks/group/${t}`)}async getMyTasks(){return await this.request("/tasks/my")}async createTask(t){return await this.request("/tasks",{method:"POST",body:JSON.stringify(t)})}async updateTaskStatus(t,i){return await this.request(`/tasks/${t}/status`,{method:"PATCH",body:JSON.stringify({status:i})})}async deleteTask(t){return await this.request(`/tasks/${t}`,{method:"DELETE"})}async getDocuments(t){return await this.request(`/documents/group/${t}`)}async getDocument(t){return await this.request(`/documents/${t}`)}async createDocument(t,i,s,m=[]){return await this.request("/documents",{method:"POST",body:JSON.stringify({title:t,content:i,groupId:s,editableMembers:m})})}async updateDocument(t,i){return await this.request(`/documents/${t}`,{method:"PATCH",body:JSON.stringify({content:i})})}async updateDocumentPermissions(t,i){return await this.request(`/documents/${t}/permissions`,{method:"PATCH",body:JSON.stringify({editableMembers:i})})}async getDocumentVersions(t){return await this.request(`/documents/${t}/versions`)}async deleteDocument(t){return await this.request(`/documents/${t}`,{method:"DELETE"})}async getAuditLogs(t={},i={}){const s=new URLSearchParams;Object.keys(t).forEach(l=>{t[l]&&s.append(l,t[l])}),Object.keys(i).forEach(l=>{i[l]&&s.append(l,i[l])});const m=s.toString();return await this.request(`/audit${m?"?"+m:""}`)}async getUserActivityStats(t,i={}){const m=new URLSearchParams(i).toString();return await this.request(`/audit/user-stats/${t}${m?"?"+m:""}`)}async getDocumentEditHistory(t,i=20){return await this.request(`/audit/document-history/${t}?limit=${i}`)}async getGroupAuditLogs(t,i={},s={}){const m=new URLSearchParams;Object.keys(i).forEach(c=>{i[c]&&m.append(c,i[c])}),Object.keys(s).forEach(c=>{s[c]&&m.append(c,s[c])});const l=m.toString();return await this.request(`/audit/group/${t}${l?"?"+l:""}`)}async getAuditSummary(t={}){const s=new URLSearchParams(t).toString();return await this.request(`/audit/stats/summary${s?"?"+s:""}`)}async getAuditLogDetail(t){return await this.request(`/audit/${t}`)}async clearAuditLogs(t={}){return await this.request("/audit",{method:"DELETE",body:JSON.stringify(t)})}async uploadFile(t,i,s=""){const m=new FormData;m.append("file",i),m.append("groupId",t),s&&m.append("description",s);const l=await fetch(`${Qe}/files/upload`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:m});if(!l.ok){const c=await l.json().catch(()=>({message:"上传失败"}));throw new Error(c.message||"上传失败")}return await l.json()}async getGroupFiles(t){return await this.request(`/files/group/${t}`)}async deleteFile(t){return await this.request(`/files/${t}`,{method:"DELETE"})}getFileDownloadUrl(t){return`${Qe}/files/${t}/download?token=${this.token}`}async createPoll(t){return await this.request("/polls",{method:"POST",body:JSON.stringify(t)})}async getGroupPolls(t){return await this.request(`/polls/group/${t}`)}async getPoll(t){return await this.request(`/polls/${t}`)}async vote(t,i){return await this.request(`/polls/${t}/vote`,{method:"POST",body:JSON.stringify({optionIndexes:i})})}async endPoll(t){return await this.request(`/polls/${t}/end`,{method:"PUT"})}async deletePoll(t){return await this.request(`/polls/${t}`,{method:"DELETE"})}}function Ne(r){if(typeof r!="string"||!r)throw new Error("expected a non-empty string, got: "+r)}function et(r){if(typeof r!="number")throw new Error("expected a number, got: "+r)}const wn=1,kn=1,Ae="emoji",je="keyvalue",ht="favorites",En="tokens",Nt="tokens",Bn="unicode",Ot="count",In="group",Ln="order",Rt="group-order",ct="eTag",We="url",kt="skinTone",Pe="readonly",bt="readwrite",Ht="skinUnicodes",$n="skinUnicodes",Tn="https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json",Sn="en";function Mn(r,t){const i=new Set,s=[];for(const m of r){const l=t(m);i.has(l)||(i.add(l),s.push(m))}return s}function Et(r){return Mn(r,t=>t.unicode)}function Cn(r){function t(i,s,m){const l=s?r.createObjectStore(i,{keyPath:s}):r.createObjectStore(i);if(m)for(const[c,[u,P]]of Object.entries(m))l.createIndex(c,u,{multiEntry:P});return l}t(je),t(Ae,Bn,{[Nt]:[En,!0],[Rt]:[[In,Ln]],[Ht]:[$n,!0]}),t(ht,void 0,{[Ot]:[""]})}const pt={},qe={},Ve={};function qt(r,t,i){i.onerror=()=>t(i.error),i.onblocked=()=>t(new Error("IDB blocked")),i.onsuccess=()=>r(i.result)}async function An(r){const t=await new Promise((i,s)=>{const m=indexedDB.open(r,wn);pt[r]=m,m.onupgradeneeded=l=>{l.oldVersion<kn&&Cn(m.result)},qt(i,s,m)});return t.onclose=()=>ft(r),t}function zn(r){return qe[r]||(qe[r]=An(r)),qe[r]}function Se(r,t,i,s){return new Promise((m,l)=>{const c=r.transaction(t,i,{durability:"relaxed"}),u=typeof t=="string"?c.objectStore(t):t.map(A=>c.objectStore(A));let P;s(u,c,A=>{P=A}),c.oncomplete=()=>m(P),c.onerror=()=>l(c.error)})}function ft(r){const t=pt[r],i=t&&t.result;if(i){i.close();const s=Ve[r];if(s)for(const m of s)m()}delete pt[r],delete qe[r],delete Ve[r]}function Dn(r){return new Promise((t,i)=>{ft(r);const s=indexedDB.deleteDatabase(r);qt(t,i,s)})}function _n(r,t){let i=Ve[r];i||(i=Ve[r]=[]),i.push(t)}const jn=new Set([":D","XD",":'D","O:)",":X",":P",";P","XP",":L",":Z",":j","8D","XO","8)",":B",":O",":S",":'o","Dx","X(","D:",":C",">0)",":3","</3","<3","\\M/",":E","8#"]);function _e(r){return r.split(/[\s_]+/).map(t=>!t.match(/\w/)||jn.has(t)?t.toLowerCase():t.replace(/[)(:,]/g,"").replace(/’/g,"'").toLowerCase()).filter(Boolean)}const Pn=2;function Gt(r){return r.filter(Boolean).map(t=>t.toLowerCase()).filter(t=>t.length>=Pn)}function Un(r){return r.map(({annotation:i,emoticon:s,group:m,order:l,shortcodes:c,skins:u,tags:P,emoji:A,version:D})=>{const R=[...new Set(Gt([...(c||[]).map(_e).flat(),...(P||[]).map(_e).flat(),..._e(i),s]))].sort(),F={annotation:i,group:m,order:l,tags:P,tokens:R,unicode:A,version:D};if(s&&(F.emoticon=s),c&&(F.shortcodes=c),u){F.skinTones=[],F.skinUnicodes=[],F.skinVersions=[];for(const{tone:W,emoji:ue,version:oe}of u)F.skinTones.push(W),F.skinUnicodes.push(ue),F.skinVersions.push(oe)}return F})}function Wt(r,t,i,s){r[t](i).onsuccess=m=>s&&s(m.target.result)}function Ce(r,t,i){Wt(r,"get",t,i)}function Vt(r,t,i){Wt(r,"getAll",t,i)}function xt(r){r.commit&&r.commit()}function Fn(r,t){let i=r[0];for(let s=1;s<r.length;s++){const m=r[s];t(i)>t(m)&&(i=m)}return i}function Yt(r,t){const i=Fn(r,m=>m.length),s=[];for(const m of i)r.some(l=>l.findIndex(c=>t(c)===t(m))===-1)||s.push(m);return s}async function Nn(r){return!await vt(r,je,We)}async function On(r,t,i){const[s,m]=await Promise.all([ct,We].map(l=>vt(r,je,l)));return s===i&&m===t}async function Rn(r,t){return Se(r,Ae,Pe,(s,m,l)=>{let c;const u=()=>{s.getAll(c&&IDBKeyRange.lowerBound(c,!0),50).onsuccess=P=>{const A=P.target.result;for(const D of A)if(c=D.unicode,t(D))return l(D);if(A.length<50)return l();u()}};u()})}async function Kt(r,t,i,s){try{const m=Un(t);await Se(r,[Ae,je],bt,([l,c],u)=>{let P,A,D=0;function R(){++D===2&&F()}function F(){if(!(P===s&&A===i)){l.clear();for(const W of m)l.put(W);c.put(s,ct),c.put(i,We),xt(u)}}Ce(c,ct,W=>{P=W,R()}),Ce(c,We,W=>{A=W,R()})})}finally{}}async function Hn(r,t){return Se(r,Ae,Pe,(i,s,m)=>{const l=IDBKeyRange.bound([t,0],[t+1,0],!1,!0);Vt(i.index(Rt),l,m)})}async function Jt(r,t){const i=Gt(_e(t));return i.length?Se(r,Ae,Pe,(s,m,l)=>{const c=[],u=()=>{c.length===i.length&&P()},P=()=>{const A=Yt(c,D=>D.unicode);l(A.sort((D,R)=>D.order<R.order?-1:1))};for(let A=0;A<i.length;A++){const D=i[A],R=A===i.length-1?IDBKeyRange.bound(D,D+"￿",!1,!0):IDBKeyRange.only(D);Vt(s.index(Nt),R,F=>{c.push(F),u()})}}):[]}async function qn(r,t){const i=await Jt(r,t);return i.length?i.filter(s=>(s.shortcodes||[]).map(l=>l.toLowerCase()).includes(t.toLowerCase()))[0]||null:await Rn(r,m=>(m.shortcodes||[]).includes(t.toLowerCase()))||null}async function Gn(r,t){return Se(r,Ae,Pe,(i,s,m)=>Ce(i,t,l=>{if(l)return m(l);Ce(i.index(Ht),t,c=>m(c||null))}))}function vt(r,t,i){return Se(r,t,Pe,(s,m,l)=>Ce(s,i,l))}function Wn(r,t,i,s){return Se(r,t,bt,(m,l)=>{m.put(s,i),xt(l)})}function Vn(r,t){return Se(r,ht,bt,(i,s)=>Ce(i,t,m=>{i.put((m||0)+1,t),xt(s)}))}function Yn(r,t,i){return i===0?[]:Se(r,[ht,Ae],Pe,([s,m],l,c)=>{const u=[];s.index(Ot).openCursor(void 0,"prev").onsuccess=P=>{const A=P.target.result;if(!A)return c(u);function D(W){if(u.push(W),u.length===i)return c(u);A.continue()}const R=A.primaryKey,F=t.byName(R);if(F)return D(F);Ce(m,R,W=>{if(W)return D(W);A.continue()})}})}const Oe="";function Kn(r,t){const i=new Map;for(const m of r){const l=t(m);for(const c of l){let u=i;for(let A=0;A<c.length;A++){const D=c.charAt(A);let R=u.get(D);R||(R=new Map,u.set(D,R)),u=R}let P=u.get(Oe);P||(P=[],u.set(Oe,P)),P.push(m)}}return(m,l)=>{let c=i;for(let A=0;A<m.length;A++){const D=m.charAt(A),R=c.get(D);if(R)c=R;else return[]}if(l)return c.get(Oe)||[];const u=[],P=[c];for(;P.length;){const D=[...P.shift().entries()].sort((R,F)=>R[0]<F[0]?-1:1);for(const[R,F]of D)R===Oe?u.push(...F):P.push(F)}return u}}const Jn=["name","url"];function Xn(r){const t=r&&Array.isArray(r),i=t&&r.length&&(!r[0]||Jn.some(s=>!(s in r[0])));if(!t||i)throw new Error("Custom emojis are in the wrong format")}function Bt(r){Xn(r);const t=(F,W)=>F.name.toLowerCase()<W.name.toLowerCase()?-1:1,i=r.sort(t),m=Kn(r,F=>{const W=new Set;if(F.shortcodes)for(const ue of F.shortcodes)for(const oe of _e(ue))W.add(oe);return W}),l=F=>m(F,!0),c=F=>m(F,!1),u=F=>{const W=_e(F),ue=W.map((oe,be)=>(be<W.length-1?l:c)(oe));return Yt(ue,oe=>oe.name).sort(t)},P=new Map,A=new Map;for(const F of r){A.set(F.name.toLowerCase(),F);for(const W of F.shortcodes||[])P.set(W.toLowerCase(),F)}return{all:i,search:u,byShortcode:F=>P.get(F.toLowerCase()),byName:F=>A.get(F.toLowerCase())}}const Zn=typeof wrappedJSObject<"u";function Ue(r){if(!r)return r;if(Zn&&(r=structuredClone(r)),delete r.tokens,r.skinTones){const t=r.skinTones.length;r.skins=Array(t);for(let i=0;i<t;i++)r.skins[i]={tone:r.skinTones[i],unicode:r.skinUnicodes[i],version:r.skinVersions[i]};delete r.skinTones,delete r.skinUnicodes,delete r.skinVersions}return r}function Xt(r){r||console.warn("emoji-picker-element is more efficient if the dataSource server exposes an ETag header.")}const Qn=["annotation","emoji","group","order","version"];function er(r){if(!r||!Array.isArray(r)||!r[0]||typeof r[0]!="object"||Qn.some(t=>!(t in r[0])))throw new Error("Emoji data is in the wrong format")}function Zt(r,t){if(Math.floor(r.status/100)!==2)throw new Error("Failed to fetch: "+t+": "+r.status)}async function tr(r){const t=await fetch(r,{method:"HEAD"});Zt(t,r);const i=t.headers.get("etag");return Xt(i),i}async function ut(r){const t=await fetch(r);Zt(t,r);const i=t.headers.get("etag");Xt(i);const s=await t.json();return er(s),[i,s]}function nr(r){for(var t="",i=new Uint8Array(r),s=i.byteLength,m=-1;++m<s;)t+=String.fromCharCode(i[m]);return t}function rr(r){for(var t=r.length,i=new ArrayBuffer(t),s=new Uint8Array(i),m=-1;++m<t;)s[m]=r.charCodeAt(m);return i}async function Qt(r){const t=JSON.stringify(r);let i=rr(t);const s=await crypto.subtle.digest("SHA-1",i),m=nr(s);return btoa(m)}async function ar(r,t){let i,s=await tr(t);if(!s){const m=await ut(t);s=m[0],i=m[1],s||(s=await Qt(i))}await On(r,t,s)||(i||(i=(await ut(t))[1]),await Kt(r,i,t,s))}async function ir(r,t){let[i,s]=await ut(t);i||(i=await Qt(s)),await Kt(r,s,t,i)}async function or(r,t){try{await ar(r,t)}catch(i){if(i.name!=="InvalidStateError")throw i}}class sr{constructor({dataSource:t=Tn,locale:i=Sn,customEmoji:s=[]}={}){this.dataSource=t,this.locale=i,this._dbName=`emoji-picker-element-${this.locale}`,this._db=void 0,this._lazyUpdate=void 0,this._custom=Bt(s),this._clear=this._clear.bind(this),this._ready=this._init()}async _init(){const t=this._db=await zn(this._dbName);_n(this._dbName,this._clear);const i=this.dataSource;await Nn(t)?await ir(t,i):this._lazyUpdate=or(t,i)}async ready(){const t=async()=>(this._ready||(this._ready=this._init()),this._ready);await t(),this._db||await t()}async getEmojiByGroup(t){return et(t),await this.ready(),Et(await Hn(this._db,t)).map(Ue)}async getEmojiBySearchQuery(t){Ne(t),await this.ready();const i=this._custom.search(t),s=Et(await Jt(this._db,t)).map(Ue);return[...i,...s]}async getEmojiByShortcode(t){Ne(t),await this.ready();const i=this._custom.byShortcode(t);return i||Ue(await qn(this._db,t))}async getEmojiByUnicodeOrName(t){Ne(t),await this.ready();const i=this._custom.byName(t);return i||Ue(await Gn(this._db,t))}async getPreferredSkinTone(){return await this.ready(),await vt(this._db,je,kt)||0}async setPreferredSkinTone(t){return et(t),await this.ready(),Wn(this._db,je,kt,t)}async incrementFavoriteEmojiCount(t){return Ne(t),await this.ready(),Vn(this._db,t)}async getTopFavoriteEmoji(t){return et(t),await this.ready(),(await Yn(this._db,this._custom,t)).map(Ue)}set customEmoji(t){this._custom=Bt(t)}get customEmoji(){return this._custom.all}async _shutdown(){await this.ready();try{await this._lazyUpdate}catch{}}_clear(){this._db=this._ready=this._lazyUpdate=void 0}async close(){await this._shutdown(),await ft(this._dbName)}async delete(){await this._shutdown(),await Dn(this._dbName)}}const gt=[[-1,"✨","custom"],[0,"😀","smileys-emotion"],[1,"👋","people-body"],[3,"🐱","animals-nature"],[4,"🍎","food-drink"],[5,"🏠️","travel-places"],[6,"⚽","activities"],[7,"📝","objects"],[8,"⛔️","symbols"],[9,"🏁","flags"]].map(([r,t,i])=>({id:r,emoji:t,name:i})),tt=gt.slice(1),dr=2,It=6,en=typeof requestIdleCallback=="function"?requestIdleCallback:setTimeout;function Lt(r){return r.unicode.includes("‍")}const lr={"🫪":17,"🫩":16,"🫨":15.1,"🫠":14,"🥲":13.1,"🥻":12.1,"🥰":11,"🤩":5,"👱‍♀️":4,"🤣":3,"👁️‍🗨️":2,"😀":1,"😐️":.7,"😃":.6},cr=1e3,pr="🖐️",ur=8,gr=["😊","😒","❤️","👍️","😍","😂","😭","☺️","😔","😩","😏","💕","🙌","😘"],tn='"Twemoji Mozilla","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji","EmojiOne Color","Android Emoji",sans-serif',mr=(r,t)=>r<t?-1:r>t?1:0,$t=(r,t)=>{const i=document.createElement("canvas");i.width=i.height=1;const s=i.getContext("2d",{willReadFrequently:!0});return s.textBaseline="top",s.font=`100px ${tn}`,s.fillStyle=t,s.scale(.01,.01),s.fillText(r,0,0),s.getImageData(0,0,1,1).data},yr=(r,t)=>{const i=[...r].join(","),s=[...t].join(",");return i===s&&!i.startsWith("0,0,0,")};function hr(r){const t=$t(r,"#000"),i=$t(r,"#fff");return t&&i&&yr(t,i)}function br(){const r=Object.entries(lr);try{for(const[t,i]of r)if(hr(t))return i}catch{}finally{}return r[0][1]}let nt;const rt=()=>(nt||(nt=new Promise(r=>en(()=>r(br())))),nt),mt=new Map,fr="️",xr="\uD83C",vr="‍",wr=127995,kr=57339;function Er(r,t){if(t===0)return r;const i=r.indexOf(vr);return i!==-1?r.substring(0,i)+String.fromCodePoint(wr+t-1)+r.substring(i):(r.endsWith(fr)&&(r=r.substring(0,r.length-1)),r+xr+String.fromCodePoint(kr+t-1))}function Ee(r){r.preventDefault(),r.stopPropagation()}function at(r,t,i){return t+=r?-1:1,t<0?t=i.length-1:t>=i.length&&(t=0),t}function nn(r,t){const i=new Set,s=[];for(const m of r){const l=t(m);i.has(l)||(i.add(l),s.push(m))}return s}function Br(r,t){const i=s=>{const m={};for(const l of s)typeof l.tone=="number"&&l.version<=t&&(m[l.tone]=l.unicode);return m};return r.map(({unicode:s,skins:m,shortcodes:l,url:c,name:u,category:P,annotation:A})=>({unicode:s,name:u,shortcodes:l,url:c,category:P,annotation:A,id:s||u,skins:m&&i(m)}))}const Ge=requestAnimationFrame;let Ir=typeof ResizeObserver=="function";function Lr(r,t,i){let s;Ir?(s=new ResizeObserver(i),s.observe(r)):Ge(i),t.addEventListener("abort",()=>{s&&s.disconnect()})}function Tt(r){{const t=document.createRange();return t.selectNode(r.firstChild),t.getBoundingClientRect().width}}let it;function $r(r,t,i){let s=!0;for(const m of r){const l=i(m);if(!l)continue;const c=Tt(l);typeof it>"u"&&(it=Tt(t));const u=c/1.8<it;mt.set(m.unicode,u),u||(s=!1)}return s}function Tr(r){return nn(r,t=>t)}function Sr(r){r&&(r.scrollTop=0)}function Fe(r,t,i){let s=r.get(t);return s||(s=i(),r.set(t,s)),s}function St(r){return""+r}function Mr(r){const t=document.createElement("template");return t.innerHTML=r,t}const Cr=new WeakMap,Ar=new WeakMap,zr=Symbol("un-keyed"),Dr="replaceChildren"in Element.prototype;function _r(r,t){Dr?r.replaceChildren(...t):(r.innerHTML="",r.append(...t))}function jr(r,t){let i=r.firstChild,s=0;for(;i;){if(t[s]!==i)return!0;i=i.nextSibling,s++}return s!==t.length}function Pr(r,t){const{targetNode:i}=t;let{targetParentNode:s}=t,m=!1;s?m=jr(s,r):(m=!0,t.targetNode=void 0,t.targetParentNode=s=i.parentNode),m&&_r(s,r)}function Ur(r,t){for(const i of t){const{targetNode:s,currentExpression:m,binding:{expressionIndex:l,attributeName:c,attributeValuePre:u,attributeValuePost:P}}=i,A=r[l];if(m!==A)if(i.currentExpression=A,c)if(A===null)s.removeAttribute(c);else{const D=u+St(A)+P;s.setAttribute(c,D)}else{let D;Array.isArray(A)?Pr(A,i):A instanceof Element?(D=A,s.replaceWith(D)):s.nodeValue=St(A),D&&(i.targetNode=D)}}}function Fr(r){let t="",i=!1,s=!1,m=-1;const l=new Map,c=[];let u=0;for(let A=0,D=r.length;A<D;A++){const R=r[A];if(t+=R.slice(u),A===D-1)break;for(let K=0;K<R.length;K++)switch(R.charAt(K)){case"<":{R.charAt(K+1)==="/"?c.pop():(i=!0,c.push(++m));break}case">":{i=!1,s=!1;break}case"=":{s=!0;break}}const F=c[c.length-1],W=Fe(l,F,()=>[]);let ue,oe,be;if(s){const K=/(\S+)="?([^"=]*)$/.exec(R);ue=K[1],oe=K[2];const te=/^([^">]*)("?)/.exec(r[A+1]);be=te[1],t=t.slice(0,-1*K[0].length),u=te[0].length}else u=0;const xe={attributeName:ue,attributeValuePre:oe,attributeValuePost:be,expressionIndex:A};W.push(xe),!i&&!s&&(t+=" ")}return{template:Mr(t),elementsToBindings:l}}function Mt(r,t,i){for(let s=0;s<r.length;s++){const m=r[s],l=m.attributeName?t:t.firstChild,c={binding:m,targetNode:l,targetParentNode:void 0,currentExpression:void 0};i.push(c)}}function Nr(r,t){const i=[];let s;if(t.size===1&&(s=t.get(0)))Mt(s,r,i);else{const m=document.createTreeWalker(r,NodeFilter.SHOW_ELEMENT);let l=r,c=-1;do{const u=t.get(++c);u&&Mt(u,l,i)}while(l=m.nextNode())}return i}function Or(r){const{template:t,elementsToBindings:i}=Fe(Cr,r,()=>Fr(r)),s=t.cloneNode(!0).content.firstElementChild,m=Nr(s,i);return function(c){return Ur(c,m),s}}function Rr(r){const t=Fe(Ar,r,()=>new Map);let i=zr;function s(l,...c){const u=Fe(t,l,()=>new Map);return Fe(u,i,()=>Or(l))(c)}function m(l,c,u){return l.map((P,A)=>{const D=i;i=u(P);try{return c(P,A)}finally{i=D}})}return{map:m,html:s}}function Hr(r,t,i,s,m,l,c,u,P){const{labelWithSkin:A,titleForEmoji:D,unicodeWithSkin:R}=i,{html:F,map:W}=Rr(t);function ue(K,te,me){return W(K,(se,ve)=>F`<button role="${te?"option":"menuitem"}" aria-selected="${te?ve===t.activeSearchItem:null}" aria-label="${A(se,t.currentSkinTone)}" title="${D(se)}" class="${"emoji"+(te&&ve===t.activeSearchItem?" active":"")+(se.unicode?"":" custom-emoji")}" id="${`${me}-${se.id}`}" style="${se.unicode?null:`--custom-emoji-background: url(${JSON.stringify(se.url)})`}">${se.unicode?R(se,t.currentSkinTone):""}</button>`,se=>`${me}-${se.id}`)}const be=F`<section data-ref="rootElement" class="picker" aria-label="${t.i18n.regionLabel}" style="${t.pickerStyle||""}"><div class="pad-top"></div><div class="search-row"><div class="search-wrapper"><input id="search" class="search" type="search" role="combobox" enterkeyhint="search" placeholder="${t.i18n.searchLabel}" autocapitalize="none" autocomplete="off" spellcheck="true" aria-expanded="${!!(t.searchMode&&t.currentEmojis.length)}" aria-controls="search-results" aria-describedby="search-description" aria-autocomplete="list" aria-activedescendant="${t.activeSearchItemId?`emo-${t.activeSearchItemId}`:null}" data-ref="searchElement" data-on-input="onSearchInput" data-on-keydown="onSearchKeydown"><label class="sr-only" for="search">${t.i18n.searchLabel}</label> <span id="search-description" class="sr-only">${t.i18n.searchDescription}</span></div><div class="skintone-button-wrapper ${t.skinTonePickerExpandedAfterAnimation?"expanded":""}"><button id="skintone-button" class="emoji ${t.skinTonePickerExpanded?"hide-focus":""}" aria-label="${t.skinToneButtonLabel}" title="${t.skinToneButtonLabel}" aria-describedby="skintone-description" aria-haspopup="listbox" aria-expanded="${t.skinTonePickerExpanded}" aria-controls="skintone-list" data-on-click="onClickSkinToneButton">${t.skinToneButtonText||""}</button></div><span id="skintone-description" class="sr-only">${t.i18n.skinToneDescription}</span><div data-ref="skinToneDropdown" id="skintone-list" class="skintone-list hide-focus ${t.skinTonePickerExpanded?"":"hidden no-animate"}" style="transform:translateY(${t.skinTonePickerExpanded?0:"calc(-1 * var(--num-skintones) * var(--total-emoji-size))"})" role="listbox" aria-label="${t.i18n.skinTonesLabel}" aria-activedescendant="skintone-${t.activeSkinTone}" aria-hidden="${!t.skinTonePickerExpanded}" tabIndex="-1" data-on-focusout="onSkinToneOptionsFocusOut" data-on-click="onSkinToneOptionsClick" data-on-keydown="onSkinToneOptionsKeydown" data-on-keyup="onSkinToneOptionsKeyup">${W(t.skinTones,(K,te)=>F`<div id="skintone-${te}" class="emoji ${te===t.activeSkinTone?"active":""}" aria-selected="${te===t.activeSkinTone}" role="option" title="${t.i18n.skinTones[te]}" aria-label="${t.i18n.skinTones[te]}">${K}</div>`,K=>K)}</div></div><div class="nav" role="tablist" style="grid-template-columns:repeat(${t.groups.length},1fr)" aria-label="${t.i18n.categoriesLabel}" data-on-keydown="onNavKeydown" data-on-click="onNavClick">${W(t.groups,K=>F`<button role="tab" class="nav-button" aria-controls="tab-${K.id}" aria-label="${t.i18n.categories[K.name]}" aria-selected="${!t.searchMode&&t.currentGroup.id===K.id}" title="${t.i18n.categories[K.name]}" data-group-id="${K.id}"><div class="nav-emoji emoji">${K.emoji}</div></button>`,K=>K.id)}</div><div class="indicator-wrapper"><div class="indicator" style="transform:translateX(${(t.isRtl?-1:1)*t.currentGroupIndex*100}%)"></div></div><div class="message ${t.message?"":"gone"}" role="alert" aria-live="polite">${t.message||""}</div><div data-ref="tabpanelElement" class="tabpanel ${!t.databaseLoaded||t.message?"gone":""}" role="${t.searchMode?"region":"tabpanel"}" aria-label="${t.searchMode?t.i18n.searchResultsLabel:t.i18n.categories[t.currentGroup.name]}" id="${t.searchMode?null:`tab-${t.currentGroup.id}`}" tabIndex="0" data-on-click="onEmojiClick"><div data-action="calculateEmojiGridStyle">${W(t.currentEmojisWithCategories,(K,te)=>F`<div><div id="menu-label-${te}" class="category ${t.currentEmojisWithCategories.length===1&&t.currentEmojisWithCategories[0].category===""?"gone":""}" aria-hidden="true">${t.searchMode?t.i18n.searchResultsLabel:K.category?K.category:t.currentEmojisWithCategories.length>1?t.i18n.categories.custom:t.i18n.categories[t.currentGroup.name]}</div><div class="emoji-menu ${te!==0&&!t.searchMode&&t.currentGroup.id===-1?"visibility-auto":""}" style="${`--num-rows: ${Math.ceil(K.emojis.length/t.numColumns)}`}" data-action="updateOnIntersection" role="${t.searchMode?"listbox":"menu"}" aria-labelledby="menu-label-${te}" id="${t.searchMode?"search-results":null}">${ue(K.emojis,t.searchMode,"emo")}</div></div>`,K=>K.category)}</div></div><div class="favorites onscreen emoji-menu ${t.message?"gone":""}" role="menu" aria-label="${t.i18n.favoritesLabel}" data-on-click="onEmojiClick">${ue(t.currentFavorites,!1,"fav")}</div><button data-ref="baselineEmoji" aria-hidden="true" tabindex="-1" class="abs-pos hidden emoji baseline-emoji">😀</button></section>`,xe=(K,te)=>{for(const me of r.querySelectorAll(`[${K}]`))te(me,me.getAttribute(K))};if(P){r.appendChild(be);for(const K of["click","focusout","input","keydown","keyup"])xe(`data-on-${K}`,(te,me)=>{te.addEventListener(K,s[me])});xe("data-ref",(K,te)=>{l[te]=K}),c.addEventListener("abort",()=>{r.removeChild(be)})}xe("data-action",(K,te)=>{let me=u.get(te);me||u.set(te,me=new WeakSet),me.has(K)||(me.add(K),m[te](K))})}const Ye=typeof queueMicrotask=="function"?queueMicrotask:r=>Promise.resolve().then(r);function qr(r){let t=!1,i;const s=new Map,m=new Set;let l;const c=()=>{if(t)return;const A=[...m];m.clear();try{for(const D of A)D()}finally{l=!1,m.size&&(l=!0,Ye(c))}},u=new Proxy({},{get(A,D){if(i){let R=s.get(D);R||(R=new Set,s.set(D,R)),R.add(i)}return A[D]},set(A,D,R){if(A[D]!==R){A[D]=R;const F=s.get(D);if(F){for(const W of F)m.add(W);l||(l=!0,Ye(c))}}return!0}}),P=A=>{const D=()=>{const R=i;i=D;try{return A()}finally{i=R}};return D()};return r.addEventListener("abort",()=>{t=!0}),{state:u,createEffect:P}}function ot(r,t,i){if(r.length!==t.length)return!1;for(let s=0;s<r.length;s++)if(!i(r[s],t[s]))return!1;return!0}const Ct=new WeakMap;function Gr(r,t,i){{const s=r.closest(".tabpanel");let m=Ct.get(s);m||(m=new IntersectionObserver(i,{root:s,rootMargin:"50% 0px 50% 0px",threshold:0}),Ct.set(s,m),t.addEventListener("abort",()=>{m.disconnect()})),m.observe(r)}}const st=[],{assign:Re}=Object;function Wr(r,t){const i={},s=new AbortController,m=s.signal,{state:l,createEffect:c}=qr(m),u=new Map;Re(l,{skinToneEmoji:void 0,i18n:void 0,database:void 0,customEmoji:void 0,customCategorySorting:void 0,emojiVersion:void 0}),Re(l,t),Re(l,{initialLoad:!0,currentEmojis:[],currentEmojisWithCategories:[],rawSearchText:"",searchText:"",searchMode:!1,activeSearchItem:-1,message:void 0,skinTonePickerExpanded:!1,skinTonePickerExpandedAfterAnimation:!1,currentSkinTone:0,activeSkinTone:0,skinToneButtonText:void 0,pickerStyle:void 0,skinToneButtonLabel:"",skinTones:[],currentFavorites:[],defaultFavoriteEmojis:void 0,numColumns:ur,isRtl:!1,currentGroupIndex:0,groups:tt,databaseLoaded:!1,activeSearchItemId:void 0}),c(()=>{l.currentGroup!==l.groups[l.currentGroupIndex]&&(l.currentGroup=l.groups[l.currentGroupIndex])});const P=o=>{r.getElementById(o).focus()},A=o=>r.getElementById(`emo-${o.id}`),D=(o,g)=>{i.rootElement.dispatchEvent(new CustomEvent(o,{detail:g,bubbles:!0,composed:!0}))},R=(o,g)=>o.id===g.id,F=(o,g)=>{const{category:b,emojis:E}=o,{category:C,emojis:G}=g;return b!==C?!1:ot(E,G,R)},W=o=>{ot(l.currentEmojis,o,R)||(l.currentEmojis=o)},ue=o=>{l.searchMode!==o&&(l.searchMode=o)},oe=o=>{ot(l.currentEmojisWithCategories,o,F)||(l.currentEmojisWithCategories=o)},be=(o,g)=>g&&o.skins&&o.skins[g]||o.unicode,te={labelWithSkin:(o,g)=>Tr([o.name||be(o,g),o.annotation,...o.shortcodes||st].filter(Boolean)).join(", "),titleForEmoji:o=>o.annotation||(o.shortcodes||st).join(", "),unicodeWithSkin:be},me={onClickSkinToneButton:B,onEmojiClick:v,onNavClick:fe,onNavKeydown:ie,onSearchKeydown:Y,onSkinToneOptionsClick:w,onSkinToneOptionsFocusOut:p,onSkinToneOptionsKeydown:L,onSkinToneOptionsKeyup:k,onSearchInput:h},se={calculateEmojiGridStyle:z,updateOnIntersection:V};let ve=!0;c(()=>{Hr(r,l,te,me,se,i,m,u,ve),ve=!1}),l.emojiVersion||rt().then(o=>{o||(l.message=l.i18n.emojiUnsupportedMessage)}),c(()=>{async function o(){let g=!1;const b=setTimeout(()=>{g=!0,l.message=l.i18n.loadingMessage},cr);try{await l.database.ready(),l.databaseLoaded=!0}catch(E){console.error(E),l.message=l.i18n.networkErrorMessage}finally{clearTimeout(b),g&&(g=!1,l.message="")}}l.database&&o()}),c(()=>{l.pickerStyle=`
56
+ `,document.getElementById("showRegister").addEventListener("click",()=>{document.getElementById("loginSection").classList.add("hidden"),document.getElementById("registerSection").classList.remove("hidden")}),document.getElementById("showLogin").addEventListener("click",()=>{document.getElementById("registerSection").classList.add("hidden"),document.getElementById("loginSection").classList.remove("hidden")}),document.getElementById("loginForm").addEventListener("submit",async s=>{s.preventDefault();const m=new FormData(s.target),l=m.get("username"),c=m.get("password");try{const u=await i.login(l,c);r(u.user,u.token)}catch(u){document.getElementById("loginError").textContent=u.message}}),document.getElementById("registerForm").addEventListener("submit",async s=>{s.preventDefault();const m=new FormData(s.target),l=m.get("username"),c=m.get("password");try{const u=await i.register(l,c);r(u.user,u.token)}catch(u){document.getElementById("registerError").textContent=u.message}})}const Qe="http://localhost:3000/api";class Ut{constructor(){this.token=localStorage.getItem("token")}async request(t,i={}){const s=await fetch(`${Qe}${t}`,{...i,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.token}`,...i.headers}});if(!s.ok){const m=await s.json().catch(()=>({message:"请求失败"}));throw console.error("API 错误:",{endpoint:t,status:s.status,error:m}),new Error(m.message||`请求失败: ${s.status}`)}return await s.json()}async getGroups(){return await this.request("/groups")}async getAllGroups(){return await this.request("/groups/all")}async getGroup(t){return await this.request(`/groups/${t}`)}async createGroup(t,i,s){return await this.request("/groups",{method:"POST",body:JSON.stringify({name:t,description:i,members:s})})}async joinGroup(t){return await this.request(`/groups/${t}/join`,{method:"POST"})}async leaveGroup(t){return await this.request(`/groups/${t}/leave`,{method:"POST"})}async addMember(t,i){return await this.request(`/groups/${t}/members`,{method:"POST",body:JSON.stringify({userId:i})})}async removeMember(t,i){return await this.request(`/groups/${t}/members/${i}`,{method:"DELETE"})}async setMuteAll(t,i){return await this.request(`/groups/${t}/mute/all`,{method:"POST",body:JSON.stringify({enabled:i})})}async setUserMute(t,i,s){return await this.request(`/groups/${t}/mute/users/${i}`,{method:"POST",body:JSON.stringify({muted:s})})}async getAllUsers(){return await this.request("/auth/users")}async getGroupMessages(t){return await this.request(`/groups/${t}/messages`)}async randomCall(t,i=1){return await this.request(`/groups/${t}/call`,{method:"POST",body:JSON.stringify({count:i})})}async clearGroupMessages(t){return await this.request(`/groups/${t}/messages`,{method:"DELETE",body:JSON.stringify({deleteAll:!0})})}async getTasks(t){return await this.request(`/tasks/group/${t}`)}async getMyTasks(){return await this.request("/tasks/my")}async createTask(t){return await this.request("/tasks",{method:"POST",body:JSON.stringify(t)})}async updateTaskStatus(t,i){return await this.request(`/tasks/${t}/status`,{method:"PATCH",body:JSON.stringify({status:i})})}async deleteTask(t){return await this.request(`/tasks/${t}`,{method:"DELETE"})}async getDocuments(t){return await this.request(`/documents/group/${t}`)}async getDocument(t){return await this.request(`/documents/${t}`)}async createDocument(t,i,s,m=[]){return await this.request("/documents",{method:"POST",body:JSON.stringify({title:t,content:i,groupId:s,editableMembers:m})})}async updateDocument(t,i){return await this.request(`/documents/${t}`,{method:"PATCH",body:JSON.stringify({content:i})})}async updateDocumentPermissions(t,i){return await this.request(`/documents/${t}/permissions`,{method:"PATCH",body:JSON.stringify({editableMembers:i})})}async getDocumentVersions(t){return await this.request(`/documents/${t}/versions`)}async deleteDocument(t){return await this.request(`/documents/${t}`,{method:"DELETE"})}async getAuditLogs(t={},i={}){const s=new URLSearchParams;Object.keys(t).forEach(l=>{t[l]&&s.append(l,t[l])}),Object.keys(i).forEach(l=>{i[l]&&s.append(l,i[l])});const m=s.toString();return await this.request(`/audit${m?"?"+m:""}`)}async getUserActivityStats(t,i={}){const m=new URLSearchParams(i).toString();return await this.request(`/audit/user-stats/${t}${m?"?"+m:""}`)}async getDocumentEditHistory(t,i=20){return await this.request(`/audit/document-history/${t}?limit=${i}`)}async getGroupAuditLogs(t,i={},s={}){const m=new URLSearchParams;Object.keys(i).forEach(c=>{i[c]&&m.append(c,i[c])}),Object.keys(s).forEach(c=>{s[c]&&m.append(c,s[c])});const l=m.toString();return await this.request(`/audit/group/${t}${l?"?"+l:""}`)}async getAuditSummary(t={}){const s=new URLSearchParams(t).toString();return await this.request(`/audit/stats/summary${s?"?"+s:""}`)}async getAuditLogDetail(t){return await this.request(`/audit/${t}`)}async clearAuditLogs(t={}){return await this.request("/audit",{method:"DELETE",body:JSON.stringify(t)})}async uploadFile(t,i,s=""){const m=new FormData;m.append("file",i),m.append("groupId",t),s&&m.append("description",s);const l=await fetch(`${Qe}/files/upload`,{method:"POST",headers:{Authorization:`Bearer ${this.token}`},body:m});if(!l.ok){const c=await l.json().catch(()=>({message:"上传失败"}));throw new Error(c.message||"上传失败")}return await l.json()}async getGroupFiles(t){return await this.request(`/files/group/${t}`)}async deleteFile(t){return await this.request(`/files/${t}`,{method:"DELETE"})}getFileDownloadUrl(t){return`${Qe}/files/${t}/download?token=${this.token}`}async createPoll(t){return await this.request("/polls",{method:"POST",body:JSON.stringify(t)})}async getGroupPolls(t){return await this.request(`/polls/group/${t}`)}async getPoll(t){return await this.request(`/polls/${t}`)}async vote(t,i){return await this.request(`/polls/${t}/vote`,{method:"POST",body:JSON.stringify({optionIndexes:i})})}async endPoll(t){return await this.request(`/polls/${t}/end`,{method:"PUT"})}async deletePoll(t){return await this.request(`/polls/${t}`,{method:"DELETE"})}}function Ne(r){if(typeof r!="string"||!r)throw new Error("expected a non-empty string, got: "+r)}function et(r){if(typeof r!="number")throw new Error("expected a number, got: "+r)}const wn=1,kn=1,De="emoji",je="keyvalue",ht="favorites",En="tokens",Nt="tokens",Bn="unicode",Ot="count",In="group",Ln="order",Rt="group-order",ct="eTag",We="url",kt="skinTone",Fe="readonly",ft="readwrite",Ht="skinUnicodes",$n="skinUnicodes",Tn="https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json",Sn="en";function Mn(r,t){const i=new Set,s=[];for(const m of r){const l=t(m);i.has(l)||(i.add(l),s.push(m))}return s}function Et(r){return Mn(r,t=>t.unicode)}function Cn(r){function t(i,s,m){const l=s?r.createObjectStore(i,{keyPath:s}):r.createObjectStore(i);if(m)for(const[c,[u,F]]of Object.entries(m))l.createIndex(c,u,{multiEntry:F});return l}t(je),t(De,Bn,{[Nt]:[En,!0],[Rt]:[[In,Ln]],[Ht]:[$n,!0]}),t(ht,void 0,{[Ot]:[""]})}const pt={},qe={},Ve={};function qt(r,t,i){i.onerror=()=>t(i.error),i.onblocked=()=>t(new Error("IDB blocked")),i.onsuccess=()=>r(i.result)}async function Dn(r){const t=await new Promise((i,s)=>{const m=indexedDB.open(r,wn);pt[r]=m,m.onupgradeneeded=l=>{l.oldVersion<kn&&Cn(m.result)},qt(i,s,m)});return t.onclose=()=>xt(r),t}function An(r){return qe[r]||(qe[r]=Dn(r)),qe[r]}function Se(r,t,i,s){return new Promise((m,l)=>{const c=r.transaction(t,i,{durability:"relaxed"}),u=typeof t=="string"?c.objectStore(t):t.map(D=>c.objectStore(D));let F;s(u,c,D=>{F=D}),c.oncomplete=()=>m(F),c.onerror=()=>l(c.error)})}function xt(r){const t=pt[r],i=t&&t.result;if(i){i.close();const s=Ve[r];if(s)for(const m of s)m()}delete pt[r],delete qe[r],delete Ve[r]}function zn(r){return new Promise((t,i)=>{xt(r);const s=indexedDB.deleteDatabase(r);qt(t,i,s)})}function _n(r,t){let i=Ve[r];i||(i=Ve[r]=[]),i.push(t)}const jn=new Set([":D","XD",":'D","O:)",":X",":P",";P","XP",":L",":Z",":j","8D","XO","8)",":B",":O",":S",":'o","Dx","X(","D:",":C",">0)",":3","</3","<3","\\M/",":E","8#"]);function _e(r){return r.split(/[\s_]+/).map(t=>!t.match(/\w/)||jn.has(t)?t.toLowerCase():t.replace(/[)(:,]/g,"").replace(/’/g,"'").toLowerCase()).filter(Boolean)}const Fn=2;function Gt(r){return r.filter(Boolean).map(t=>t.toLowerCase()).filter(t=>t.length>=Fn)}function Pn(r){return r.map(({annotation:i,emoticon:s,group:m,order:l,shortcodes:c,skins:u,tags:F,emoji:D,version:z})=>{const R=[...new Set(Gt([...(c||[]).map(_e).flat(),...(F||[]).map(_e).flat(),..._e(i),s]))].sort(),U={annotation:i,group:m,order:l,tags:F,tokens:R,unicode:D,version:z};if(s&&(U.emoticon=s),c&&(U.shortcodes=c),u){U.skinTones=[],U.skinUnicodes=[],U.skinVersions=[];for(const{tone:W,emoji:ue,version:oe}of u)U.skinTones.push(W),U.skinUnicodes.push(ue),U.skinVersions.push(oe)}return U})}function Wt(r,t,i,s){r[t](i).onsuccess=m=>s&&s(m.target.result)}function Ce(r,t,i){Wt(r,"get",t,i)}function Vt(r,t,i){Wt(r,"getAll",t,i)}function bt(r){r.commit&&r.commit()}function Un(r,t){let i=r[0];for(let s=1;s<r.length;s++){const m=r[s];t(i)>t(m)&&(i=m)}return i}function Yt(r,t){const i=Un(r,m=>m.length),s=[];for(const m of i)r.some(l=>l.findIndex(c=>t(c)===t(m))===-1)||s.push(m);return s}async function Nn(r){return!await vt(r,je,We)}async function On(r,t,i){const[s,m]=await Promise.all([ct,We].map(l=>vt(r,je,l)));return s===i&&m===t}async function Rn(r,t){return Se(r,De,Fe,(s,m,l)=>{let c;const u=()=>{s.getAll(c&&IDBKeyRange.lowerBound(c,!0),50).onsuccess=F=>{const D=F.target.result;for(const z of D)if(c=z.unicode,t(z))return l(z);if(D.length<50)return l();u()}};u()})}async function Kt(r,t,i,s){try{const m=Pn(t);await Se(r,[De,je],ft,([l,c],u)=>{let F,D,z=0;function R(){++z===2&&U()}function U(){if(!(F===s&&D===i)){l.clear();for(const W of m)l.put(W);c.put(s,ct),c.put(i,We),bt(u)}}Ce(c,ct,W=>{F=W,R()}),Ce(c,We,W=>{D=W,R()})})}finally{}}async function Hn(r,t){return Se(r,De,Fe,(i,s,m)=>{const l=IDBKeyRange.bound([t,0],[t+1,0],!1,!0);Vt(i.index(Rt),l,m)})}async function Jt(r,t){const i=Gt(_e(t));return i.length?Se(r,De,Fe,(s,m,l)=>{const c=[],u=()=>{c.length===i.length&&F()},F=()=>{const D=Yt(c,z=>z.unicode);l(D.sort((z,R)=>z.order<R.order?-1:1))};for(let D=0;D<i.length;D++){const z=i[D],R=D===i.length-1?IDBKeyRange.bound(z,z+"￿",!1,!0):IDBKeyRange.only(z);Vt(s.index(Nt),R,U=>{c.push(U),u()})}}):[]}async function qn(r,t){const i=await Jt(r,t);return i.length?i.filter(s=>(s.shortcodes||[]).map(l=>l.toLowerCase()).includes(t.toLowerCase()))[0]||null:await Rn(r,m=>(m.shortcodes||[]).includes(t.toLowerCase()))||null}async function Gn(r,t){return Se(r,De,Fe,(i,s,m)=>Ce(i,t,l=>{if(l)return m(l);Ce(i.index(Ht),t,c=>m(c||null))}))}function vt(r,t,i){return Se(r,t,Fe,(s,m,l)=>Ce(s,i,l))}function Wn(r,t,i,s){return Se(r,t,ft,(m,l)=>{m.put(s,i),bt(l)})}function Vn(r,t){return Se(r,ht,ft,(i,s)=>Ce(i,t,m=>{i.put((m||0)+1,t),bt(s)}))}function Yn(r,t,i){return i===0?[]:Se(r,[ht,De],Fe,([s,m],l,c)=>{const u=[];s.index(Ot).openCursor(void 0,"prev").onsuccess=F=>{const D=F.target.result;if(!D)return c(u);function z(W){if(u.push(W),u.length===i)return c(u);D.continue()}const R=D.primaryKey,U=t.byName(R);if(U)return z(U);Ce(m,R,W=>{if(W)return z(W);D.continue()})}})}const Oe="";function Kn(r,t){const i=new Map;for(const m of r){const l=t(m);for(const c of l){let u=i;for(let D=0;D<c.length;D++){const z=c.charAt(D);let R=u.get(z);R||(R=new Map,u.set(z,R)),u=R}let F=u.get(Oe);F||(F=[],u.set(Oe,F)),F.push(m)}}return(m,l)=>{let c=i;for(let D=0;D<m.length;D++){const z=m.charAt(D),R=c.get(z);if(R)c=R;else return[]}if(l)return c.get(Oe)||[];const u=[],F=[c];for(;F.length;){const z=[...F.shift().entries()].sort((R,U)=>R[0]<U[0]?-1:1);for(const[R,U]of z)R===Oe?u.push(...U):F.push(U)}return u}}const Jn=["name","url"];function Xn(r){const t=r&&Array.isArray(r),i=t&&r.length&&(!r[0]||Jn.some(s=>!(s in r[0])));if(!t||i)throw new Error("Custom emojis are in the wrong format")}function Bt(r){Xn(r);const t=(U,W)=>U.name.toLowerCase()<W.name.toLowerCase()?-1:1,i=r.sort(t),m=Kn(r,U=>{const W=new Set;if(U.shortcodes)for(const ue of U.shortcodes)for(const oe of _e(ue))W.add(oe);return W}),l=U=>m(U,!0),c=U=>m(U,!1),u=U=>{const W=_e(U),ue=W.map((oe,fe)=>(fe<W.length-1?l:c)(oe));return Yt(ue,oe=>oe.name).sort(t)},F=new Map,D=new Map;for(const U of r){D.set(U.name.toLowerCase(),U);for(const W of U.shortcodes||[])F.set(W.toLowerCase(),U)}return{all:i,search:u,byShortcode:U=>F.get(U.toLowerCase()),byName:U=>D.get(U.toLowerCase())}}const Zn=typeof wrappedJSObject<"u";function Pe(r){if(!r)return r;if(Zn&&(r=structuredClone(r)),delete r.tokens,r.skinTones){const t=r.skinTones.length;r.skins=Array(t);for(let i=0;i<t;i++)r.skins[i]={tone:r.skinTones[i],unicode:r.skinUnicodes[i],version:r.skinVersions[i]};delete r.skinTones,delete r.skinUnicodes,delete r.skinVersions}return r}function Xt(r){r||console.warn("emoji-picker-element is more efficient if the dataSource server exposes an ETag header.")}const Qn=["annotation","emoji","group","order","version"];function er(r){if(!r||!Array.isArray(r)||!r[0]||typeof r[0]!="object"||Qn.some(t=>!(t in r[0])))throw new Error("Emoji data is in the wrong format")}function Zt(r,t){if(Math.floor(r.status/100)!==2)throw new Error("Failed to fetch: "+t+": "+r.status)}async function tr(r){const t=await fetch(r,{method:"HEAD"});Zt(t,r);const i=t.headers.get("etag");return Xt(i),i}async function ut(r){const t=await fetch(r);Zt(t,r);const i=t.headers.get("etag");Xt(i);const s=await t.json();return er(s),[i,s]}function nr(r){for(var t="",i=new Uint8Array(r),s=i.byteLength,m=-1;++m<s;)t+=String.fromCharCode(i[m]);return t}function rr(r){for(var t=r.length,i=new ArrayBuffer(t),s=new Uint8Array(i),m=-1;++m<t;)s[m]=r.charCodeAt(m);return i}async function Qt(r){const t=JSON.stringify(r);let i=rr(t);const s=await crypto.subtle.digest("SHA-1",i),m=nr(s);return btoa(m)}async function ar(r,t){let i,s=await tr(t);if(!s){const m=await ut(t);s=m[0],i=m[1],s||(s=await Qt(i))}await On(r,t,s)||(i||(i=(await ut(t))[1]),await Kt(r,i,t,s))}async function ir(r,t){let[i,s]=await ut(t);i||(i=await Qt(s)),await Kt(r,s,t,i)}async function or(r,t){try{await ar(r,t)}catch(i){if(i.name!=="InvalidStateError")throw i}}class sr{constructor({dataSource:t=Tn,locale:i=Sn,customEmoji:s=[]}={}){this.dataSource=t,this.locale=i,this._dbName=`emoji-picker-element-${this.locale}`,this._db=void 0,this._lazyUpdate=void 0,this._custom=Bt(s),this._clear=this._clear.bind(this),this._ready=this._init()}async _init(){const t=this._db=await An(this._dbName);_n(this._dbName,this._clear);const i=this.dataSource;await Nn(t)?await ir(t,i):this._lazyUpdate=or(t,i)}async ready(){const t=async()=>(this._ready||(this._ready=this._init()),this._ready);await t(),this._db||await t()}async getEmojiByGroup(t){return et(t),await this.ready(),Et(await Hn(this._db,t)).map(Pe)}async getEmojiBySearchQuery(t){Ne(t),await this.ready();const i=this._custom.search(t),s=Et(await Jt(this._db,t)).map(Pe);return[...i,...s]}async getEmojiByShortcode(t){Ne(t),await this.ready();const i=this._custom.byShortcode(t);return i||Pe(await qn(this._db,t))}async getEmojiByUnicodeOrName(t){Ne(t),await this.ready();const i=this._custom.byName(t);return i||Pe(await Gn(this._db,t))}async getPreferredSkinTone(){return await this.ready(),await vt(this._db,je,kt)||0}async setPreferredSkinTone(t){return et(t),await this.ready(),Wn(this._db,je,kt,t)}async incrementFavoriteEmojiCount(t){return Ne(t),await this.ready(),Vn(this._db,t)}async getTopFavoriteEmoji(t){return et(t),await this.ready(),(await Yn(this._db,this._custom,t)).map(Pe)}set customEmoji(t){this._custom=Bt(t)}get customEmoji(){return this._custom.all}async _shutdown(){await this.ready();try{await this._lazyUpdate}catch{}}_clear(){this._db=this._ready=this._lazyUpdate=void 0}async close(){await this._shutdown(),await xt(this._dbName)}async delete(){await this._shutdown(),await zn(this._dbName)}}const gt=[[-1,"✨","custom"],[0,"😀","smileys-emotion"],[1,"👋","people-body"],[3,"🐱","animals-nature"],[4,"🍎","food-drink"],[5,"🏠️","travel-places"],[6,"⚽","activities"],[7,"📝","objects"],[8,"⛔️","symbols"],[9,"🏁","flags"]].map(([r,t,i])=>({id:r,emoji:t,name:i})),tt=gt.slice(1),dr=2,It=6,en=typeof requestIdleCallback=="function"?requestIdleCallback:setTimeout;function Lt(r){return r.unicode.includes("‍")}const lr={"🫪":17,"🫩":16,"🫨":15.1,"🫠":14,"🥲":13.1,"🥻":12.1,"🥰":11,"🤩":5,"👱‍♀️":4,"🤣":3,"👁️‍🗨️":2,"😀":1,"😐️":.7,"😃":.6},cr=1e3,pr="🖐️",ur=8,gr=["😊","😒","❤️","👍️","😍","😂","😭","☺️","😔","😩","😏","💕","🙌","😘"],tn='"Twemoji Mozilla","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji","EmojiOne Color","Android Emoji",sans-serif',mr=(r,t)=>r<t?-1:r>t?1:0,$t=(r,t)=>{const i=document.createElement("canvas");i.width=i.height=1;const s=i.getContext("2d",{willReadFrequently:!0});return s.textBaseline="top",s.font=`100px ${tn}`,s.fillStyle=t,s.scale(.01,.01),s.fillText(r,0,0),s.getImageData(0,0,1,1).data},yr=(r,t)=>{const i=[...r].join(","),s=[...t].join(",");return i===s&&!i.startsWith("0,0,0,")};function hr(r){const t=$t(r,"#000"),i=$t(r,"#fff");return t&&i&&yr(t,i)}function fr(){const r=Object.entries(lr);try{for(const[t,i]of r)if(hr(t))return i}catch{}finally{}return r[0][1]}let nt;const rt=()=>(nt||(nt=new Promise(r=>en(()=>r(fr())))),nt),mt=new Map,xr="️",br="\uD83C",vr="‍",wr=127995,kr=57339;function Er(r,t){if(t===0)return r;const i=r.indexOf(vr);return i!==-1?r.substring(0,i)+String.fromCodePoint(wr+t-1)+r.substring(i):(r.endsWith(xr)&&(r=r.substring(0,r.length-1)),r+br+String.fromCodePoint(kr+t-1))}function Ee(r){r.preventDefault(),r.stopPropagation()}function at(r,t,i){return t+=r?-1:1,t<0?t=i.length-1:t>=i.length&&(t=0),t}function nn(r,t){const i=new Set,s=[];for(const m of r){const l=t(m);i.has(l)||(i.add(l),s.push(m))}return s}function Br(r,t){const i=s=>{const m={};for(const l of s)typeof l.tone=="number"&&l.version<=t&&(m[l.tone]=l.unicode);return m};return r.map(({unicode:s,skins:m,shortcodes:l,url:c,name:u,category:F,annotation:D})=>({unicode:s,name:u,shortcodes:l,url:c,category:F,annotation:D,id:s||u,skins:m&&i(m)}))}const Ge=requestAnimationFrame;let Ir=typeof ResizeObserver=="function";function Lr(r,t,i){let s;Ir?(s=new ResizeObserver(i),s.observe(r)):Ge(i),t.addEventListener("abort",()=>{s&&s.disconnect()})}function Tt(r){{const t=document.createRange();return t.selectNode(r.firstChild),t.getBoundingClientRect().width}}let it;function $r(r,t,i){let s=!0;for(const m of r){const l=i(m);if(!l)continue;const c=Tt(l);typeof it>"u"&&(it=Tt(t));const u=c/1.8<it;mt.set(m.unicode,u),u||(s=!1)}return s}function Tr(r){return nn(r,t=>t)}function Sr(r){r&&(r.scrollTop=0)}function Ue(r,t,i){let s=r.get(t);return s||(s=i(),r.set(t,s)),s}function St(r){return""+r}function Mr(r){const t=document.createElement("template");return t.innerHTML=r,t}const Cr=new WeakMap,Dr=new WeakMap,Ar=Symbol("un-keyed"),zr="replaceChildren"in Element.prototype;function _r(r,t){zr?r.replaceChildren(...t):(r.innerHTML="",r.append(...t))}function jr(r,t){let i=r.firstChild,s=0;for(;i;){if(t[s]!==i)return!0;i=i.nextSibling,s++}return s!==t.length}function Fr(r,t){const{targetNode:i}=t;let{targetParentNode:s}=t,m=!1;s?m=jr(s,r):(m=!0,t.targetNode=void 0,t.targetParentNode=s=i.parentNode),m&&_r(s,r)}function Pr(r,t){for(const i of t){const{targetNode:s,currentExpression:m,binding:{expressionIndex:l,attributeName:c,attributeValuePre:u,attributeValuePost:F}}=i,D=r[l];if(m!==D)if(i.currentExpression=D,c)if(D===null)s.removeAttribute(c);else{const z=u+St(D)+F;s.setAttribute(c,z)}else{let z;Array.isArray(D)?Fr(D,i):D instanceof Element?(z=D,s.replaceWith(z)):s.nodeValue=St(D),z&&(i.targetNode=z)}}}function Ur(r){let t="",i=!1,s=!1,m=-1;const l=new Map,c=[];let u=0;for(let D=0,z=r.length;D<z;D++){const R=r[D];if(t+=R.slice(u),D===z-1)break;for(let K=0;K<R.length;K++)switch(R.charAt(K)){case"<":{R.charAt(K+1)==="/"?c.pop():(i=!0,c.push(++m));break}case">":{i=!1,s=!1;break}case"=":{s=!0;break}}const U=c[c.length-1],W=Ue(l,U,()=>[]);let ue,oe,fe;if(s){const K=/(\S+)="?([^"=]*)$/.exec(R);ue=K[1],oe=K[2];const te=/^([^">]*)("?)/.exec(r[D+1]);fe=te[1],t=t.slice(0,-1*K[0].length),u=te[0].length}else u=0;const be={attributeName:ue,attributeValuePre:oe,attributeValuePost:fe,expressionIndex:D};W.push(be),!i&&!s&&(t+=" ")}return{template:Mr(t),elementsToBindings:l}}function Mt(r,t,i){for(let s=0;s<r.length;s++){const m=r[s],l=m.attributeName?t:t.firstChild,c={binding:m,targetNode:l,targetParentNode:void 0,currentExpression:void 0};i.push(c)}}function Nr(r,t){const i=[];let s;if(t.size===1&&(s=t.get(0)))Mt(s,r,i);else{const m=document.createTreeWalker(r,NodeFilter.SHOW_ELEMENT);let l=r,c=-1;do{const u=t.get(++c);u&&Mt(u,l,i)}while(l=m.nextNode())}return i}function Or(r){const{template:t,elementsToBindings:i}=Ue(Cr,r,()=>Ur(r)),s=t.cloneNode(!0).content.firstElementChild,m=Nr(s,i);return function(c){return Pr(c,m),s}}function Rr(r){const t=Ue(Dr,r,()=>new Map);let i=Ar;function s(l,...c){const u=Ue(t,l,()=>new Map);return Ue(u,i,()=>Or(l))(c)}function m(l,c,u){return l.map((F,D)=>{const z=i;i=u(F);try{return c(F,D)}finally{i=z}})}return{map:m,html:s}}function Hr(r,t,i,s,m,l,c,u,F){const{labelWithSkin:D,titleForEmoji:z,unicodeWithSkin:R}=i,{html:U,map:W}=Rr(t);function ue(K,te,me){return W(K,(se,ve)=>U`<button role="${te?"option":"menuitem"}" aria-selected="${te?ve===t.activeSearchItem:null}" aria-label="${D(se,t.currentSkinTone)}" title="${z(se)}" class="${"emoji"+(te&&ve===t.activeSearchItem?" active":"")+(se.unicode?"":" custom-emoji")}" id="${`${me}-${se.id}`}" style="${se.unicode?null:`--custom-emoji-background: url(${JSON.stringify(se.url)})`}">${se.unicode?R(se,t.currentSkinTone):""}</button>`,se=>`${me}-${se.id}`)}const fe=U`<section data-ref="rootElement" class="picker" aria-label="${t.i18n.regionLabel}" style="${t.pickerStyle||""}"><div class="pad-top"></div><div class="search-row"><div class="search-wrapper"><input id="search" class="search" type="search" role="combobox" enterkeyhint="search" placeholder="${t.i18n.searchLabel}" autocapitalize="none" autocomplete="off" spellcheck="true" aria-expanded="${!!(t.searchMode&&t.currentEmojis.length)}" aria-controls="search-results" aria-describedby="search-description" aria-autocomplete="list" aria-activedescendant="${t.activeSearchItemId?`emo-${t.activeSearchItemId}`:null}" data-ref="searchElement" data-on-input="onSearchInput" data-on-keydown="onSearchKeydown"><label class="sr-only" for="search">${t.i18n.searchLabel}</label> <span id="search-description" class="sr-only">${t.i18n.searchDescription}</span></div><div class="skintone-button-wrapper ${t.skinTonePickerExpandedAfterAnimation?"expanded":""}"><button id="skintone-button" class="emoji ${t.skinTonePickerExpanded?"hide-focus":""}" aria-label="${t.skinToneButtonLabel}" title="${t.skinToneButtonLabel}" aria-describedby="skintone-description" aria-haspopup="listbox" aria-expanded="${t.skinTonePickerExpanded}" aria-controls="skintone-list" data-on-click="onClickSkinToneButton">${t.skinToneButtonText||""}</button></div><span id="skintone-description" class="sr-only">${t.i18n.skinToneDescription}</span><div data-ref="skinToneDropdown" id="skintone-list" class="skintone-list hide-focus ${t.skinTonePickerExpanded?"":"hidden no-animate"}" style="transform:translateY(${t.skinTonePickerExpanded?0:"calc(-1 * var(--num-skintones) * var(--total-emoji-size))"})" role="listbox" aria-label="${t.i18n.skinTonesLabel}" aria-activedescendant="skintone-${t.activeSkinTone}" aria-hidden="${!t.skinTonePickerExpanded}" tabIndex="-1" data-on-focusout="onSkinToneOptionsFocusOut" data-on-click="onSkinToneOptionsClick" data-on-keydown="onSkinToneOptionsKeydown" data-on-keyup="onSkinToneOptionsKeyup">${W(t.skinTones,(K,te)=>U`<div id="skintone-${te}" class="emoji ${te===t.activeSkinTone?"active":""}" aria-selected="${te===t.activeSkinTone}" role="option" title="${t.i18n.skinTones[te]}" aria-label="${t.i18n.skinTones[te]}">${K}</div>`,K=>K)}</div></div><div class="nav" role="tablist" style="grid-template-columns:repeat(${t.groups.length},1fr)" aria-label="${t.i18n.categoriesLabel}" data-on-keydown="onNavKeydown" data-on-click="onNavClick">${W(t.groups,K=>U`<button role="tab" class="nav-button" aria-controls="tab-${K.id}" aria-label="${t.i18n.categories[K.name]}" aria-selected="${!t.searchMode&&t.currentGroup.id===K.id}" title="${t.i18n.categories[K.name]}" data-group-id="${K.id}"><div class="nav-emoji emoji">${K.emoji}</div></button>`,K=>K.id)}</div><div class="indicator-wrapper"><div class="indicator" style="transform:translateX(${(t.isRtl?-1:1)*t.currentGroupIndex*100}%)"></div></div><div class="message ${t.message?"":"gone"}" role="alert" aria-live="polite">${t.message||""}</div><div data-ref="tabpanelElement" class="tabpanel ${!t.databaseLoaded||t.message?"gone":""}" role="${t.searchMode?"region":"tabpanel"}" aria-label="${t.searchMode?t.i18n.searchResultsLabel:t.i18n.categories[t.currentGroup.name]}" id="${t.searchMode?null:`tab-${t.currentGroup.id}`}" tabIndex="0" data-on-click="onEmojiClick"><div data-action="calculateEmojiGridStyle">${W(t.currentEmojisWithCategories,(K,te)=>U`<div><div id="menu-label-${te}" class="category ${t.currentEmojisWithCategories.length===1&&t.currentEmojisWithCategories[0].category===""?"gone":""}" aria-hidden="true">${t.searchMode?t.i18n.searchResultsLabel:K.category?K.category:t.currentEmojisWithCategories.length>1?t.i18n.categories.custom:t.i18n.categories[t.currentGroup.name]}</div><div class="emoji-menu ${te!==0&&!t.searchMode&&t.currentGroup.id===-1?"visibility-auto":""}" style="${`--num-rows: ${Math.ceil(K.emojis.length/t.numColumns)}`}" data-action="updateOnIntersection" role="${t.searchMode?"listbox":"menu"}" aria-labelledby="menu-label-${te}" id="${t.searchMode?"search-results":null}">${ue(K.emojis,t.searchMode,"emo")}</div></div>`,K=>K.category)}</div></div><div class="favorites onscreen emoji-menu ${t.message?"gone":""}" role="menu" aria-label="${t.i18n.favoritesLabel}" data-on-click="onEmojiClick">${ue(t.currentFavorites,!1,"fav")}</div><button data-ref="baselineEmoji" aria-hidden="true" tabindex="-1" class="abs-pos hidden emoji baseline-emoji">😀</button></section>`,be=(K,te)=>{for(const me of r.querySelectorAll(`[${K}]`))te(me,me.getAttribute(K))};if(F){r.appendChild(fe);for(const K of["click","focusout","input","keydown","keyup"])be(`data-on-${K}`,(te,me)=>{te.addEventListener(K,s[me])});be("data-ref",(K,te)=>{l[te]=K}),c.addEventListener("abort",()=>{r.removeChild(fe)})}be("data-action",(K,te)=>{let me=u.get(te);me||u.set(te,me=new WeakSet),me.has(K)||(me.add(K),m[te](K))})}const Ye=typeof queueMicrotask=="function"?queueMicrotask:r=>Promise.resolve().then(r);function qr(r){let t=!1,i;const s=new Map,m=new Set;let l;const c=()=>{if(t)return;const D=[...m];m.clear();try{for(const z of D)z()}finally{l=!1,m.size&&(l=!0,Ye(c))}},u=new Proxy({},{get(D,z){if(i){let R=s.get(z);R||(R=new Set,s.set(z,R)),R.add(i)}return D[z]},set(D,z,R){if(D[z]!==R){D[z]=R;const U=s.get(z);if(U){for(const W of U)m.add(W);l||(l=!0,Ye(c))}}return!0}}),F=D=>{const z=()=>{const R=i;i=z;try{return D()}finally{i=R}};return z()};return r.addEventListener("abort",()=>{t=!0}),{state:u,createEffect:F}}function ot(r,t,i){if(r.length!==t.length)return!1;for(let s=0;s<r.length;s++)if(!i(r[s],t[s]))return!1;return!0}const Ct=new WeakMap;function Gr(r,t,i){{const s=r.closest(".tabpanel");let m=Ct.get(s);m||(m=new IntersectionObserver(i,{root:s,rootMargin:"50% 0px 50% 0px",threshold:0}),Ct.set(s,m),t.addEventListener("abort",()=>{m.disconnect()})),m.observe(r)}}const st=[],{assign:Re}=Object;function Wr(r,t){const i={},s=new AbortController,m=s.signal,{state:l,createEffect:c}=qr(m),u=new Map;Re(l,{skinToneEmoji:void 0,i18n:void 0,database:void 0,customEmoji:void 0,customCategorySorting:void 0,emojiVersion:void 0}),Re(l,t),Re(l,{initialLoad:!0,currentEmojis:[],currentEmojisWithCategories:[],rawSearchText:"",searchText:"",searchMode:!1,activeSearchItem:-1,message:void 0,skinTonePickerExpanded:!1,skinTonePickerExpandedAfterAnimation:!1,currentSkinTone:0,activeSkinTone:0,skinToneButtonText:void 0,pickerStyle:void 0,skinToneButtonLabel:"",skinTones:[],currentFavorites:[],defaultFavoriteEmojis:void 0,numColumns:ur,isRtl:!1,currentGroupIndex:0,groups:tt,databaseLoaded:!1,activeSearchItemId:void 0}),c(()=>{l.currentGroup!==l.groups[l.currentGroupIndex]&&(l.currentGroup=l.groups[l.currentGroupIndex])});const F=o=>{r.getElementById(o).focus()},D=o=>r.getElementById(`emo-${o.id}`),z=(o,g)=>{i.rootElement.dispatchEvent(new CustomEvent(o,{detail:g,bubbles:!0,composed:!0}))},R=(o,g)=>o.id===g.id,U=(o,g)=>{const{category:f,emojis:E}=o,{category:C,emojis:G}=g;return f!==C?!1:ot(E,G,R)},W=o=>{ot(l.currentEmojis,o,R)||(l.currentEmojis=o)},ue=o=>{l.searchMode!==o&&(l.searchMode=o)},oe=o=>{ot(l.currentEmojisWithCategories,o,U)||(l.currentEmojisWithCategories=o)},fe=(o,g)=>g&&o.skins&&o.skins[g]||o.unicode,te={labelWithSkin:(o,g)=>Tr([o.name||fe(o,g),o.annotation,...o.shortcodes||st].filter(Boolean)).join(", "),titleForEmoji:o=>o.annotation||(o.shortcodes||st).join(", "),unicodeWithSkin:fe},me={onClickSkinToneButton:B,onEmojiClick:v,onNavClick:xe,onNavKeydown:ie,onSearchKeydown:Y,onSkinToneOptionsClick:w,onSkinToneOptionsFocusOut:p,onSkinToneOptionsKeydown:L,onSkinToneOptionsKeyup:k,onSearchInput:h},se={calculateEmojiGridStyle:A,updateOnIntersection:V};let ve=!0;c(()=>{Hr(r,l,te,me,se,i,m,u,ve),ve=!1}),l.emojiVersion||rt().then(o=>{o||(l.message=l.i18n.emojiUnsupportedMessage)}),c(()=>{async function o(){let g=!1;const f=setTimeout(()=>{g=!0,l.message=l.i18n.loadingMessage},cr);try{await l.database.ready(),l.databaseLoaded=!0}catch(E){console.error(E),l.message=l.i18n.networkErrorMessage}finally{clearTimeout(f),g&&(g=!1,l.message="")}}l.database&&o()}),c(()=>{l.pickerStyle=`
57
57
  --num-groups: ${l.groups.length};
58
58
  --indicator-opacity: ${l.searchMode?0:1};
59
- --num-skintones: ${It};`}),c(()=>{l.customEmoji&&l.database&&U()}),c(()=>{l.customEmoji&&l.customEmoji.length?l.groups!==gt&&(l.groups=gt):l.groups!==tt&&(l.currentGroupIndex&&l.currentGroupIndex--,l.groups=tt)}),c(()=>{async function o(){l.databaseLoaded&&(l.currentSkinTone=await l.database.getPreferredSkinTone())}o()}),c(()=>{l.skinTones=Array(It).fill().map((o,g)=>Er(l.skinToneEmoji,g))}),c(()=>{l.skinToneButtonText=l.skinTones[l.currentSkinTone]}),c(()=>{l.skinToneButtonLabel=l.i18n.skinToneLabel.replace("{skinTone}",l.i18n.skinTones[l.currentSkinTone])}),c(()=>{async function o(){const{database:g}=l,b=(await Promise.all(gr.map(E=>g.getEmojiByUnicodeOrName(E)))).filter(Boolean);l.defaultFavoriteEmojis=b}l.databaseLoaded&&o()});function U(){const{customEmoji:o,database:g}=l,b=o||st;g.customEmoji!==b&&(g.customEmoji=b)}c(()=>{async function o(){U();const{database:g,defaultFavoriteEmojis:b,numColumns:E}=l,C=await g.getTopFavoriteEmoji(E),G=await _(nn([...C,...b],J=>J.unicode||J.name).slice(0,E));l.currentFavorites=G}l.databaseLoaded&&l.defaultFavoriteEmojis&&o()});function z(o){Lr(o,m,()=>{{const g=getComputedStyle(i.rootElement),b=parseInt(g.getPropertyValue("--num-columns"),10),E=g.getPropertyValue("direction")==="rtl";l.numColumns=b,l.isRtl=E}})}function V(o){Gr(o,m,g=>{for(const{target:b,isIntersecting:E}of g)b.classList.toggle("onscreen",E)})}c(()=>{async function o(){const{searchText:g,currentGroup:b,databaseLoaded:E,customEmoji:C}=l;if(!E)l.currentEmojis=[],l.searchMode=!1;else if(g.length>=dr){const G=await Z(g);l.searchText===g&&(W(G),ue(!0))}else{const{id:G}=b;if(G!==-1||C&&C.length){const J=await O(G);l.currentGroup.id===G&&(W(J),ue(!1))}}}o()});const $=()=>{Ge(()=>Sr(i.tabpanelElement))};c(()=>{const{currentEmojis:o,emojiVersion:g}=l,b=o.filter(E=>E.unicode).filter(E=>Lt(E)&&!mt.has(E.unicode));if(!g&&b.length)W(o),Ge(()=>M(b));else{const E=g?o:o.filter(N);W(E),$()}});function M(o){$r(o,i.baselineEmoji,A)?$():l.currentEmojis=[...l.currentEmojis]}function N(o){return!o.unicode||!Lt(o)||mt.get(o.unicode)}async function H(o){const g=l.emojiVersion||await rt();return o.filter(({version:b})=>!b||b<=g)}async function _(o){return Br(o,l.emojiVersion||await rt())}async function O(o){const g=o===-1?l.customEmoji:await l.database.getEmojiByGroup(o);return _(await H(g))}async function Z(o){return _(await H(await l.database.getEmojiBySearchQuery(o)))}c(()=>{}),c(()=>{function o(){const{searchMode:b,currentEmojis:E}=l;if(b)return[{category:"",emojis:E}];const C=new Map;for(const G of E){const J=G.category||"";let ee=C.get(J);ee||(ee=[],C.set(J,ee)),ee.push(G)}return[...C.entries()].map(([G,J])=>({category:G,emojis:J})).sort((G,J)=>l.customCategorySorting(G.category,J.category))}const g=o();oe(g)}),c(()=>{l.activeSearchItemId=l.activeSearchItem!==-1&&l.currentEmojis[l.activeSearchItem].id}),c(()=>{const{rawSearchText:o}=l;en(()=>{l.searchText=(o||"").trim(),l.activeSearchItem=-1})});function Y(o){if(!l.searchMode||!l.currentEmojis.length)return;const g=b=>{Ee(o),l.activeSearchItem=at(b,l.activeSearchItem,l.currentEmojis)};switch(o.key){case"ArrowDown":return g(!1);case"ArrowUp":return g(!0);case"Enter":if(l.activeSearchItem===-1)l.activeSearchItem=0;else return Ee(o),ae(l.currentEmojis[l.activeSearchItem].id)}}function fe(o){const{target:g}=o,b=g.closest(".nav-button");if(!b)return;const E=parseInt(b.dataset.groupId,10);i.searchElement.value="",l.rawSearchText="",l.searchText="",l.activeSearchItem=-1,l.currentGroupIndex=l.groups.findIndex(C=>C.id===E)}function ie(o){const{target:g,key:b}=o,E=C=>{C&&(Ee(o),C.focus())};switch(b){case"ArrowLeft":return E(g.previousElementSibling);case"ArrowRight":return E(g.nextElementSibling);case"Home":return E(g.parentElement.firstElementChild);case"End":return E(g.parentElement.lastElementChild)}}async function we(o){const g=await l.database.getEmojiByUnicodeOrName(o),b=[...l.currentEmojis,...l.currentFavorites].find(C=>C.id===o),E=b.unicode&&be(b,l.currentSkinTone);return await l.database.incrementFavoriteEmojiCount(o),{emoji:g,skinTone:l.currentSkinTone,...E&&{unicode:E},...b.name&&{name:b.name}}}async function ae(o){const g=we(o);D("emoji-click-sync",g),D("emoji-click",await g)}function v(o){const{target:g}=o;if(!g.classList.contains("emoji"))return;Ee(o);const b=g.id.substring(4);ae(b)}function x(o){l.currentSkinTone=o,l.skinTonePickerExpanded=!1,P("skintone-button"),D("skin-tone-change",{skinTone:o}),l.database.setPreferredSkinTone(o)}function w(o){const{target:{id:g}}=o,b=g&&g.match(/^skintone-(\d)/);if(!b)return;Ee(o);const E=parseInt(b[1],10);x(E)}function B(o){l.skinTonePickerExpanded=!l.skinTonePickerExpanded,l.activeSkinTone=l.currentSkinTone,l.skinTonePickerExpanded&&(Ee(o),Ge(()=>P("skintone-list")))}c(()=>{l.skinTonePickerExpanded?i.skinToneDropdown.addEventListener("transitionend",()=>{l.skinTonePickerExpandedAfterAnimation=!0},{once:!0}):l.skinTonePickerExpandedAfterAnimation=!1});function L(o){if(!l.skinTonePickerExpanded)return;const g=async b=>{Ee(o),l.activeSkinTone=b};switch(o.key){case"ArrowUp":return g(at(!0,l.activeSkinTone,l.skinTones));case"ArrowDown":return g(at(!1,l.activeSkinTone,l.skinTones));case"Home":return g(0);case"End":return g(l.skinTones.length-1);case"Enter":return Ee(o),x(l.activeSkinTone);case"Escape":return Ee(o),l.skinTonePickerExpanded=!1,P("skintone-button")}}function k(o){if(l.skinTonePickerExpanded)switch(o.key){case" ":return Ee(o),x(l.activeSkinTone)}}async function p(o){const{relatedTarget:g}=o;(!g||g.id!=="skintone-list")&&(l.skinTonePickerExpanded=!1)}function h(o){l.rawSearchText=o.target.value}return{$set(o){Re(l,o)},$destroy(){s.abort()}}}const Vr="https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json",Yr="en";var Kr={categoriesLabel:"Categories",emojiUnsupportedMessage:"Your browser does not support color emoji.",favoritesLabel:"Favorites",loadingMessage:"Loading…",networkErrorMessage:"Could not load emoji.",regionLabel:"Emoji picker",searchDescription:"When search results are available, press up or down to select and enter to choose.",searchLabel:"Search",searchResultsLabel:"Search results",skinToneDescription:"When expanded, press up or down to select and enter to choose.",skinToneLabel:"Choose a skin tone (currently {skinTone})",skinTonesLabel:"Skin tones",skinTones:["Default","Light","Medium-Light","Medium","Medium-Dark","Dark"],categories:{custom:"Custom","smileys-emotion":"Smileys and emoticons","people-body":"People and body","animals-nature":"Animals and nature","food-drink":"Food and drink","travel-places":"Travel and places",activities:"Activities",objects:"Objects",symbols:"Symbols",flags:"Flags"}},Jr=':host{--emoji-size:1.375rem;--emoji-padding:0.5rem;--category-emoji-size:var(--emoji-size);--category-emoji-padding:var(--emoji-padding);--indicator-height:3px;--input-border-radius:0.5rem;--input-border-size:1px;--input-font-size:1rem;--input-line-height:1.5;--input-padding:0.25rem;--num-columns:8;--outline-size:2px;--border-size:1px;--border-radius:0;--skintone-border-radius:1rem;--category-font-size:1rem;display:flex;width:min-content;height:400px}:host,:host(.light){color-scheme:light;--background:#fff;--border-color:#e0e0e0;--indicator-color:#385ac1;--input-border-color:#999;--input-font-color:#111;--input-placeholder-color:#999;--outline-color:#999;--category-font-color:#111;--button-active-background:#e6e6e6;--button-hover-background:#d9d9d9}:host(.dark){color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}@media (prefers-color-scheme:dark){:host{color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}}:host([hidden]){display:none}button{margin:0;padding:0;border:0;background:0 0;box-shadow:none;-webkit-tap-highlight-color:transparent}button::-moz-focus-inner{border:0}input{padding:0;margin:0;line-height:1.15;font-family:inherit}input[type=search]{-webkit-appearance:none}:focus{outline:var(--outline-color) solid var(--outline-size);outline-offset:calc(-1*var(--outline-size))}:host([data-js-focus-visible]) :focus:not([data-focus-visible-added]){outline:0}:focus:not(:focus-visible){outline:0}.hide-focus{outline:0}*{box-sizing:border-box}.picker{contain:content;display:flex;flex-direction:column;background:var(--background);border:var(--border-size) solid var(--border-color);border-radius:var(--border-radius);width:100%;height:100%;overflow:hidden;--total-emoji-size:calc(var(--emoji-size) + (2 * var(--emoji-padding)));--total-category-emoji-size:calc(var(--category-emoji-size) + (2 * var(--category-emoji-padding)))}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.hidden{opacity:0;pointer-events:none}.abs-pos{position:absolute;left:0;top:0}.gone{display:none!important}.skintone-button-wrapper,.skintone-list{background:var(--background);z-index:3}.skintone-button-wrapper.expanded{z-index:1}.skintone-list{position:absolute;inset-inline-end:0;top:0;z-index:2;overflow:visible;border-bottom:var(--border-size) solid var(--border-color);border-radius:0 0 var(--skintone-border-radius) var(--skintone-border-radius);will-change:transform;transition:transform .2s ease-in-out;transform-origin:center 0}@media (prefers-reduced-motion:reduce){.skintone-list{transition-duration:.001s}}@supports not (inset-inline-end:0){.skintone-list{right:0}}.skintone-list.no-animate{transition:none}.tabpanel{overflow-y:auto;scrollbar-gutter:stable;-webkit-overflow-scrolling:touch;will-change:transform;min-height:0;flex:1;contain:content}.emoji-menu{display:grid;grid-template-columns:repeat(var(--num-columns),var(--total-emoji-size));justify-content:space-around;align-items:flex-start;width:100%}.emoji-menu.visibility-auto{content-visibility:auto;contain-intrinsic-size:calc(var(--num-columns)*var(--total-emoji-size)) calc(var(--num-rows)*var(--total-emoji-size))}.category{padding:var(--emoji-padding);font-size:var(--category-font-size);color:var(--category-font-color)}.emoji,button.emoji{font-size:var(--emoji-size);display:flex;align-items:center;justify-content:center;border-radius:100%;height:var(--total-emoji-size);width:var(--total-emoji-size);line-height:1;overflow:hidden;font-family:var(--emoji-font-family);cursor:pointer}@media (hover:hover) and (pointer:fine){.emoji:hover,button.emoji:hover{background:var(--button-hover-background)}}.emoji.active,.emoji:active,button.emoji.active,button.emoji:active{background:var(--button-active-background)}.onscreen .custom-emoji::after{content:"";width:var(--emoji-size);height:var(--emoji-size);background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:var(--custom-emoji-background)}.nav,.nav-button{align-items:center}.nav{display:grid;justify-content:space-between;contain:content}.nav-button{display:flex;justify-content:center}.nav-emoji{font-size:var(--category-emoji-size);width:var(--total-category-emoji-size);height:var(--total-category-emoji-size)}.indicator-wrapper{display:flex;border-bottom:1px solid var(--border-color)}.indicator{width:calc(100%/var(--num-groups));height:var(--indicator-height);opacity:var(--indicator-opacity);background-color:var(--indicator-color);will-change:transform,opacity;transition:opacity .1s linear,transform .25s ease-in-out}@media (prefers-reduced-motion:reduce){.indicator{will-change:opacity;transition:opacity .1s linear}}.pad-top,input.search{background:var(--background);width:100%}.pad-top{height:var(--emoji-padding);z-index:3}.search-row{display:flex;align-items:center;position:relative;padding-inline-start:var(--emoji-padding);padding-bottom:var(--emoji-padding)}.search-wrapper{flex:1;min-width:0}input.search{padding:var(--input-padding);border-radius:var(--input-border-radius);border:var(--input-border-size) solid var(--input-border-color);color:var(--input-font-color);font-size:var(--input-font-size);line-height:var(--input-line-height)}input.search::placeholder{color:var(--input-placeholder-color)}.favorites{overflow-y:auto;scrollbar-gutter:stable;display:flex;flex-direction:row;border-top:var(--border-size) solid var(--border-color);contain:content}.message{padding:var(--emoji-padding)}';const rn=["customEmoji","customCategorySorting","database","dataSource","i18n","locale","skinToneEmoji","emojiVersion"],Xr=`:host{--emoji-font-family:${tn}}`;class wt extends HTMLElement{constructor(t){super(),this.attachShadow({mode:"open"});const i=document.createElement("style");i.textContent=Jr+Xr,this.shadowRoot.appendChild(i),this._ctx={locale:Yr,dataSource:Vr,skinToneEmoji:pr,customCategorySorting:mr,customEmoji:null,i18n:Kr,emojiVersion:null,...t};for(const s of rn)s!=="database"&&Object.prototype.hasOwnProperty.call(this,s)&&(this._ctx[s]=this[s],delete this[s]);this._dbFlush()}connectedCallback(){At(this),this._cmp||(this._cmp=Wr(this.shadowRoot,this._ctx))}disconnectedCallback(){At(this),Ye(()=>{if(!this.isConnected&&this._cmp){this._cmp.$destroy(),this._cmp=void 0;const{database:t}=this._ctx;t.close().catch(i=>console.error(i))}})}static get observedAttributes(){return["locale","data-source","skin-tone-emoji","emoji-version"]}attributeChangedCallback(t,i,s){this._set(t.replace(/-([a-z])/g,(m,l)=>l.toUpperCase()),t==="emoji-version"?parseFloat(s):s)}_set(t,i){this._ctx[t]=i,this._cmp&&this._cmp.$set({[t]:i}),["locale","dataSource"].includes(t)&&this._dbFlush()}_dbCreate(){const{locale:t,dataSource:i,database:s}=this._ctx;(!s||s.locale!==t||s.dataSource!==i)&&this._set("database",new sr({locale:t,dataSource:i}))}_dbFlush(){Ye(()=>this._dbCreate())}}const an={};for(const r of rn)an[r]={get(){return r==="database"&&this._dbCreate(),this._ctx[r]},set(t){if(r==="database")throw new Error("database is read-only");this._set(r,t)}};Object.defineProperties(wt.prototype,an);function At(r){r instanceof wt||Object.setPrototypeOf(r,customElements.get(r.tagName.toLowerCase()).prototype)}customElements.get("emoji-picker")||customElements.define("emoji-picker",wt);function Zr(r,t){const i=document.getElementById("app"),s=new Ft,m=new Je,l=r.id||r._id;let c=null,u=[];const P=localStorage.getItem("currentTheme")||"dark";Qr(P),i.innerHTML=`
59
+ --num-skintones: ${It};`}),c(()=>{l.customEmoji&&l.database&&P()}),c(()=>{l.customEmoji&&l.customEmoji.length?l.groups!==gt&&(l.groups=gt):l.groups!==tt&&(l.currentGroupIndex&&l.currentGroupIndex--,l.groups=tt)}),c(()=>{async function o(){l.databaseLoaded&&(l.currentSkinTone=await l.database.getPreferredSkinTone())}o()}),c(()=>{l.skinTones=Array(It).fill().map((o,g)=>Er(l.skinToneEmoji,g))}),c(()=>{l.skinToneButtonText=l.skinTones[l.currentSkinTone]}),c(()=>{l.skinToneButtonLabel=l.i18n.skinToneLabel.replace("{skinTone}",l.i18n.skinTones[l.currentSkinTone])}),c(()=>{async function o(){const{database:g}=l,f=(await Promise.all(gr.map(E=>g.getEmojiByUnicodeOrName(E)))).filter(Boolean);l.defaultFavoriteEmojis=f}l.databaseLoaded&&o()});function P(){const{customEmoji:o,database:g}=l,f=o||st;g.customEmoji!==f&&(g.customEmoji=f)}c(()=>{async function o(){P();const{database:g,defaultFavoriteEmojis:f,numColumns:E}=l,C=await g.getTopFavoriteEmoji(E),G=await _(nn([...C,...f],J=>J.unicode||J.name).slice(0,E));l.currentFavorites=G}l.databaseLoaded&&l.defaultFavoriteEmojis&&o()});function A(o){Lr(o,m,()=>{{const g=getComputedStyle(i.rootElement),f=parseInt(g.getPropertyValue("--num-columns"),10),E=g.getPropertyValue("direction")==="rtl";l.numColumns=f,l.isRtl=E}})}function V(o){Gr(o,m,g=>{for(const{target:f,isIntersecting:E}of g)f.classList.toggle("onscreen",E)})}c(()=>{async function o(){const{searchText:g,currentGroup:f,databaseLoaded:E,customEmoji:C}=l;if(!E)l.currentEmojis=[],l.searchMode=!1;else if(g.length>=dr){const G=await Z(g);l.searchText===g&&(W(G),ue(!0))}else{const{id:G}=f;if(G!==-1||C&&C.length){const J=await O(G);l.currentGroup.id===G&&(W(J),ue(!1))}}}o()});const $=()=>{Ge(()=>Sr(i.tabpanelElement))};c(()=>{const{currentEmojis:o,emojiVersion:g}=l,f=o.filter(E=>E.unicode).filter(E=>Lt(E)&&!mt.has(E.unicode));if(!g&&f.length)W(o),Ge(()=>M(f));else{const E=g?o:o.filter(N);W(E),$()}});function M(o){$r(o,i.baselineEmoji,D)?$():l.currentEmojis=[...l.currentEmojis]}function N(o){return!o.unicode||!Lt(o)||mt.get(o.unicode)}async function H(o){const g=l.emojiVersion||await rt();return o.filter(({version:f})=>!f||f<=g)}async function _(o){return Br(o,l.emojiVersion||await rt())}async function O(o){const g=o===-1?l.customEmoji:await l.database.getEmojiByGroup(o);return _(await H(g))}async function Z(o){return _(await H(await l.database.getEmojiBySearchQuery(o)))}c(()=>{}),c(()=>{function o(){const{searchMode:f,currentEmojis:E}=l;if(f)return[{category:"",emojis:E}];const C=new Map;for(const G of E){const J=G.category||"";let ee=C.get(J);ee||(ee=[],C.set(J,ee)),ee.push(G)}return[...C.entries()].map(([G,J])=>({category:G,emojis:J})).sort((G,J)=>l.customCategorySorting(G.category,J.category))}const g=o();oe(g)}),c(()=>{l.activeSearchItemId=l.activeSearchItem!==-1&&l.currentEmojis[l.activeSearchItem].id}),c(()=>{const{rawSearchText:o}=l;en(()=>{l.searchText=(o||"").trim(),l.activeSearchItem=-1})});function Y(o){if(!l.searchMode||!l.currentEmojis.length)return;const g=f=>{Ee(o),l.activeSearchItem=at(f,l.activeSearchItem,l.currentEmojis)};switch(o.key){case"ArrowDown":return g(!1);case"ArrowUp":return g(!0);case"Enter":if(l.activeSearchItem===-1)l.activeSearchItem=0;else return Ee(o),ae(l.currentEmojis[l.activeSearchItem].id)}}function xe(o){const{target:g}=o,f=g.closest(".nav-button");if(!f)return;const E=parseInt(f.dataset.groupId,10);i.searchElement.value="",l.rawSearchText="",l.searchText="",l.activeSearchItem=-1,l.currentGroupIndex=l.groups.findIndex(C=>C.id===E)}function ie(o){const{target:g,key:f}=o,E=C=>{C&&(Ee(o),C.focus())};switch(f){case"ArrowLeft":return E(g.previousElementSibling);case"ArrowRight":return E(g.nextElementSibling);case"Home":return E(g.parentElement.firstElementChild);case"End":return E(g.parentElement.lastElementChild)}}async function we(o){const g=await l.database.getEmojiByUnicodeOrName(o),f=[...l.currentEmojis,...l.currentFavorites].find(C=>C.id===o),E=f.unicode&&fe(f,l.currentSkinTone);return await l.database.incrementFavoriteEmojiCount(o),{emoji:g,skinTone:l.currentSkinTone,...E&&{unicode:E},...f.name&&{name:f.name}}}async function ae(o){const g=we(o);z("emoji-click-sync",g),z("emoji-click",await g)}function v(o){const{target:g}=o;if(!g.classList.contains("emoji"))return;Ee(o);const f=g.id.substring(4);ae(f)}function b(o){l.currentSkinTone=o,l.skinTonePickerExpanded=!1,F("skintone-button"),z("skin-tone-change",{skinTone:o}),l.database.setPreferredSkinTone(o)}function w(o){const{target:{id:g}}=o,f=g&&g.match(/^skintone-(\d)/);if(!f)return;Ee(o);const E=parseInt(f[1],10);b(E)}function B(o){l.skinTonePickerExpanded=!l.skinTonePickerExpanded,l.activeSkinTone=l.currentSkinTone,l.skinTonePickerExpanded&&(Ee(o),Ge(()=>F("skintone-list")))}c(()=>{l.skinTonePickerExpanded?i.skinToneDropdown.addEventListener("transitionend",()=>{l.skinTonePickerExpandedAfterAnimation=!0},{once:!0}):l.skinTonePickerExpandedAfterAnimation=!1});function L(o){if(!l.skinTonePickerExpanded)return;const g=async f=>{Ee(o),l.activeSkinTone=f};switch(o.key){case"ArrowUp":return g(at(!0,l.activeSkinTone,l.skinTones));case"ArrowDown":return g(at(!1,l.activeSkinTone,l.skinTones));case"Home":return g(0);case"End":return g(l.skinTones.length-1);case"Enter":return Ee(o),b(l.activeSkinTone);case"Escape":return Ee(o),l.skinTonePickerExpanded=!1,F("skintone-button")}}function k(o){if(l.skinTonePickerExpanded)switch(o.key){case" ":return Ee(o),b(l.activeSkinTone)}}async function p(o){const{relatedTarget:g}=o;(!g||g.id!=="skintone-list")&&(l.skinTonePickerExpanded=!1)}function h(o){l.rawSearchText=o.target.value}return{$set(o){Re(l,o)},$destroy(){s.abort()}}}const Vr="https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json",Yr="en";var Kr={categoriesLabel:"Categories",emojiUnsupportedMessage:"Your browser does not support color emoji.",favoritesLabel:"Favorites",loadingMessage:"Loading…",networkErrorMessage:"Could not load emoji.",regionLabel:"Emoji picker",searchDescription:"When search results are available, press up or down to select and enter to choose.",searchLabel:"Search",searchResultsLabel:"Search results",skinToneDescription:"When expanded, press up or down to select and enter to choose.",skinToneLabel:"Choose a skin tone (currently {skinTone})",skinTonesLabel:"Skin tones",skinTones:["Default","Light","Medium-Light","Medium","Medium-Dark","Dark"],categories:{custom:"Custom","smileys-emotion":"Smileys and emoticons","people-body":"People and body","animals-nature":"Animals and nature","food-drink":"Food and drink","travel-places":"Travel and places",activities:"Activities",objects:"Objects",symbols:"Symbols",flags:"Flags"}},Jr=':host{--emoji-size:1.375rem;--emoji-padding:0.5rem;--category-emoji-size:var(--emoji-size);--category-emoji-padding:var(--emoji-padding);--indicator-height:3px;--input-border-radius:0.5rem;--input-border-size:1px;--input-font-size:1rem;--input-line-height:1.5;--input-padding:0.25rem;--num-columns:8;--outline-size:2px;--border-size:1px;--border-radius:0;--skintone-border-radius:1rem;--category-font-size:1rem;display:flex;width:min-content;height:400px}:host,:host(.light){color-scheme:light;--background:#fff;--border-color:#e0e0e0;--indicator-color:#385ac1;--input-border-color:#999;--input-font-color:#111;--input-placeholder-color:#999;--outline-color:#999;--category-font-color:#111;--button-active-background:#e6e6e6;--button-hover-background:#d9d9d9}:host(.dark){color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}@media (prefers-color-scheme:dark){:host{color-scheme:dark;--background:#222;--border-color:#444;--indicator-color:#5373ec;--input-border-color:#ccc;--input-font-color:#efefef;--input-placeholder-color:#ccc;--outline-color:#fff;--category-font-color:#efefef;--button-active-background:#555555;--button-hover-background:#484848}}:host([hidden]){display:none}button{margin:0;padding:0;border:0;background:0 0;box-shadow:none;-webkit-tap-highlight-color:transparent}button::-moz-focus-inner{border:0}input{padding:0;margin:0;line-height:1.15;font-family:inherit}input[type=search]{-webkit-appearance:none}:focus{outline:var(--outline-color) solid var(--outline-size);outline-offset:calc(-1*var(--outline-size))}:host([data-js-focus-visible]) :focus:not([data-focus-visible-added]){outline:0}:focus:not(:focus-visible){outline:0}.hide-focus{outline:0}*{box-sizing:border-box}.picker{contain:content;display:flex;flex-direction:column;background:var(--background);border:var(--border-size) solid var(--border-color);border-radius:var(--border-radius);width:100%;height:100%;overflow:hidden;--total-emoji-size:calc(var(--emoji-size) + (2 * var(--emoji-padding)));--total-category-emoji-size:calc(var(--category-emoji-size) + (2 * var(--category-emoji-padding)))}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.hidden{opacity:0;pointer-events:none}.abs-pos{position:absolute;left:0;top:0}.gone{display:none!important}.skintone-button-wrapper,.skintone-list{background:var(--background);z-index:3}.skintone-button-wrapper.expanded{z-index:1}.skintone-list{position:absolute;inset-inline-end:0;top:0;z-index:2;overflow:visible;border-bottom:var(--border-size) solid var(--border-color);border-radius:0 0 var(--skintone-border-radius) var(--skintone-border-radius);will-change:transform;transition:transform .2s ease-in-out;transform-origin:center 0}@media (prefers-reduced-motion:reduce){.skintone-list{transition-duration:.001s}}@supports not (inset-inline-end:0){.skintone-list{right:0}}.skintone-list.no-animate{transition:none}.tabpanel{overflow-y:auto;scrollbar-gutter:stable;-webkit-overflow-scrolling:touch;will-change:transform;min-height:0;flex:1;contain:content}.emoji-menu{display:grid;grid-template-columns:repeat(var(--num-columns),var(--total-emoji-size));justify-content:space-around;align-items:flex-start;width:100%}.emoji-menu.visibility-auto{content-visibility:auto;contain-intrinsic-size:calc(var(--num-columns)*var(--total-emoji-size)) calc(var(--num-rows)*var(--total-emoji-size))}.category{padding:var(--emoji-padding);font-size:var(--category-font-size);color:var(--category-font-color)}.emoji,button.emoji{font-size:var(--emoji-size);display:flex;align-items:center;justify-content:center;border-radius:100%;height:var(--total-emoji-size);width:var(--total-emoji-size);line-height:1;overflow:hidden;font-family:var(--emoji-font-family);cursor:pointer}@media (hover:hover) and (pointer:fine){.emoji:hover,button.emoji:hover{background:var(--button-hover-background)}}.emoji.active,.emoji:active,button.emoji.active,button.emoji:active{background:var(--button-active-background)}.onscreen .custom-emoji::after{content:"";width:var(--emoji-size);height:var(--emoji-size);background-repeat:no-repeat;background-position:center center;background-size:contain;background-image:var(--custom-emoji-background)}.nav,.nav-button{align-items:center}.nav{display:grid;justify-content:space-between;contain:content}.nav-button{display:flex;justify-content:center}.nav-emoji{font-size:var(--category-emoji-size);width:var(--total-category-emoji-size);height:var(--total-category-emoji-size)}.indicator-wrapper{display:flex;border-bottom:1px solid var(--border-color)}.indicator{width:calc(100%/var(--num-groups));height:var(--indicator-height);opacity:var(--indicator-opacity);background-color:var(--indicator-color);will-change:transform,opacity;transition:opacity .1s linear,transform .25s ease-in-out}@media (prefers-reduced-motion:reduce){.indicator{will-change:opacity;transition:opacity .1s linear}}.pad-top,input.search{background:var(--background);width:100%}.pad-top{height:var(--emoji-padding);z-index:3}.search-row{display:flex;align-items:center;position:relative;padding-inline-start:var(--emoji-padding);padding-bottom:var(--emoji-padding)}.search-wrapper{flex:1;min-width:0}input.search{padding:var(--input-padding);border-radius:var(--input-border-radius);border:var(--input-border-size) solid var(--input-border-color);color:var(--input-font-color);font-size:var(--input-font-size);line-height:var(--input-line-height)}input.search::placeholder{color:var(--input-placeholder-color)}.favorites{overflow-y:auto;scrollbar-gutter:stable;display:flex;flex-direction:row;border-top:var(--border-size) solid var(--border-color);contain:content}.message{padding:var(--emoji-padding)}';const rn=["customEmoji","customCategorySorting","database","dataSource","i18n","locale","skinToneEmoji","emojiVersion"],Xr=`:host{--emoji-font-family:${tn}}`;class wt extends HTMLElement{constructor(t){super(),this.attachShadow({mode:"open"});const i=document.createElement("style");i.textContent=Jr+Xr,this.shadowRoot.appendChild(i),this._ctx={locale:Yr,dataSource:Vr,skinToneEmoji:pr,customCategorySorting:mr,customEmoji:null,i18n:Kr,emojiVersion:null,...t};for(const s of rn)s!=="database"&&Object.prototype.hasOwnProperty.call(this,s)&&(this._ctx[s]=this[s],delete this[s]);this._dbFlush()}connectedCallback(){Dt(this),this._cmp||(this._cmp=Wr(this.shadowRoot,this._ctx))}disconnectedCallback(){Dt(this),Ye(()=>{if(!this.isConnected&&this._cmp){this._cmp.$destroy(),this._cmp=void 0;const{database:t}=this._ctx;t.close().catch(i=>console.error(i))}})}static get observedAttributes(){return["locale","data-source","skin-tone-emoji","emoji-version"]}attributeChangedCallback(t,i,s){this._set(t.replace(/-([a-z])/g,(m,l)=>l.toUpperCase()),t==="emoji-version"?parseFloat(s):s)}_set(t,i){this._ctx[t]=i,this._cmp&&this._cmp.$set({[t]:i}),["locale","dataSource"].includes(t)&&this._dbFlush()}_dbCreate(){const{locale:t,dataSource:i,database:s}=this._ctx;(!s||s.locale!==t||s.dataSource!==i)&&this._set("database",new sr({locale:t,dataSource:i}))}_dbFlush(){Ye(()=>this._dbCreate())}}const an={};for(const r of rn)an[r]={get(){return r==="database"&&this._dbCreate(),this._ctx[r]},set(t){if(r==="database")throw new Error("database is read-only");this._set(r,t)}};Object.defineProperties(wt.prototype,an);function Dt(r){r instanceof wt||Object.setPrototypeOf(r,customElements.get(r.tagName.toLowerCase()).prototype)}customElements.get("emoji-picker")||customElements.define("emoji-picker",wt);function Zr(r,t){const i=document.getElementById("app"),s=new Ut,m=new Je,l=r.id||r._id;let c=null,u=[];const F=localStorage.getItem("currentTheme")||"dark";Qr(F),i.innerHTML=`
60
60
  <div class="dashboard">
61
61
  <aside class="sidebar">
62
62
  <div class="sidebar-header">
@@ -131,7 +131,7 @@
131
131
  <div id="contentArea"></div>
132
132
  </main>
133
133
  </div>
134
- `,document.querySelectorAll(".nav-item").forEach(v=>{v.addEventListener("click",()=>{document.querySelectorAll(".nav-item").forEach(w=>w.classList.remove("active")),v.classList.add("active");const x=v.dataset.view;ae(x)})}),document.getElementById("logoutBtn").addEventListener("click",()=>{m.logout()}),document.getElementById("settingsBtn").addEventListener("click",()=>{ae("settings")}),document.getElementById("helpBtn").addEventListener("click",()=>{ae("help")});async function A(v){u=(await s.getGroups()).groups,v.innerHTML=`
134
+ `,document.querySelectorAll(".nav-item").forEach(v=>{v.addEventListener("click",()=>{document.querySelectorAll(".nav-item").forEach(w=>w.classList.remove("active")),v.classList.add("active");const b=v.dataset.view;ae(b)})}),document.getElementById("logoutBtn").addEventListener("click",()=>{m.logout()}),document.getElementById("settingsBtn").addEventListener("click",()=>{ae("settings")}),document.getElementById("helpBtn").addEventListener("click",()=>{ae("help")});async function D(v){u=(await s.getGroups()).groups,v.innerHTML=`
135
135
  <div class="view-header">
136
136
  <h2>群组管理</h2>
137
137
  <button class="btn-primary" id="createGroupBtn">创建群组</button>
@@ -184,13 +184,13 @@
184
184
  <button class="btn-select" data-id="${B._id}">选择</button>
185
185
  <button class="btn-secondary" data-id="${B._id}" data-action="manage">管理成员</button>
186
186
  </div>
187
- `,w.appendChild(L)}),document.querySelectorAll(".btn-select").forEach(B=>{B.addEventListener("click",()=>{c=u.find(L=>L._id===B.dataset.id),t.joinGroup(c._id),alert(`已加入群组: ${c.name}`)})}),document.querySelectorAll('[data-action="manage"]').forEach(B=>{B.addEventListener("click",async()=>{const L=B.dataset.id;await R(L)})}),document.getElementById("createGroupBtn").addEventListener("click",async()=>{document.getElementById("createGroupModal").classList.remove("hidden"),await D()}),document.getElementById("closeModal").addEventListener("click",()=>{document.getElementById("createGroupModal").classList.add("hidden")}),document.getElementById("closeMembersModal").addEventListener("click",()=>{document.getElementById("manageMembersModal").classList.add("hidden")}),document.getElementById("createGroupForm").addEventListener("submit",async B=>{B.preventDefault();const L=new FormData(B.target),k=Array.from(document.querySelectorAll("#usersList input:checked")).map(p=>p.value);try{const p=await s.createGroup(L.get("name"),L.get("description"),k);alert("群组创建成功!"),await A(v),document.getElementById("createGroupModal").classList.add("hidden")}catch(p){console.error("创建群组错误:",p),alert("创建失败: "+p.message)}})}async function D(){try{const v=await s.getAllUsers(),x=document.getElementById("usersList");x.innerHTML=v.users.map(w=>`
187
+ `,w.appendChild(L)}),document.querySelectorAll(".btn-select").forEach(B=>{B.addEventListener("click",()=>{c=u.find(L=>L._id===B.dataset.id),t.joinGroup(c._id),alert(`已加入群组: ${c.name}`)})}),document.querySelectorAll('[data-action="manage"]').forEach(B=>{B.addEventListener("click",async()=>{const L=B.dataset.id;await R(L)})}),document.getElementById("createGroupBtn").addEventListener("click",async()=>{document.getElementById("createGroupModal").classList.remove("hidden"),await z()}),document.getElementById("closeModal").addEventListener("click",()=>{document.getElementById("createGroupModal").classList.add("hidden")}),document.getElementById("closeMembersModal").addEventListener("click",()=>{document.getElementById("manageMembersModal").classList.add("hidden")}),document.getElementById("createGroupForm").addEventListener("submit",async B=>{B.preventDefault();const L=new FormData(B.target),k=Array.from(document.querySelectorAll("#usersList input:checked")).map(p=>p.value);try{const p=await s.createGroup(L.get("name"),L.get("description"),k);alert("群组创建成功!"),await D(v),document.getElementById("createGroupModal").classList.add("hidden")}catch(p){console.error("创建群组错误:",p),alert("创建失败: "+p.message)}})}async function z(){try{const v=await s.getAllUsers(),b=document.getElementById("usersList");b.innerHTML=v.users.map(w=>`
188
188
  <label style="display: flex; align-items: center; gap: 10px; padding: 8px; cursor: pointer;">
189
189
  <input type="checkbox" value="${w._id}">
190
190
  <div class="avatar" style="width: 30px; height: 30px; font-size: 14px;">${w.username[0].toUpperCase()}</div>
191
191
  <span>${w.username} (${w.role==="admin"?"管理员":"用户"})</span>
192
192
  </label>
193
- `).join("")}catch(v){console.error("加载用户失败:",v),document.getElementById("usersList").innerHTML='<p style="color: var(--danger);">加载失败</p>'}}async function R(v){try{const x=await s.getGroup(v),w=await s.getAllUsers(),B=x.group,L=document.getElementById("currentMembers");L.innerHTML=`
193
+ `).join("")}catch(v){console.error("加载用户失败:",v),document.getElementById("usersList").innerHTML='<p style="color: var(--danger);">加载失败</p>'}}async function R(v){try{const b=await s.getGroup(v),w=await s.getAllUsers(),B=b.group,L=document.getElementById("currentMembers");L.innerHTML=`
194
194
  <h4>当前成员 (${B.members.length})</h4>
195
195
  <div style="max-height: 200px; overflow-y: auto;">
196
196
  ${B.members.map(o=>`
@@ -211,7 +211,7 @@
211
211
  </div>
212
212
  <button class="btn-primary btn-sm" onclick="addMember('${v}', '${o._id}')">添加</button>
213
213
  </div>
214
- `).join(""),document.getElementById("manageMembersModal").classList.remove("hidden")}catch(x){console.error("加载成员失败:",x),alert("加载失败: "+x.message)}}window.addMember=async(v,x)=>{try{await s.addMember(v,x),alert("成员添加成功!"),await R(v)}catch(w){alert("添加失败: "+w.message)}},window.removeMember=async(v,x)=>{if(confirm("确定要移除该成员吗?"))try{await s.removeMember(v,x),alert("成员移除成功!"),await R(v)}catch(w){alert("移除失败: "+w.message)}};async function F(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}const x=await s.getTasks(c._id);v.innerHTML=`
214
+ `).join(""),document.getElementById("manageMembersModal").classList.remove("hidden")}catch(b){console.error("加载成员失败:",b),alert("加载失败: "+b.message)}}window.addMember=async(v,b)=>{try{await s.addMember(v,b),alert("成员添加成功!"),await R(v)}catch(w){alert("添加失败: "+w.message)}},window.removeMember=async(v,b)=>{if(confirm("确定要移除该成员吗?"))try{await s.removeMember(v,b),alert("成员移除成功!"),await R(v)}catch(w){alert("移除失败: "+w.message)}};async function U(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}const b=await s.getTasks(c._id);v.innerHTML=`
215
215
  <div class="view-header">
216
216
  <h2>任务管理 - ${c.name}</h2>
217
217
  <button class="btn-primary" id="createTaskBtn">创建任务</button>
@@ -253,7 +253,7 @@
253
253
  </div>
254
254
  </div>
255
255
  </div>
256
- `;const w=document.getElementById("tasksList");x.tasks.length===0?w.innerHTML='<div class="empty-state">暂无任务</div>':(x.tasks.forEach(B=>{const L=document.createElement("div");L.className=`task-card status-${B.status}`,L.innerHTML=`
256
+ `;const w=document.getElementById("tasksList");b.tasks.length===0?w.innerHTML='<div class="empty-state">暂无任务</div>':(b.tasks.forEach(B=>{const L=document.createElement("div");L.className=`task-card status-${B.status}`,L.innerHTML=`
257
257
  <div style="display: flex; justify-content: space-between; align-items: start;">
258
258
  <div style="flex: 1;">
259
259
  <h3>${B.title}</h3>
@@ -267,7 +267,7 @@
267
267
  <button class="btn-primary btn-sm" data-id="${B._id}" data-action="view-task" title="查看详细">📋 查看详细</button>
268
268
  <button class="btn-danger btn-sm" data-id="${B._id}" data-action="delete-task" title="删除任务" style="min-width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;">🗑️ 删除</button>
269
269
  </div>
270
- `,w.appendChild(L)}),document.querySelectorAll('[data-action="delete-task"]').forEach(B=>{B.addEventListener("click",async L=>{L.stopPropagation();const k=B.dataset.id;if(confirm("确定要删除这个任务吗?删除后无法恢复!"))try{await s.deleteTask(k),alert("任务删除成功!"),await F(v)}catch(p){console.error("删除任务错误:",p),alert("删除失败: "+(p.message||"未知错误"))}})}),document.querySelectorAll('[data-action="view-task"]').forEach(B=>{B.addEventListener("click",async L=>{var h;L.stopPropagation();const k=B.dataset.id,p=x.tasks.find(o=>o._id===k);if(p){const o=document.getElementById("taskDetailContent"),g=b=>({pending:"#6366f1","in-progress":"#f59e0b",completed:"#10b981",cancelled:"#ef4444"})[b]||"#6366f1";o.innerHTML=`
270
+ `,w.appendChild(L)}),document.querySelectorAll('[data-action="delete-task"]').forEach(B=>{B.addEventListener("click",async L=>{L.stopPropagation();const k=B.dataset.id;if(confirm("确定要删除这个任务吗?删除后无法恢复!"))try{await s.deleteTask(k),alert("任务删除成功!"),await U(v)}catch(p){console.error("删除任务错误:",p),alert("删除失败: "+(p.message||"未知错误"))}})}),document.querySelectorAll('[data-action="view-task"]').forEach(B=>{B.addEventListener("click",async L=>{var h;L.stopPropagation();const k=B.dataset.id,p=b.tasks.find(o=>o._id===k);if(p){const o=document.getElementById("taskDetailContent"),g=f=>({pending:"#6366f1","in-progress":"#f59e0b",completed:"#10b981",cancelled:"#ef4444"})[f]||"#6366f1";o.innerHTML=`
271
271
  <div class="task-detail" style="background: linear-gradient(135deg, rgba(99, 102, 241, 0.05) 0%, rgba(168, 85, 247, 0.05) 100%); border-radius: 12px; padding: 16px;">
272
272
 
273
273
  <!-- 任务标题 -->
@@ -324,11 +324,11 @@
324
324
  ${p.assignedTo&&p.assignedTo.length>0?`<span style="background: var(--primary); color: white; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600;">${p.assignedTo.length} 人</span>`:""}
325
325
  </div>
326
326
  <div style="display: flex; flex-wrap: wrap; gap: 8px;">
327
- ${p.assignedTo&&p.assignedTo.length>0?p.assignedTo.map(b=>{var G,J;const E=p.completedBy&&p.completedBy.some(ee=>ee.user&&ee.user._id===b._id),C=E?p.completedBy.find(ee=>ee.user&&ee.user._id===b._id):null;return`
327
+ ${p.assignedTo&&p.assignedTo.length>0?p.assignedTo.map(f=>{var G,J;const E=p.completedBy&&p.completedBy.some(ee=>ee.user&&ee.user._id===f._id),C=E?p.completedBy.find(ee=>ee.user&&ee.user._id===f._id):null;return`
328
328
  <div style="display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: linear-gradient(135deg, ${E?"rgba(16, 185, 129, 0.1)":"rgba(99, 102, 241, 0.1)"} 0%, ${E?"rgba(5, 150, 105, 0.1)":"rgba(168, 85, 247, 0.1)"} 100%); border-radius: 8px; border: 1px solid ${E?"rgba(16, 185, 129, 0.3)":"rgba(99, 102, 241, 0.2)"}; transition: all 0.3s ease; position: relative;">
329
- <div class="avatar" style="width: 30px; height: 30px; font-size: 14px; background: linear-gradient(135deg, ${E?"#10b981 0%, #059669":"#6366f1 0%, #a855f7"} 100%); box-shadow: 0 2px 6px ${E?"rgba(16, 185, 129, 0.3)":"rgba(99, 102, 241, 0.3)"};">${((J=(G=b.username)==null?void 0:G[0])==null?void 0:J.toUpperCase())||"?"}</div>
329
+ <div class="avatar" style="width: 30px; height: 30px; font-size: 14px; background: linear-gradient(135deg, ${E?"#10b981 0%, #059669":"#6366f1 0%, #a855f7"} 100%); box-shadow: 0 2px 6px ${E?"rgba(16, 185, 129, 0.3)":"rgba(99, 102, 241, 0.3)"};">${((J=(G=f.username)==null?void 0:G[0])==null?void 0:J.toUpperCase())||"?"}</div>
330
330
  <div style="display: flex; flex-direction: column; gap: 1px;">
331
- <span style="font-weight: 600; font-size: 13px; color: var(--text-primary);">${b.username||"未知用户"}</span>
331
+ <span style="font-weight: 600; font-size: 13px; color: var(--text-primary);">${f.username||"未知用户"}</span>
332
332
  ${E?`<span style="font-size: 10px; color: #10b981; font-weight: 500;">✓ ${C&&C.completedAt?new Date(C.completedAt).toLocaleString("zh-CN",{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"}):"已完成"}</span>`:'<span style="font-size: 10px; color: var(--text-tertiary);">未完成</span>'}
333
333
  </div>
334
334
  ${E?'<span style="position: absolute; top: -4px; right: -4px; background: #10b981; color: white; width: 16px; height: 16px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">✓</span>':""}
@@ -422,11 +422,11 @@
422
422
 
423
423
  <!-- 投票选项 -->
424
424
  <div style="display: flex; flex-direction: column; gap: 8px;">
425
- ${((h=p.poll.options)==null?void 0:h.map(b=>{const E=p.poll.totalVotes>0?Math.round((b.votes||0)/p.poll.totalVotes*100):0,C=b.voters||[];return`
425
+ ${((h=p.poll.options)==null?void 0:h.map(f=>{const E=p.poll.totalVotes>0?Math.round((f.votes||0)/p.poll.totalVotes*100):0,C=f.voters||[];return`
426
426
  <div style="background: var(--bg-tertiary); border-radius: 8px; padding: 10px; border: 1px solid var(--border);">
427
427
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
428
- <span style="font-weight: 600; font-size: 13px; color: var(--text-primary);">${b.text}</span>
429
- <span style="font-weight: 700; font-size: 13px; color: var(--primary);">${b.votes||0} 票 (${E}%)</span>
428
+ <span style="font-weight: 600; font-size: 13px; color: var(--text-primary);">${f.text}</span>
429
+ <span style="font-weight: 700; font-size: 13px; color: var(--primary);">${f.votes||0} 票 (${E}%)</span>
430
430
  </div>
431
431
  <div style="height: 6px; background: var(--bg-secondary); border-radius: 3px; overflow: hidden; margin-bottom: 8px;">
432
432
  <div style="height: 100%; background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%); width: ${E}%; transition: width 0.3s;"></div>
@@ -458,7 +458,7 @@
458
458
  <span>未投票成员 (${p.poll.unvotedMembers.length}人):</span>
459
459
  </div>
460
460
  <div style="display: flex; flex-wrap: wrap; gap: 8px;">
461
- ${p.poll.unvotedMembers.map(b=>{const E=typeof b=="string"?b:b.username;return`
461
+ ${p.poll.unvotedMembers.map(f=>{const E=typeof f=="string"?f:f.username;return`
462
462
  <span style="display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; background: var(--bg-tertiary); border: 2px solid rgba(239, 68, 68, 0.3); border-radius: 12px; font-size: 12px;">
463
463
  <span style="width: 22px; height: 22px; border-radius: 50%; background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); display: flex; align-items: center; justify-content: center; color: white; font-size: 11px; font-weight: 700;">${E?E[0].toUpperCase():"?"}</span>
464
464
  <span style="font-weight: 600; color: var(--text-primary);">${E||"未知用户"}</span>
@@ -477,7 +477,7 @@
477
477
  `:""}
478
478
 
479
479
  </div>
480
- `,document.getElementById("taskDetailModal").classList.remove("hidden")}})})),document.getElementById("createTaskBtn").addEventListener("click",()=>{document.getElementById("createTaskModal").classList.remove("hidden")}),document.getElementById("closeTaskModal").addEventListener("click",()=>{document.getElementById("createTaskModal").classList.add("hidden")}),document.getElementById("closeTaskDetailModal").addEventListener("click",()=>{document.getElementById("taskDetailModal").classList.add("hidden")}),document.getElementById("createTaskForm").addEventListener("submit",async B=>{B.preventDefault();const L=new FormData(B.target);try{const p=(await s.getGroup(c._id)).group.members.map(h=>h._id);await s.createTask({title:L.get("title"),description:L.get("description"),groupId:c._id,assignedTo:p,deadline:L.get("deadline")||null}),alert("任务创建成功!已分配给所有群组成员"),await F(v),document.getElementById("createTaskModal").classList.add("hidden")}catch(k){console.error("创建任务错误:",k),alert("创建失败: "+k.message)}})}async function W(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}const x=await s.getDocuments(c._id),B=(await s.getGroup(c._id)).group;v.innerHTML=`
480
+ `,document.getElementById("taskDetailModal").classList.remove("hidden")}})})),document.getElementById("createTaskBtn").addEventListener("click",()=>{document.getElementById("createTaskModal").classList.remove("hidden")}),document.getElementById("closeTaskModal").addEventListener("click",()=>{document.getElementById("createTaskModal").classList.add("hidden")}),document.getElementById("closeTaskDetailModal").addEventListener("click",()=>{document.getElementById("taskDetailModal").classList.add("hidden")}),document.getElementById("createTaskForm").addEventListener("submit",async B=>{B.preventDefault();const L=new FormData(B.target);try{const p=(await s.getGroup(c._id)).group.members.map(h=>h._id);await s.createTask({title:L.get("title"),description:L.get("description"),groupId:c._id,assignedTo:p,deadline:L.get("deadline")||null}),alert("任务创建成功!已分配给所有群组成员"),await U(v),document.getElementById("createTaskModal").classList.add("hidden")}catch(k){console.error("创建任务错误:",k),alert("创建失败: "+k.message)}})}async function W(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}const b=await s.getDocuments(c._id),B=(await s.getGroup(c._id)).group;v.innerHTML=`
481
481
  <div class="view-header">
482
482
  <h2>📄 共享文档 - ${c.name}</h2>
483
483
  <button class="btn-primary" id="createDocBtn">➕ 创建文档</button>
@@ -535,7 +535,7 @@
535
535
  </div>
536
536
  </div>
537
537
  </div>
538
- `;const L=document.getElementById("docsList");x.documents.length===0?L.innerHTML='<div class="empty-state">暂无共享文档</div>':(x.documents.forEach(p=>{var g;const h=document.createElement("div");h.className="document-card";const o=((g=p.editableMembers)==null?void 0:g.length)||0;h.innerHTML=`
538
+ `;const L=document.getElementById("docsList");b.documents.length===0?L.innerHTML='<div class="empty-state">暂无共享文档</div>':(b.documents.forEach(p=>{var g;const h=document.createElement("div");h.className="document-card";const o=((g=p.editableMembers)==null?void 0:g.length)||0;h.innerHTML=`
539
539
  <div style="display: flex; justify-content: space-between; align-items: start;">
540
540
  <div style="flex: 1;">
541
541
  <h3>📄 ${p.title}</h3>
@@ -551,19 +551,19 @@
551
551
  <button class="btn-danger btn-sm" data-id="${p._id}" data-action="delete-doc" title="删除文档" style="padding: 8px 16px;">🗑️ 删除</button>
552
552
  </div>
553
553
  </div>
554
- `,L.appendChild(h)}),document.querySelectorAll('[data-action="edit-doc"]').forEach(p=>{p.addEventListener("click",()=>{ue(v,p.dataset.id)})}),document.querySelectorAll('[data-action="manage-permission"]').forEach(p=>{p.addEventListener("click",async()=>{const h=p.dataset.id,o=x.documents.find(g=>g._id===h);k(o,B)})}),document.querySelectorAll('[data-action="delete-doc"]').forEach(p=>{p.addEventListener("click",async h=>{h.stopPropagation();const o=p.dataset.id;if(confirm("确定要删除这个文档吗?删除后无法恢复!"))try{await s.deleteDocument(o),alert("文档删除成功!"),await W(v)}catch(g){console.error("删除文档错误:",g),alert("删除失败: "+(g.message||"未知错误"))}})})),document.getElementById("createDocBtn").addEventListener("click",()=>{document.getElementById("createDocModal").classList.remove("hidden")}),document.getElementById("closeDocModal").addEventListener("click",()=>{document.getElementById("createDocModal").classList.add("hidden")}),document.getElementById("closeDocModalBtn").addEventListener("click",()=>{document.getElementById("createDocModal").classList.add("hidden")});function k(p,h){const o=document.getElementById("editPermissionModal"),g=document.getElementById("permissionContent");g.innerHTML=`
554
+ `,L.appendChild(h)}),document.querySelectorAll('[data-action="edit-doc"]').forEach(p=>{p.addEventListener("click",()=>{ue(v,p.dataset.id)})}),document.querySelectorAll('[data-action="manage-permission"]').forEach(p=>{p.addEventListener("click",async()=>{const h=p.dataset.id,o=b.documents.find(g=>g._id===h);k(o,B)})}),document.querySelectorAll('[data-action="delete-doc"]').forEach(p=>{p.addEventListener("click",async h=>{h.stopPropagation();const o=p.dataset.id;if(confirm("确定要删除这个文档吗?删除后无法恢复!"))try{await s.deleteDocument(o),alert("文档删除成功!"),await W(v)}catch(g){console.error("删除文档错误:",g),alert("删除失败: "+(g.message||"未知错误"))}})})),document.getElementById("createDocBtn").addEventListener("click",()=>{document.getElementById("createDocModal").classList.remove("hidden")}),document.getElementById("closeDocModal").addEventListener("click",()=>{document.getElementById("createDocModal").classList.add("hidden")}),document.getElementById("closeDocModalBtn").addEventListener("click",()=>{document.getElementById("createDocModal").classList.add("hidden")});function k(p,h){const o=document.getElementById("editPermissionModal"),g=document.getElementById("permissionContent");g.innerHTML=`
555
555
  <div style="margin-bottom: 16px;">
556
556
  <h4 style="margin: 0 0 8px 0;">📄 ${p.title}</h4>
557
557
  <p style="font-size: 13px; color: var(--text-secondary); margin: 0;">管理哪些成员可以编辑此文档</p>
558
558
  </div>
559
559
  <form id="updatePermissionForm">
560
560
  <div style="max-height: 300px; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 10px;">
561
- ${h.members.map(b=>{var G;const E=((G=p.editableMembers)==null?void 0:G.includes(b._id))||b._id===h.admin.toString(),C=b._id===h.admin.toString();return`
561
+ ${h.members.map(f=>{var G;const E=((G=p.editableMembers)==null?void 0:G.includes(f._id))||f._id===h.admin.toString(),C=f._id===h.admin.toString();return`
562
562
  <div style="display: flex; align-items: center; gap: 10px; padding: 8px; background: var(--bg-secondary); border-radius: 6px; margin-bottom: 8px;">
563
- <div class="avatar" style="width: 32px; height: 32px; font-size: 14px;">${b.username[0].toUpperCase()}</div>
564
- <span style="flex: 1;">${b.username}</span>
563
+ <div class="avatar" style="width: 32px; height: 32px; font-size: 14px;">${f.username[0].toUpperCase()}</div>
564
+ <span style="flex: 1;">${f.username}</span>
565
565
  <label style="display: flex; align-items: center; gap: 6px; cursor: pointer;">
566
- <input type="checkbox" name="editableMembers" value="${b._id}" ${E?"checked":""} ${C?"disabled":""} style="width: 18px; height: 18px; cursor: pointer;">
566
+ <input type="checkbox" name="editableMembers" value="${f._id}" ${E?"checked":""} ${C?"disabled":""} style="width: 18px; height: 18px; cursor: pointer;">
567
567
  <span style="font-size: 13px;">${C?"管理员":"可编辑"}</span>
568
568
  </label>
569
569
  </div>
@@ -575,7 +575,7 @@
575
575
  <button type="button" class="btn-secondary" id="cancelPermissionBtn" style="flex: 1;">取消</button>
576
576
  </div>
577
577
  </form>
578
- `,o.classList.remove("hidden"),document.getElementById("cancelPermissionBtn").addEventListener("click",()=>{o.classList.add("hidden")}),document.getElementById("updatePermissionForm").addEventListener("submit",async b=>{b.preventDefault();const C=new FormData(b.target).getAll("editableMembers");try{await s.updateDocumentPermissions(p._id,C),alert("权限更新成功!"),o.classList.add("hidden"),await W(v)}catch(G){console.error("更新权限错误:",G),alert("更新失败: "+G.message)}})}document.getElementById("closePermissionModal").addEventListener("click",()=>{document.getElementById("editPermissionModal").classList.add("hidden")}),document.getElementById("createDocForm").addEventListener("submit",async p=>{p.preventDefault();const h=new FormData(p.target),o=h.getAll("editableMembers");try{await s.createDocument(h.get("title"),h.get("content"),c._id,o),alert("文档创建成功!"),await W(v),document.getElementById("createDocModal").classList.add("hidden")}catch(g){console.error("创建文档错误:",g),alert("创建失败: "+g.message)}})}async function ue(v,x){const B=(await s.getDocument(x)).document;v.innerHTML=`
578
+ `,o.classList.remove("hidden"),document.getElementById("cancelPermissionBtn").addEventListener("click",()=>{o.classList.add("hidden")}),document.getElementById("updatePermissionForm").addEventListener("submit",async f=>{f.preventDefault();const C=new FormData(f.target).getAll("editableMembers");try{await s.updateDocumentPermissions(p._id,C),alert("权限更新成功!"),o.classList.add("hidden"),await W(v)}catch(G){console.error("更新权限错误:",G),alert("更新失败: "+G.message)}})}document.getElementById("closePermissionModal").addEventListener("click",()=>{document.getElementById("editPermissionModal").classList.add("hidden")}),document.getElementById("createDocForm").addEventListener("submit",async p=>{p.preventDefault();const h=new FormData(p.target),o=h.getAll("editableMembers");try{await s.createDocument(h.get("title"),h.get("content"),c._id,o),alert("文档创建成功!"),await W(v),document.getElementById("createDocModal").classList.add("hidden")}catch(g){console.error("创建文档错误:",g),alert("创建失败: "+g.message)}})}async function ue(v,b){const B=(await s.getDocument(b)).document;v.innerHTML=`
579
579
  <div class="view-header">
580
580
  <button class="btn-back" id="backBtn">← 返回</button>
581
581
  <h2>${B.title}</h2>
@@ -593,7 +593,7 @@
593
593
  <span>最后编辑: ${new Date(B.updatedAt).toLocaleString()}</span>
594
594
  </div>
595
595
  </div>
596
- `;const L=new Quill("#editor",{theme:"snow",modules:{toolbar:[[{header:[1,2,3,!1]}],["bold","italic","underline","strike"],[{list:"ordered"},{list:"bullet"}],[{color:[]},{background:[]}],["link","image","code-block"],["clean"]]},readOnly:!1});L.root.innerHTML=B.content||"";let k,p;L.on("text-change",()=>{clearTimeout(k),clearTimeout(p),t.sendTyping(x,r.username,!0),k=setTimeout(()=>{t.sendTyping(x,r.username,!1)},1e3),p=setTimeout(async()=>{const h=L.root.innerHTML;try{await s.updateDocument(x,h)}catch(o){console.error("自动保存失败:",o)}},2e3)}),document.getElementById("saveBtn").addEventListener("click",async()=>{try{const h=L.root.innerHTML;await s.updateDocument(x,h),alert("保存成功!")}catch(h){alert("保存失败: "+h.message)}}),t.on("document_update",h=>{h.documentId===x&&h.userId!==r.id&&(L.root.innerHTML=h.content)}),t.on("typing",h=>{if(h.documentId===x&&h.userId!==r.id){const o=document.getElementById("onlineUsers");if(h.isTyping)o.innerHTML+=`<span class="user-badge typing" data-user="${h.userId}">✏️ ${h.username}</span>`;else{const g=o.querySelector(`[data-user="${h.userId}"]`);g&&g.remove()}}}),document.getElementById("backBtn").addEventListener("click",()=>{W(v)})}async function oe(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const x=await s.getGroupFiles(c._id);v.innerHTML=`
596
+ `;const L=new Quill("#editor",{theme:"snow",modules:{toolbar:[[{header:[1,2,3,!1]}],["bold","italic","underline","strike"],[{list:"ordered"},{list:"bullet"}],[{color:[]},{background:[]}],["link","image","code-block"],["clean"]]},readOnly:!1});L.root.innerHTML=B.content||"";let k,p;L.on("text-change",()=>{clearTimeout(k),clearTimeout(p),t.sendTyping(b,r.username,!0),k=setTimeout(()=>{t.sendTyping(b,r.username,!1)},1e3),p=setTimeout(async()=>{const h=L.root.innerHTML;try{await s.updateDocument(b,h)}catch(o){console.error("自动保存失败:",o)}},2e3)}),document.getElementById("saveBtn").addEventListener("click",async()=>{try{const h=L.root.innerHTML;await s.updateDocument(b,h),alert("保存成功!")}catch(h){alert("保存失败: "+h.message)}}),t.on("document_update",h=>{h.documentId===b&&h.userId!==r.id&&(L.root.innerHTML=h.content)}),t.on("typing",h=>{if(h.documentId===b&&h.userId!==r.id){const o=document.getElementById("onlineUsers");if(h.isTyping)o.innerHTML+=`<span class="user-badge typing" data-user="${h.userId}">✏️ ${h.username}</span>`;else{const g=o.querySelector(`[data-user="${h.userId}"]`);g&&g.remove()}}}),document.getElementById("backBtn").addEventListener("click",()=>{W(v)})}async function oe(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const b=await s.getGroupFiles(c._id);v.innerHTML=`
597
597
  <div class="view-header">
598
598
  <h2>文件管理 - ${c.name}</h2>
599
599
  <button class="btn-primary" id="uploadFileBtn">📤 上传文件</button>
@@ -624,7 +624,7 @@
624
624
  </form>
625
625
  </div>
626
626
  </div>
627
- `;const w=document.getElementById("filesList");!x.files||x.files.length===0?w.innerHTML='<div class="empty-state">暂无文件</div>':(x.files.forEach(B=>{const L=document.createElement("div");L.className="file-card";const k=be(B.mimetype),p=xe(B.size);L.innerHTML=`
627
+ `;const w=document.getElementById("filesList");!b.files||b.files.length===0?w.innerHTML='<div class="empty-state">暂无文件</div>':(b.files.forEach(B=>{const L=document.createElement("div");L.className="file-card";const k=fe(B.mimetype),p=be(B.size);L.innerHTML=`
628
628
  <div class="file-icon">${k}</div>
629
629
  <div class="file-info">
630
630
  <h4>${B.originalName}</h4>
@@ -639,12 +639,12 @@
639
639
  <a href="${s.getFileDownloadUrl(B._id)}" class="btn-primary" download>下载</a>
640
640
  <button class="btn-danger" data-id="${B._id}" data-action="delete-file">删除</button>
641
641
  </div>
642
- `,w.appendChild(L)}),document.querySelectorAll('[data-action="delete-file"]').forEach(B=>{B.addEventListener("click",async()=>{if(confirm("确定要删除这个文件吗?"))try{await s.deleteFile(B.dataset.id),alert("文件删除成功!"),await oe(v)}catch(L){alert("删除失败: "+L.message)}})})),document.getElementById("uploadFileBtn").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.remove("hidden")}),document.getElementById("closeUploadModal").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("cancelUpload").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("uploadFileForm").addEventListener("submit",async B=>{B.preventDefault();const L=document.getElementById("fileInput"),k=document.getElementById("fileDescription").value;if(!L.files[0]){alert("请选择文件");return}try{await s.uploadFile(c._id,L.files[0],k),alert("文件上传成功!"),document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset(),await oe(v)}catch(p){alert("上传失败: "+p.message)}})}catch(x){console.error("获取文件列表失败:",x),v.innerHTML=`
642
+ `,w.appendChild(L)}),document.querySelectorAll('[data-action="delete-file"]').forEach(B=>{B.addEventListener("click",async()=>{if(confirm("确定要删除这个文件吗?"))try{await s.deleteFile(B.dataset.id),alert("文件删除成功!"),await oe(v)}catch(L){alert("删除失败: "+L.message)}})})),document.getElementById("uploadFileBtn").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.remove("hidden")}),document.getElementById("closeUploadModal").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("cancelUpload").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("uploadFileForm").addEventListener("submit",async B=>{B.preventDefault();const L=document.getElementById("fileInput"),k=document.getElementById("fileDescription").value;if(!L.files[0]){alert("请选择文件");return}try{await s.uploadFile(c._id,L.files[0],k),alert("文件上传成功!"),document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset(),await oe(v)}catch(p){alert("上传失败: "+p.message)}})}catch(b){console.error("获取文件列表失败:",b),v.innerHTML=`
643
643
  <div class="view-header">
644
644
  <h2>文件管理</h2>
645
645
  </div>
646
- <div class="empty-state">加载文件失败: ${x.message}</div>
647
- `}}function be(v){return v.startsWith("image/")?"🖼️":v==="application/pdf"?"📕":v.includes("word")||v.includes("document")?"📘":v.includes("excel")||v.includes("spreadsheet")?"📗":v.includes("zip")||v.includes("compressed")?"📦":"📄"}function xe(v){if(v===0)return"0 Bytes";const x=1024,w=["Bytes","KB","MB","GB"],B=Math.floor(Math.log(v)/Math.log(x));return Math.round(v/Math.pow(x,B)*100)/100+" "+w[B]}async function K(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}let w=(await s.getGroup(c._id)).group;function B(S){if(S.startsWith("[白板作品]")){const j=S.replace("[白板作品]","").trim(),T=j.includes("/api/files/")&&j.includes("/download");let X=j;if(T&&!j.includes("token=")){const q=localStorage.getItem("token");X=j.includes("?")?`${j}&token=${q}`:`${j}?token=${q}`}return`
646
+ <div class="empty-state">加载文件失败: ${b.message}</div>
647
+ `}}function fe(v){return v.startsWith("image/")?"🖼️":v==="application/pdf"?"📕":v.includes("word")||v.includes("document")?"📘":v.includes("excel")||v.includes("spreadsheet")?"📗":v.includes("zip")||v.includes("compressed")?"📦":"📄"}function be(v){if(v===0)return"0 Bytes";const b=1024,w=["Bytes","KB","MB","GB"],B=Math.floor(Math.log(v)/Math.log(b));return Math.round(v/Math.pow(b,B)*100)/100+" "+w[B]}async function K(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}let w=(await s.getGroup(c._id)).group;function B(S){if(S.startsWith("[白板作品]")){const j=S.replace("[白板作品]","").trim(),T=j.includes("/api/files/")&&j.includes("/download");let X=j;if(T&&!j.includes("token=")){const q=localStorage.getItem("token");X=j.includes("?")?`${j}&token=${q}`:`${j}?token=${q}`}return`
648
648
  <div style="background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%); padding: 16px; border-radius: 12px; box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);">
649
649
  <div style="margin-bottom: 12px; font-weight: 600; color: white; display: flex; align-items: center; gap: 6px; font-size: 15px;">
650
650
  <span style="font-size: 18px;">🎨</span>
@@ -725,7 +725,7 @@
725
725
  </div>
726
726
 
727
727
  <h3 style="margin-bottom: 16px;">投票选项</h3>
728
- ${q.options.map((a,e)=>{const n=re>0?(a.votes.length/re*100).toFixed(1):0;let d="";if(!q.anonymous&&a.votes.length>0){const y=a.votes.map(f=>{if(f&&typeof f=="object"){if(f.username&&typeof f.username=="string"&&f.username.trim())return f.username.trim();if(f.user&&typeof f.user=="object"&&f.user.username&&typeof f.user.username=="string")return f.user.username.trim()}return null}).filter(f=>f!==null&&f!=="未知用户"&&f.trim()!=="");y.length>0?d=`
728
+ ${q.options.map((a,e)=>{const n=re>0?(a.votes.length/re*100).toFixed(1):0;let d="";if(!q.anonymous&&a.votes.length>0){const y=a.votes.map(x=>{if(x&&typeof x=="object"){if(x.username&&typeof x.username=="string"&&x.username.trim())return x.username.trim();if(x.user&&typeof x.user=="object"&&x.user.username&&typeof x.user.username=="string")return x.user.username.trim()}return null}).filter(x=>x!==null&&x!=="未知用户"&&x.trim()!=="");y.length>0?d=`
729
729
  <div style="font-size: 13px; color: var(--text-secondary); margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border);">
730
730
  <strong style="color: var(--text-primary);">👥 投票者:</strong> ${y.join(", ")}
731
731
  </div>
@@ -942,17 +942,17 @@
942
942
  </div>
943
943
  </div>
944
944
  </div>
945
- `;const L=document.getElementById("messages"),k=document.getElementById("messageInput"),p=document.getElementById("sendBtn"),h=document.getElementById("emojiBtn"),o=document.getElementById("emojiPicker");let g=new Set((w.mutedUsers||[]).map(String)),b=!!w.mutedAll;h.addEventListener("click",()=>{o.classList.toggle("hidden")}),o.addEventListener("emoji-click",S=>{k.value+=S.detail.unicode,k.focus(),o.classList.add("hidden")}),document.addEventListener("click",S=>{!h.contains(S.target)&&!o.contains(S.target)&&o.classList.add("hidden")}),"Notification"in window&&Notification.permission==="default"&&Notification.requestPermission();try{const S=await s.getGroupMessages(c._id);S.messages&&(S.messages.forEach(j=>{const T=document.createElement("div");T.className=`message ${j.sender===l?"own":""}`;const X=B(j.content),q=j.content.startsWith("[白板作品]")||j.content.startsWith("[投票]"),re=j.content.startsWith("[白板作品]");T.innerHTML=`
945
+ `;const L=document.getElementById("messages"),k=document.getElementById("messageInput"),p=document.getElementById("sendBtn"),h=document.getElementById("emojiBtn"),o=document.getElementById("emojiPicker");let g=new Set((w.mutedUsers||[]).map(String)),f=!!w.mutedAll;h.addEventListener("click",()=>{o.classList.toggle("hidden")}),o.addEventListener("emoji-click",S=>{k.value+=S.detail.unicode,k.focus(),o.classList.add("hidden")}),document.addEventListener("click",S=>{!h.contains(S.target)&&!o.contains(S.target)&&o.classList.add("hidden")}),"Notification"in window&&Notification.permission==="default"&&Notification.requestPermission();try{const S=await s.getGroupMessages(c._id);S.messages&&(S.messages.forEach(j=>{const T=document.createElement("div");T.className=`message ${j.sender===l?"own":""}`;const X=B(j.content),q=j.content.startsWith("[白板作品]")||j.content.startsWith("[投票]"),re=j.content.startsWith("[白板作品]");T.innerHTML=`
946
946
  <div class="message-header">
947
947
  <span class="message-user">${j.username}</span>
948
948
  <span class="message-time">${new Date(j.timestamp).toLocaleTimeString()}</span>
949
949
  </div>
950
950
  <div class="message-content" style="${re?"background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%); color: white; padding: 16px; border-radius: 12px; box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);":q?"background: transparent; padding: 0;":""}">${X}</div>
951
- `,L.appendChild(T)}),L.scrollTop=L.scrollHeight)}catch(S){console.error("加载历史消息失败:",S)}const E=()=>{const S=document.getElementById("muteAllBtn");S.textContent=b?"取消全体禁言":"全体禁言",S.style.background=b?"var(--danger)":""};E(),document.getElementById("clearChatBtn").addEventListener("click",async()=>{if(!confirm(`⚠️ 警告:此操作将永久删除该群组的所有聊天记录!
951
+ `,L.appendChild(T)}),L.scrollTop=L.scrollHeight)}catch(S){console.error("加载历史消息失败:",S)}const E=()=>{const S=document.getElementById("muteAllBtn");S.textContent=f?"取消全体禁言":"全体禁言",S.style.background=f?"var(--danger)":""};E(),document.getElementById("clearChatBtn").addEventListener("click",async()=>{if(!confirm(`⚠️ 警告:此操作将永久删除该群组的所有聊天记录!
952
952
 
953
953
  确定要清除吗?`))return;if(prompt(`请输入群组名称以确认删除:
954
954
 
955
- 群组名称:`+c.name)!==c.name){alert("❌ 群组名称不匹配,操作已取消");return}try{const T=document.getElementById("clearChatBtn"),X=T.innerHTML;T.innerHTML="⏳ 清除中...",T.disabled=!0;const q=localStorage.getItem("token"),re=await fetch(`http://localhost:3000/api/messages/group/${c._id}/clear`,{method:"DELETE",headers:{Authorization:`Bearer ${q}`,"Content-Type":"application/json"}});if(!re.ok){const ne=await re.json();throw new Error(ne.message||"清除失败")}const de=await re.json();L.innerHTML='<div class="empty-state" style="padding: 40px; text-align: center; color: var(--text-secondary);">✨ 聊天记录已清空</div>',alert(`✅ 成功清除 ${de.deletedCount||0} 条聊天记录!`),T.innerHTML=X,T.disabled=!1}catch(T){console.error("清除聊天记录失败:",T),alert("❌ 清除失败: "+T.message);const X=document.getElementById("clearChatBtn");X.innerHTML="🗑️ 清除记录",X.disabled=!1}}),document.getElementById("muteAllBtn").addEventListener("click",async()=>{try{const S=!b;b=!!(await s.setMuteAll(c._id,S)).mutedAll,E();const T=document.createElement("div");T.className="notification",T.textContent=b?"已开启全体禁言(成员无法发言)":"已取消全体禁言",L.appendChild(T),L.scrollTop=L.scrollHeight}catch(S){alert("设置失败: "+S.message)}}),document.getElementById("manageMuteBtn").addEventListener("click",async()=>{w=(await s.getGroup(c._id)).group,g=new Set((w.mutedUsers||[]).map(String));const j=document.getElementById("membersList");j.innerHTML=w.members.filter(T=>T._id.toString()!==l).map(T=>{const X=g.has(T._id.toString());return`
955
+ 群组名称:`+c.name)!==c.name){alert("❌ 群组名称不匹配,操作已取消");return}try{const T=document.getElementById("clearChatBtn"),X=T.innerHTML;T.innerHTML="⏳ 清除中...",T.disabled=!0;const q=localStorage.getItem("token"),re=await fetch(`http://localhost:3000/api/messages/group/${c._id}/clear`,{method:"DELETE",headers:{Authorization:`Bearer ${q}`,"Content-Type":"application/json"}});if(!re.ok){const ne=await re.json();throw new Error(ne.message||"清除失败")}const de=await re.json();L.innerHTML='<div class="empty-state" style="padding: 40px; text-align: center; color: var(--text-secondary);">✨ 聊天记录已清空</div>',alert(`✅ 成功清除 ${de.deletedCount||0} 条聊天记录!`),T.innerHTML=X,T.disabled=!1}catch(T){console.error("清除聊天记录失败:",T),alert("❌ 清除失败: "+T.message);const X=document.getElementById("clearChatBtn");X.innerHTML="🗑️ 清除记录",X.disabled=!1}}),document.getElementById("muteAllBtn").addEventListener("click",async()=>{try{const S=!f;f=!!(await s.setMuteAll(c._id,S)).mutedAll,E();const T=document.createElement("div");T.className="notification",T.textContent=f?"已开启全体禁言(成员无法发言)":"已取消全体禁言",L.appendChild(T),L.scrollTop=L.scrollHeight}catch(S){alert("设置失败: "+S.message)}}),document.getElementById("manageMuteBtn").addEventListener("click",async()=>{w=(await s.getGroup(c._id)).group,g=new Set((w.mutedUsers||[]).map(String));const j=document.getElementById("membersList");j.innerHTML=w.members.filter(T=>T._id.toString()!==l).map(T=>{const X=g.has(T._id.toString());return`
956
956
  <div style="display: flex; align-items: center; justify-content: space-between; padding: 12px; border-bottom: 1px solid var(--border);">
957
957
  <div style="display: flex; align-items: center; gap: 10px;">
958
958
  <div class="avatar" style="width: 35px; height: 35px;">${T.username[0].toUpperCase()}</div>
@@ -971,7 +971,7 @@
971
971
  <span class="message-time">${new Date(S.timestamp).toLocaleTimeString()}</span>
972
972
  </div>
973
973
  <div class="message-content" style="${q?"background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%); color: white; padding: 16px; border-radius: 12px; box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);":X?"background: transparent; padding: 0;":""}">${T}</div>
974
- `,L.appendChild(j),L.scrollTop=L.scrollHeight}}),t.on("chat_blocked",S=>{if(S.groupId===c._id){const j=document.createElement("div");j.className="notification",j.textContent=S.message||"消息发送失败",L.appendChild(j),L.scrollTop=L.scrollHeight}});const C=()=>{const S=k.value.trim();S&&(t.sendChatMessage(c._id,r.username,S),k.value="")};p.addEventListener("click",C),k.addEventListener("keypress",S=>{S.key==="Enter"&&C()}),document.getElementById("openAIBtn").addEventListener("click",()=>{document.getElementById("aiModal").classList.remove("hidden")}),document.getElementById("closeAIModal").addEventListener("click",()=>{document.getElementById("aiModal").classList.add("hidden")}),document.querySelectorAll(".quick-question-btn").forEach(S=>{S.addEventListener("click",()=>{document.getElementById("aiInputText").value=S.dataset.question,document.getElementById("aiSendBtnModal").click()}),S.addEventListener("mouseenter",j=>{j.target.style.background="var(--primary)",j.target.style.color="white",j.target.style.transform="translateY(-2px)"}),S.addEventListener("mouseleave",j=>{j.target.style.background="var(--bg)",j.target.style.color="inherit",j.target.style.transform="translateY(0)"})});const G=document.getElementById("aiInputText");G.addEventListener("input",()=>{G.style.height="auto",G.style.height=G.scrollHeight+"px"}),G.addEventListener("keydown",S=>{S.key==="Enter"&&!S.shiftKey&&(S.preventDefault(),document.getElementById("aiSendBtnModal").click())}),G.addEventListener("focus",()=>{G.style.borderColor="var(--primary)"}),G.addEventListener("blur",()=>{G.style.borderColor="var(--border)"});const J=document.getElementById("aiSendBtnModal");J.addEventListener("mouseenter",()=>{J.style.transform="scale(1.05)"}),J.addEventListener("mouseleave",()=>{J.style.transform="scale(1)"}),document.getElementById("aiSendBtnModal").addEventListener("click",async()=>{const S=document.getElementById("aiInputText"),j=S.value.trim();if(!j)return;const T=document.getElementById("aiChatMessages"),X=document.createElement("div");X.className="ai-message user",X.style.cssText="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 18px; border-radius: 18px 18px 4px 18px; margin: 10px 0; max-width: 75%; margin-left: auto; text-align: right; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); animation: slideInRight 0.3s ease;",X.textContent=j,T.appendChild(X),S.value="";const q=document.createElement("div");q.className="ai-message ai loading",q.style.cssText="background: var(--bg-tertiary); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",q.textContent="思考中...",T.appendChild(q),T.scrollTop=T.scrollHeight;try{const re=localStorage.getItem("token"),ne=await(await fetch("http://localhost:3000/api/ai/ask",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${re}`},body:JSON.stringify({question:j,groupId:c==null?void 0:c._id})})).json();q.remove();const pe=document.createElement("div");pe.className="ai-message ai",pe.style.cssText="background: var(--bg-secondary); padding: 15px 18px; border-radius: 18px 18px 18px 4px; margin: 10px 0; max-width: 75%; border: 1px solid var(--border); box-shadow: 0 2px 4px rgba(0,0,0,0.05); animation: slideInLeft 0.3s ease; line-height: 1.6;",pe.textContent=ne.answer||"抱歉,我无法回答这个问题。",T.appendChild(pe),T.scrollTop=T.scrollHeight}catch(re){q.remove();const de=document.createElement("div");de.className="ai-message ai error",de.style.cssText="background: var(--danger); color: white; padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",de.textContent="抱歉,发生了错误: "+re.message,T.appendChild(de),T.scrollTop=T.scrollHeight}}),window.showImageModal=S=>{const j=document.getElementById("imagePreviewModal"),T=document.getElementById("previewImage"),X=document.getElementById("downloadImageBtn");T.src=S,j.classList.remove("hidden"),X.onclick=async()=>{try{const re=await(await fetch(S)).blob(),de=window.URL.createObjectURL(re),ne=document.createElement("a");ne.href=de,ne.download=`whiteboard-${Date.now()}.png`,document.body.appendChild(ne),ne.click(),document.body.removeChild(ne),window.URL.revokeObjectURL(de)}catch(q){console.error("下载失败:",q),alert("下载失败,请重试")}}},document.getElementById("closeImagePreview").addEventListener("click",()=>{document.getElementById("imagePreviewModal").classList.add("hidden")}),document.getElementById("imagePreviewModal").addEventListener("click",S=>{S.target.id==="imagePreviewModal"&&document.getElementById("imagePreviewModal").classList.add("hidden")}),document.getElementById("openWhiteboardBtn").addEventListener("click",()=>{document.getElementById("whiteboardModal").classList.remove("hidden"),ee()}),document.getElementById("closeWhiteboardModal").addEventListener("click",()=>{document.getElementById("whiteboardModal").classList.add("hidden")});function ee(){const S=document.getElementById("whiteboardCanvas");if(!S)return;const j=S.getContext("2d");let T=!1,X="pen",q="#000000",re=3,de=0,ne=0;document.querySelectorAll(".tool-btn").forEach(n=>{n.onclick=()=>{document.querySelectorAll(".tool-btn").forEach(d=>{d.style.background="transparent",d.style.borderColor="var(--border)",d.style.color="inherit",d.classList.remove("active")}),n.style.background="var(--primary)",n.style.borderColor="var(--primary)",n.style.color="white",n.classList.add("active"),X=n.dataset.tool}});const pe=document.getElementById("colorPickerCanvas");pe&&(pe.onchange=n=>{q=n.target.value});const a=document.getElementById("brushSizeCanvas"),e=document.getElementById("brushSizeLabel");a&&e&&(a.oninput=n=>{re=n.target.value,e.textContent=`大小: ${re}`}),S.onmousedown=n=>{T=!0;const d=S.getBoundingClientRect();de=n.clientX-d.left,ne=n.clientY-d.top},S.onmousemove=n=>{if(!T)return;const d=S.getBoundingClientRect(),y=n.clientX-d.left,f=n.clientY-d.top;j.beginPath(),j.moveTo(de,ne),j.lineTo(y,f),j.strokeStyle=X==="eraser"?"#ffffff":q,j.lineWidth=re,j.lineCap="round",j.stroke(),de=y,ne=f},S.onmouseup=()=>{T=!1},S.onmouseleave=()=>{T=!1},document.getElementById("clearCanvasBtn").onclick=()=>{confirm("确定要清空画布吗?")&&j.clearRect(0,0,S.width,S.height)},document.getElementById("saveCanvasBtn").onclick=()=>{const n=S.toDataURL("image/png"),d=document.createElement("a");d.download=`whiteboard-${Date.now()}.png`,d.href=n,d.click(),alert("白板已保存!")},document.getElementById("sendToGroupBtn").onclick=async()=>{try{const n=S.toDataURL("image/png"),d=await fetch(n).then(Q=>Q.blob()),y=new FormData;y.append("file",d,`whiteboard-${Date.now()}.png`),y.append("groupId",c._id),y.append("description","协作白板作品");const f=localStorage.getItem("token"),I=await fetch("http://localhost:3000/api/files/upload",{method:"POST",headers:{Authorization:`Bearer ${f}`},body:y});if(I.ok){const ce=`http://localhost:3000/api/files/${(await I.json()).file._id}/download?token=${f}`;t.sendChatMessage(c._id,r.username,`[白板作品]${ce}`),alert("白板作品已发送到群聊!"),document.getElementById("whiteboardModal").classList.add("hidden")}else throw new Error("上传失败")}catch(n){console.error("发送白板作品错误:",n),alert("发送失败: "+n.message)}}}}async function te(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}v.innerHTML=`
974
+ `,L.appendChild(j),L.scrollTop=L.scrollHeight}}),t.on("chat_blocked",S=>{if(S.groupId===c._id){const j=document.createElement("div");j.className="notification",j.textContent=S.message||"消息发送失败",L.appendChild(j),L.scrollTop=L.scrollHeight}});const C=()=>{const S=k.value.trim();S&&(t.sendChatMessage(c._id,r.username,S),k.value="")};p.addEventListener("click",C),k.addEventListener("keypress",S=>{S.key==="Enter"&&C()}),document.getElementById("openAIBtn").addEventListener("click",()=>{document.getElementById("aiModal").classList.remove("hidden")}),document.getElementById("closeAIModal").addEventListener("click",()=>{document.getElementById("aiModal").classList.add("hidden")}),document.querySelectorAll(".quick-question-btn").forEach(S=>{S.addEventListener("click",()=>{document.getElementById("aiInputText").value=S.dataset.question,document.getElementById("aiSendBtnModal").click()}),S.addEventListener("mouseenter",j=>{j.target.style.background="var(--primary)",j.target.style.color="white",j.target.style.transform="translateY(-2px)"}),S.addEventListener("mouseleave",j=>{j.target.style.background="var(--bg)",j.target.style.color="inherit",j.target.style.transform="translateY(0)"})});const G=document.getElementById("aiInputText");G.addEventListener("input",()=>{G.style.height="auto",G.style.height=G.scrollHeight+"px"}),G.addEventListener("keydown",S=>{S.key==="Enter"&&!S.shiftKey&&(S.preventDefault(),document.getElementById("aiSendBtnModal").click())}),G.addEventListener("focus",()=>{G.style.borderColor="var(--primary)"}),G.addEventListener("blur",()=>{G.style.borderColor="var(--border)"});const J=document.getElementById("aiSendBtnModal");J.addEventListener("mouseenter",()=>{J.style.transform="scale(1.05)"}),J.addEventListener("mouseleave",()=>{J.style.transform="scale(1)"}),document.getElementById("aiSendBtnModal").addEventListener("click",async()=>{const S=document.getElementById("aiInputText"),j=S.value.trim();if(!j)return;const T=document.getElementById("aiChatMessages"),X=document.createElement("div");X.className="ai-message user",X.style.cssText="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 18px; border-radius: 18px 18px 4px 18px; margin: 10px 0; max-width: 75%; margin-left: auto; text-align: right; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); animation: slideInRight 0.3s ease;",X.textContent=j,T.appendChild(X),S.value="";const q=document.createElement("div");q.className="ai-message ai loading",q.style.cssText="background: var(--bg-tertiary); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",q.textContent="思考中...",T.appendChild(q),T.scrollTop=T.scrollHeight;try{const re=localStorage.getItem("token"),ne=await(await fetch("http://localhost:3000/api/ai/ask",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${re}`},body:JSON.stringify({question:j,groupId:c==null?void 0:c._id})})).json();q.remove();const pe=document.createElement("div");pe.className="ai-message ai",pe.style.cssText="background: var(--bg-secondary); padding: 15px 18px; border-radius: 18px 18px 18px 4px; margin: 10px 0; max-width: 75%; border: 1px solid var(--border); box-shadow: 0 2px 4px rgba(0,0,0,0.05); animation: slideInLeft 0.3s ease; line-height: 1.6;",pe.textContent=ne.answer||"抱歉,我无法回答这个问题。",T.appendChild(pe),T.scrollTop=T.scrollHeight}catch(re){q.remove();const de=document.createElement("div");de.className="ai-message ai error",de.style.cssText="background: var(--danger); color: white; padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",de.textContent="抱歉,发生了错误: "+re.message,T.appendChild(de),T.scrollTop=T.scrollHeight}}),window.showImageModal=S=>{const j=document.getElementById("imagePreviewModal"),T=document.getElementById("previewImage"),X=document.getElementById("downloadImageBtn");T.src=S,j.classList.remove("hidden"),X.onclick=async()=>{try{const re=await(await fetch(S)).blob(),de=window.URL.createObjectURL(re),ne=document.createElement("a");ne.href=de,ne.download=`whiteboard-${Date.now()}.png`,document.body.appendChild(ne),ne.click(),document.body.removeChild(ne),window.URL.revokeObjectURL(de)}catch(q){console.error("下载失败:",q),alert("下载失败,请重试")}}},document.getElementById("closeImagePreview").addEventListener("click",()=>{document.getElementById("imagePreviewModal").classList.add("hidden")}),document.getElementById("imagePreviewModal").addEventListener("click",S=>{S.target.id==="imagePreviewModal"&&document.getElementById("imagePreviewModal").classList.add("hidden")}),document.getElementById("openWhiteboardBtn").addEventListener("click",()=>{document.getElementById("whiteboardModal").classList.remove("hidden"),ee()}),document.getElementById("closeWhiteboardModal").addEventListener("click",()=>{document.getElementById("whiteboardModal").classList.add("hidden")});function ee(){const S=document.getElementById("whiteboardCanvas");if(!S)return;const j=S.getContext("2d");let T=!1,X="pen",q="#000000",re=3,de=0,ne=0;document.querySelectorAll(".tool-btn").forEach(n=>{n.onclick=()=>{document.querySelectorAll(".tool-btn").forEach(d=>{d.style.background="transparent",d.style.borderColor="var(--border)",d.style.color="inherit",d.classList.remove("active")}),n.style.background="var(--primary)",n.style.borderColor="var(--primary)",n.style.color="white",n.classList.add("active"),X=n.dataset.tool}});const pe=document.getElementById("colorPickerCanvas");pe&&(pe.onchange=n=>{q=n.target.value});const a=document.getElementById("brushSizeCanvas"),e=document.getElementById("brushSizeLabel");a&&e&&(a.oninput=n=>{re=n.target.value,e.textContent=`大小: ${re}`}),S.onmousedown=n=>{T=!0;const d=S.getBoundingClientRect();de=n.clientX-d.left,ne=n.clientY-d.top},S.onmousemove=n=>{if(!T)return;const d=S.getBoundingClientRect(),y=n.clientX-d.left,x=n.clientY-d.top;j.beginPath(),j.moveTo(de,ne),j.lineTo(y,x),j.strokeStyle=X==="eraser"?"#ffffff":q,j.lineWidth=re,j.lineCap="round",j.stroke(),de=y,ne=x},S.onmouseup=()=>{T=!1},S.onmouseleave=()=>{T=!1},document.getElementById("clearCanvasBtn").onclick=()=>{confirm("确定要清空画布吗?")&&j.clearRect(0,0,S.width,S.height)},document.getElementById("saveCanvasBtn").onclick=()=>{const n=S.toDataURL("image/png"),d=document.createElement("a");d.download=`whiteboard-${Date.now()}.png`,d.href=n,d.click(),alert("白板已保存!")},document.getElementById("sendToGroupBtn").onclick=async()=>{try{const n=S.toDataURL("image/png"),d=await fetch(n).then(Q=>Q.blob()),y=new FormData;y.append("file",d,`whiteboard-${Date.now()}.png`),y.append("groupId",c._id),y.append("description","协作白板作品");const x=localStorage.getItem("token"),I=await fetch("http://localhost:3000/api/files/upload",{method:"POST",headers:{Authorization:`Bearer ${x}`},body:y});if(I.ok){const ce=`http://localhost:3000/api/files/${(await I.json()).file._id}/download?token=${x}`;t.sendChatMessage(c._id,r.username,`[白板作品]${ce}`),alert("白板作品已发送到群聊!"),document.getElementById("whiteboardModal").classList.add("hidden")}else throw new Error("上传失败")}catch(n){console.error("发送白板作品错误:",n),alert("发送失败: "+n.message)}}}}async function te(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}v.innerHTML=`
975
975
  <div class="view-header">
976
976
  <h2>随机点名 - ${c.name}</h2>
977
977
  </div>
@@ -983,7 +983,7 @@
983
983
  </div>
984
984
  <div id="callResult" class="call-result"></div>
985
985
  </div>
986
- `,document.getElementById("randomCallBtn").addEventListener("click",async()=>{const x=parseInt(document.getElementById("callCount").value);try{const w=await s.randomCall(c._id,x),B=document.getElementById("callResult");if(B.innerHTML=`
986
+ `,document.getElementById("randomCallBtn").addEventListener("click",async()=>{const b=parseInt(document.getElementById("callCount").value);try{const w=await s.randomCall(c._id,b),B=document.getElementById("callResult");if(B.innerHTML=`
987
987
  <h3>点名结果:</h3>
988
988
  <div class="called-members">
989
989
  ${w.calledMembers.map(L=>`
@@ -1057,7 +1057,7 @@
1057
1057
  </div>
1058
1058
  </div>
1059
1059
  </div>
1060
- `;let x=1,w={};try{const o=await s.getGroups(),g=document.getElementById("auditGroupFilter");o.groups.forEach(b=>{const E=document.createElement("option");E.value=b._id,E.textContent=b.name,g.appendChild(E)})}catch(o){console.error("加载群组列表失败:",o)}async function B(o=1,g={}){try{const b=document.getElementById("auditLogs");b.innerHTML='<div class="loading">加载中...</div>';const E={page:o,limit:20},C=await s.getAuditLogs(g,E);if(C.logs.length===0){b.innerHTML='<div class="empty-state">暂无操作记录</div>',document.getElementById("auditPagination").style.display="none";return}b.innerHTML=`
1060
+ `;let b=1,w={};try{const o=await s.getGroups(),g=document.getElementById("auditGroupFilter");o.groups.forEach(f=>{const E=document.createElement("option");E.value=f._id,E.textContent=f.name,g.appendChild(E)})}catch(o){console.error("加载群组列表失败:",o)}async function B(o=1,g={}){try{const f=document.getElementById("auditLogs");f.innerHTML='<div class="loading">加载中...</div>';const E={page:o,limit:20},C=await s.getAuditLogs(g,E);if(C.logs.length===0){f.innerHTML='<div class="empty-state">暂无操作记录</div>',document.getElementById("auditPagination").style.display="none";return}f.innerHTML=`
1061
1061
  <div class="audit-table">
1062
1062
  <div class="audit-header">
1063
1063
  <div>时间</div>
@@ -1081,7 +1081,7 @@
1081
1081
  </div>
1082
1082
  `}).join("")}
1083
1083
  </div>
1084
- `;const G=document.getElementById("auditPagination"),J=document.getElementById("pageInfo");J.textContent=`第 ${C.pagination.page} 页,共 ${C.pagination.pages} 页`,document.getElementById("prevPage").disabled=C.pagination.page<=1,document.getElementById("nextPage").disabled=C.pagination.page>=C.pagination.pages,G.style.display=C.pagination.pages>1?"flex":"none"}catch(b){console.error("加载审计日志失败:",b),document.getElementById("auditLogs").innerHTML='<div class="error-state">加载失败: '+b.message+"</div>"}}async function L(){try{const o=new Date,g=new Date(o.getTime()-7*24*60*60*1e3),b=await s.getAuditSummary({startDate:o.toISOString().split("T")[0],endDate:o.toISOString().split("T")[0]}),E=await s.getAuditSummary({startDate:g.toISOString().split("T")[0],endDate:o.toISOString().split("T")[0]});document.getElementById("todayCount").textContent=b.summary.totalLogs,document.getElementById("weekCount").textContent=E.summary.totalLogs,document.getElementById("activeUsers").textContent=E.summary.topUsers.length}catch(o){console.error("加载统计信息失败:",o)}}function k(o){var G,J,ee,S,j,T;const g=((G=o.user)==null?void 0:G.username)||"未知用户",b=V(o.action),E=o.resourceTitle||o.resourceId;let C='<strong style="color: #6366f1;">'+g+"</strong> ";switch(o.action){case"document_create":C+='创建了文档 <strong>"'+E+'"</strong>';break;case"document_update":C+='更新了文档 <strong>"'+E+'"</strong>',(J=o.details)!=null&&J.field&&(C+=" 的 <strong>"+p(o.details.field)+"</strong>");break;case"document_delete":C+='删除了文档 <strong>"'+E+'"</strong>';break;case"content_edit":if(C+='编辑了文档 <strong>"'+E+'"</strong> 的内容',o.changes){const X=((ee=o.changes.insertions)==null?void 0:ee.reduce((re,de)=>re+de.length,0))||0,q=((S=o.changes.deletions)==null?void 0:S.reduce((re,de)=>re+de.length,0))||0;(X>0||q>0)&&(C+=' (<span style="color: #10b981;">+'+X+'</span> / <span style="color: #ef4444;">-'+q+"</span> 字符)")}break;case"title_edit":C+='修改了文档 <strong>"'+E+'"</strong> 的标题',(j=o.details)!=null&&j.oldValue&&((T=o.details)!=null&&T.newValue)&&(C+=' 从 <strong>"'+o.details.oldValue+'"</strong> 改为 <strong>"'+o.details.newValue+'"</strong>');break;case"document_permission_change":C+='修改了文档 <strong>"'+E+'"</strong> 的权限设置';break;default:C+="执行了 <strong>"+b+"</strong> 操作"}return C}function p(o){return{title:"标题",content:"内容",permissions:"权限",status:"状态",tags:"标签",category:"分类",description:"描述"}[o]||o}function h(o){if(o==null)return'<span style="color: var(--text-tertiary); font-style: italic;">空</span>';if(typeof o=="object")return JSON.stringify(o,null,2);const g=String(o);return g.length>500?g.substring(0,500)+'... <span style="color: var(--text-tertiary); font-style: italic;">(内容过长,已截断)</span>':g.replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.showAuditDetail=async o=>{var g,b,E,C,G,J;try{const ee=localStorage.getItem("token"),T=(await(await fetch(`http://localhost:3000/api/audit/${o}`,{headers:{Authorization:`Bearer ${ee}`}})).json()).log,X=document.getElementById("auditDetailModal"),q=document.getElementById("auditDetailContent"),re=pe=>({create:"#10b981",update:"#f59e0b",delete:"#ef4444",login:"#6366f1",logout:"#8b5cf6"})[pe]||"#6366f1";q.innerHTML=`
1084
+ `;const G=document.getElementById("auditPagination"),J=document.getElementById("pageInfo");J.textContent=`第 ${C.pagination.page} 页,共 ${C.pagination.pages} 页`,document.getElementById("prevPage").disabled=C.pagination.page<=1,document.getElementById("nextPage").disabled=C.pagination.page>=C.pagination.pages,G.style.display=C.pagination.pages>1?"flex":"none"}catch(f){console.error("加载审计日志失败:",f),document.getElementById("auditLogs").innerHTML='<div class="error-state">加载失败: '+f.message+"</div>"}}async function L(){try{const o=new Date,g=new Date(o.getTime()-7*24*60*60*1e3),f=await s.getAuditSummary({startDate:o.toISOString().split("T")[0],endDate:o.toISOString().split("T")[0]}),E=await s.getAuditSummary({startDate:g.toISOString().split("T")[0],endDate:o.toISOString().split("T")[0]});document.getElementById("todayCount").textContent=f.summary.totalLogs,document.getElementById("weekCount").textContent=E.summary.totalLogs,document.getElementById("activeUsers").textContent=E.summary.topUsers.length}catch(o){console.error("加载统计信息失败:",o)}}function k(o){var G,J,ee,S,j,T;const g=((G=o.user)==null?void 0:G.username)||"未知用户",f=V(o.action),E=o.resourceTitle||o.resourceId;let C='<strong style="color: #6366f1;">'+g+"</strong> ";switch(o.action){case"document_create":C+='创建了文档 <strong>"'+E+'"</strong>';break;case"document_update":C+='更新了文档 <strong>"'+E+'"</strong>',(J=o.details)!=null&&J.field&&(C+=" 的 <strong>"+p(o.details.field)+"</strong>");break;case"document_delete":C+='删除了文档 <strong>"'+E+'"</strong>';break;case"content_edit":if(C+='编辑了文档 <strong>"'+E+'"</strong> 的内容',o.changes){const X=((ee=o.changes.insertions)==null?void 0:ee.reduce((re,de)=>re+de.length,0))||0,q=((S=o.changes.deletions)==null?void 0:S.reduce((re,de)=>re+de.length,0))||0;(X>0||q>0)&&(C+=' (<span style="color: #10b981;">+'+X+'</span> / <span style="color: #ef4444;">-'+q+"</span> 字符)")}break;case"title_edit":C+='修改了文档 <strong>"'+E+'"</strong> 的标题',(j=o.details)!=null&&j.oldValue&&((T=o.details)!=null&&T.newValue)&&(C+=' 从 <strong>"'+o.details.oldValue+'"</strong> 改为 <strong>"'+o.details.newValue+'"</strong>');break;case"document_permission_change":C+='修改了文档 <strong>"'+E+'"</strong> 的权限设置';break;default:C+="执行了 <strong>"+f+"</strong> 操作"}return C}function p(o){return{title:"标题",content:"内容",permissions:"权限",status:"状态",tags:"标签",category:"分类",description:"描述"}[o]||o}function h(o){if(o==null)return'<span style="color: var(--text-tertiary); font-style: italic;">空</span>';if(typeof o=="object")return JSON.stringify(o,null,2);const g=String(o);return g.length>500?g.substring(0,500)+'... <span style="color: var(--text-tertiary); font-style: italic;">(内容过长,已截断)</span>':g.replace(/</g,"&lt;").replace(/>/g,"&gt;")}window.showAuditDetail=async o=>{var g,f,E,C,G,J;try{const ee=localStorage.getItem("token"),T=(await(await fetch(`http://localhost:3000/api/audit/${o}`,{headers:{Authorization:`Bearer ${ee}`}})).json()).log,X=document.getElementById("auditDetailModal"),q=document.getElementById("auditDetailContent"),re=pe=>({create:"#10b981",update:"#f59e0b",delete:"#ef4444",login:"#6366f1",logout:"#8b5cf6"})[pe]||"#6366f1";q.innerHTML=`
1085
1085
  <div class="audit-detail" style="padding: 0; background: linear-gradient(135deg, rgba(99, 102, 241, 0.03) 0%, rgba(168, 85, 247, 0.03) 100%);">
1086
1086
 
1087
1087
  <!-- 操作信息 -->
@@ -1099,7 +1099,7 @@
1099
1099
  <span style="font-weight: 600; color: var(--text-primary);">${new Date(T.createdAt).toLocaleString("zh-CN",{year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}</span>
1100
1100
  <span style="color: var(--text-tertiary); font-weight: 500;">操作用户:</span>
1101
1101
  <span style="display: flex; align-items: center; gap: 10px;">
1102
- <div class="avatar" style="width: 32px; height: 32px; font-size: 14px; background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);">${((E=(b=(g=T.user)==null?void 0:g.username)==null?void 0:b[0])==null?void 0:E.toUpperCase())||"?"}</div>
1102
+ <div class="avatar" style="width: 32px; height: 32px; font-size: 14px; background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);">${((E=(f=(g=T.user)==null?void 0:g.username)==null?void 0:f[0])==null?void 0:E.toUpperCase())||"?"}</div>
1103
1103
  <span style="font-weight: 600; color: var(--text-primary);">${((C=T.user)==null?void 0:C.username)||"未知用户"}</span>
1104
1104
  </span>
1105
1105
  </div>
@@ -1167,21 +1167,21 @@
1167
1167
  </div>
1168
1168
  </div>
1169
1169
  </div>
1170
- `,document.getElementById("auditDescriptionText").innerHTML=k(T);const de=document.getElementById("auditDetailsContent");let ne="";if(T.details&&(T.details.field&&(ne+='<span style="color: var(--text-tertiary); font-weight: 500;">修改字段:</span>',ne+='<span style="font-weight: 600; color: var(--text-primary);">'+p(T.details.field)+"</span>"),T.details.oldValue!==void 0&&T.details.oldValue!==null&&(ne+='<span style="color: var(--text-tertiary); font-weight: 500;">原始值:</span>',ne+=`<div style="padding: 8px 12px; background: rgba(239, 68, 68, 0.1); border-radius: 6px; border-left: 3px solid #ef4444; font-family: 'Courier New', monospace; font-size: 13px; word-break: break-all; max-height: 200px; overflow-y: auto;">`+h(T.details.oldValue)+"</div>"),T.details.newValue!==void 0&&T.details.newValue!==null&&(ne+='<span style="color: var(--text-tertiary); font-weight: 500;">新值:</span>',ne+=`<div style="padding: 8px 12px; background: rgba(16, 185, 129, 0.1); border-radius: 6px; border-left: 3px solid #10b981; font-family: 'Courier New', monospace; font-size: 13px; word-break: break-all; max-height: 200px; overflow-y: auto;">`+h(T.details.newValue)+"</div>")),ne?(de.innerHTML=ne,document.getElementById("auditDetailsSection").style.display="block"):document.getElementById("auditDetailsSection").style.display="none",T.changes&&(((G=T.changes.insertions)==null?void 0:G.length)>0||((J=T.changes.deletions)==null?void 0:J.length)>0)){const pe=document.getElementById("auditChangesContent");let a="";if(T.changes.insertions&&T.changes.insertions.length>0){const e=T.changes.insertions.reduce((n,d)=>n+d.length,0);a+='<div style="flex: 1; padding: 12px; background: rgba(16, 185, 129, 0.1); border-radius: 8px; border-left: 3px solid #10b981;">',a+='<div style="font-weight: 600; color: #10b981; margin-bottom: 4px;">✅ 新增内容</div>',a+='<div style="color: var(--text-secondary);">共 '+e+" 个字符</div>",a+="</div>"}if(T.changes.deletions&&T.changes.deletions.length>0){const e=T.changes.deletions.reduce((n,d)=>n+d.length,0);a+='<div style="flex: 1; padding: 12px; background: rgba(239, 68, 68, 0.1); border-radius: 8px; border-left: 3px solid #ef4444;">',a+='<div style="font-weight: 600; color: #ef4444; margin-bottom: 4px;">❌ 删除内容</div>',a+='<div style="color: var(--text-secondary);">共 '+e+" 个字符</div>",a+="</div>"}pe.innerHTML=a,document.getElementById("auditChangesSection").style.display="block"}else document.getElementById("auditChangesSection").style.display="none";X.classList.remove("hidden")}catch(ee){alert("加载详情失败: "+ee.message)}},document.getElementById("applyFilters").addEventListener("click",()=>{w={groupId:document.getElementById("auditGroupFilter").value,action:document.getElementById("auditActionFilter").value,startDate:document.getElementById("startDate").value,endDate:document.getElementById("endDate").value},Object.keys(w).forEach(o=>{w[o]||delete w[o]}),x=1,B(x,w)}),document.getElementById("prevPage").addEventListener("click",()=>{x>1&&(x--,B(x,w))}),document.getElementById("nextPage").addEventListener("click",()=>{x++,B(x,w)}),document.getElementById("exportLogs").addEventListener("click",()=>{alert("导出功能开发中...")}),document.getElementById("clearAuditLogs").addEventListener("click",async()=>{const g=Object.keys(w||{}).length>0?"将清除当前筛选条件下的所有操作记录,确认继续?":"⚠️ 将清除全部操作记录(不可恢复),确认继续?";if(confirm(g))try{const b=await s.clearAuditLogs(w||{});alert(`已清除 ${b.deletedCount||0} 条操作记录`),x=1,await L(),await B(x,w)}catch(b){alert("清除失败: "+b.message)}}),document.getElementById("closeAuditDetail").addEventListener("click",()=>{document.getElementById("auditDetailModal").classList.add("hidden")}),L(),B()}async function se(v){if(!c){v.innerHTML=`
1170
+ `,document.getElementById("auditDescriptionText").innerHTML=k(T);const de=document.getElementById("auditDetailsContent");let ne="";if(T.details&&(T.details.field&&(ne+='<span style="color: var(--text-tertiary); font-weight: 500;">修改字段:</span>',ne+='<span style="font-weight: 600; color: var(--text-primary);">'+p(T.details.field)+"</span>"),T.details.oldValue!==void 0&&T.details.oldValue!==null&&(ne+='<span style="color: var(--text-tertiary); font-weight: 500;">原始值:</span>',ne+=`<div style="padding: 8px 12px; background: rgba(239, 68, 68, 0.1); border-radius: 6px; border-left: 3px solid #ef4444; font-family: 'Courier New', monospace; font-size: 13px; word-break: break-all; max-height: 200px; overflow-y: auto;">`+h(T.details.oldValue)+"</div>"),T.details.newValue!==void 0&&T.details.newValue!==null&&(ne+='<span style="color: var(--text-tertiary); font-weight: 500;">新值:</span>',ne+=`<div style="padding: 8px 12px; background: rgba(16, 185, 129, 0.1); border-radius: 6px; border-left: 3px solid #10b981; font-family: 'Courier New', monospace; font-size: 13px; word-break: break-all; max-height: 200px; overflow-y: auto;">`+h(T.details.newValue)+"</div>")),ne?(de.innerHTML=ne,document.getElementById("auditDetailsSection").style.display="block"):document.getElementById("auditDetailsSection").style.display="none",T.changes&&(((G=T.changes.insertions)==null?void 0:G.length)>0||((J=T.changes.deletions)==null?void 0:J.length)>0)){const pe=document.getElementById("auditChangesContent");let a="";if(T.changes.insertions&&T.changes.insertions.length>0){const e=T.changes.insertions.reduce((n,d)=>n+d.length,0);a+='<div style="flex: 1; padding: 12px; background: rgba(16, 185, 129, 0.1); border-radius: 8px; border-left: 3px solid #10b981;">',a+='<div style="font-weight: 600; color: #10b981; margin-bottom: 4px;">✅ 新增内容</div>',a+='<div style="color: var(--text-secondary);">共 '+e+" 个字符</div>",a+="</div>"}if(T.changes.deletions&&T.changes.deletions.length>0){const e=T.changes.deletions.reduce((n,d)=>n+d.length,0);a+='<div style="flex: 1; padding: 12px; background: rgba(239, 68, 68, 0.1); border-radius: 8px; border-left: 3px solid #ef4444;">',a+='<div style="font-weight: 600; color: #ef4444; margin-bottom: 4px;">❌ 删除内容</div>',a+='<div style="color: var(--text-secondary);">共 '+e+" 个字符</div>",a+="</div>"}pe.innerHTML=a,document.getElementById("auditChangesSection").style.display="block"}else document.getElementById("auditChangesSection").style.display="none";X.classList.remove("hidden")}catch(ee){alert("加载详情失败: "+ee.message)}},document.getElementById("applyFilters").addEventListener("click",()=>{w={groupId:document.getElementById("auditGroupFilter").value,action:document.getElementById("auditActionFilter").value,startDate:document.getElementById("startDate").value,endDate:document.getElementById("endDate").value},Object.keys(w).forEach(o=>{w[o]||delete w[o]}),b=1,B(b,w)}),document.getElementById("prevPage").addEventListener("click",()=>{b>1&&(b--,B(b,w))}),document.getElementById("nextPage").addEventListener("click",()=>{b++,B(b,w)}),document.getElementById("exportLogs").addEventListener("click",()=>{alert("导出功能开发中...")}),document.getElementById("clearAuditLogs").addEventListener("click",async()=>{const g=Object.keys(w||{}).length>0?"将清除当前筛选条件下的所有操作记录,确认继续?":"⚠️ 将清除全部操作记录(不可恢复),确认继续?";if(confirm(g))try{const f=await s.clearAuditLogs(w||{});alert(`已清除 ${f.deletedCount||0} 条操作记录`),b=1,await L(),await B(b,w)}catch(f){alert("清除失败: "+f.message)}}),document.getElementById("closeAuditDetail").addEventListener("click",()=>{document.getElementById("auditDetailModal").classList.add("hidden")}),L(),B()}async function se(v){if(!c){v.innerHTML=`
1171
1171
  <div class="empty-state" style="text-align: center; padding: 60px 20px;">
1172
1172
  <div style="font-size: 64px; margin-bottom: 20px;">🗳️</div>
1173
1173
  <h3 style="font-size: 24px; margin-bottom: 12px;">投票管理</h3>
1174
1174
  <p style="color: var(--text-secondary); margin-bottom: 24px;">请先选择一个群组</p>
1175
1175
  <button class="btn-primary" onclick="document.querySelector('[data-view=\\"groups\\"]').click()">前往群组管理</button>
1176
1176
  </div>
1177
- `;return}try{const x=localStorage.getItem("token"),w=await fetch(`http://localhost:3000/api/polls/group/${c._id}`,{headers:{Authorization:`Bearer ${x}`}});if(!w.ok)throw new Error("获取投票列表失败");const L=(await w.json()).polls||[];v.innerHTML=`
1177
+ `;return}try{const b=localStorage.getItem("token"),w=await fetch(`http://localhost:3000/api/polls/group/${c._id}`,{headers:{Authorization:`Bearer ${b}`}});if(!w.ok)throw new Error("获取投票列表失败");const L=(await w.json()).polls||[];v.innerHTML=`
1178
1178
  <div class="view-header">
1179
1179
  <h2>🗳️ 投票管理 - ${c.name}</h2>
1180
1180
  </div>
1181
1181
  <div class="polls-grid" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 20px; padding: 20px;">
1182
1182
  ${L.length===0?'<div class="empty-state" style="grid-column: 1/-1;">暂无投票</div>':""}
1183
1183
  </div>
1184
- `;const k=v.querySelector(".polls-grid");L.forEach(p=>{const h=p.options.reduce((b,E)=>b+E.votes.length,0),o=p.status==="ended"||p.endTime&&new Date(p.endTime)<new Date,g=document.createElement("div");g.className="poll-card",g.style.cssText="background: var(--bg-secondary); padding: 20px; border-radius: 12px; border: 1px solid var(--border); transition: transform 0.2s, box-shadow 0.2s;",g.innerHTML=`
1184
+ `;const k=v.querySelector(".polls-grid");L.forEach(p=>{const h=p.options.reduce((f,E)=>f+E.votes.length,0),o=p.status==="ended"||p.endTime&&new Date(p.endTime)<new Date,g=document.createElement("div");g.className="poll-card",g.style.cssText="background: var(--bg-secondary); padding: 20px; border-radius: 12px; border: 1px solid var(--border); transition: transform 0.2s, box-shadow 0.2s;",g.innerHTML=`
1185
1185
  <div style="display: flex; align-items: start; justify-content: space-between; margin-bottom: 15px;">
1186
1186
  <div style="flex: 1;">
1187
1187
  <h3 style="margin: 0 0 8px 0; font-size: 18px;">${p.title}</h3>
@@ -1203,11 +1203,11 @@
1203
1203
  </div>
1204
1204
 
1205
1205
  <div style="margin-bottom: 15px;">
1206
- ${p.options.map((b,E)=>{const C=h>0?(b.votes.length/h*100).toFixed(1):0;return`
1206
+ ${p.options.map((f,E)=>{const C=h>0?(f.votes.length/h*100).toFixed(1):0;return`
1207
1207
  <div style="margin-bottom: 10px;">
1208
1208
  <div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
1209
- <span style="font-size: 14px; color: var(--text-primary);">${b.text}</span>
1210
- <span style="font-size: 14px; font-weight: 600; color: var(--primary);">${b.votes.length} 票 (${C}%)</span>
1209
+ <span style="font-size: 14px; color: var(--text-primary);">${f.text}</span>
1210
+ <span style="font-size: 14px; font-weight: 600; color: var(--primary);">${f.votes.length} 票 (${C}%)</span>
1211
1211
  </div>
1212
1212
  <div style="height: 6px; background: var(--bg-tertiary); border-radius: 3px; overflow: hidden;">
1213
1213
  <div style="height: 100%; background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 100%); width: ${C}%; transition: width 0.3s;"></div>
@@ -1226,12 +1226,12 @@
1226
1226
  ${o?"":`<button class="btn-secondary btn-sm end-poll" data-poll-id="${p._id}">结束投票</button>`}
1227
1227
  <button class="btn-danger btn-sm delete-poll" data-poll-id="${p._id}">删除</button>
1228
1228
  </div>
1229
- `,g.onmouseenter=()=>{g.style.transform="translateY(-4px)",g.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},g.onmouseleave=()=>{g.style.transform="translateY(0)",g.style.boxShadow="none"},k.appendChild(g)}),document.querySelectorAll(".view-poll-detail").forEach(p=>{p.addEventListener("click",async()=>{const h=p.dataset.pollId;await ve(h)})}),document.querySelectorAll(".end-poll").forEach(p=>{p.addEventListener("click",async()=>{if(confirm("确定要结束这个投票吗?"))try{const h=localStorage.getItem("token");if(!(await fetch(`http://localhost:3000/api/polls/${p.dataset.pollId}/end`,{method:"PUT",headers:{Authorization:`Bearer ${h}`}})).ok)throw new Error("结束投票失败");alert("投票已结束!"),await se(v)}catch(h){alert("操作失败: "+h.message)}})}),document.querySelectorAll(".delete-poll").forEach(p=>{p.addEventListener("click",async()=>{if(confirm("确定要删除这个投票吗?"))try{const h=localStorage.getItem("token");if(!(await fetch(`http://localhost:3000/api/polls/${p.dataset.pollId}`,{method:"DELETE",headers:{Authorization:`Bearer ${h}`}})).ok)throw new Error("删除投票失败");alert("投票已删除!"),await se(v)}catch(h){alert("操作失败: "+h.message)}})})}catch(x){console.error("加载投票列表失败:",x),v.innerHTML=`
1229
+ `,g.onmouseenter=()=>{g.style.transform="translateY(-4px)",g.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},g.onmouseleave=()=>{g.style.transform="translateY(0)",g.style.boxShadow="none"},k.appendChild(g)}),document.querySelectorAll(".view-poll-detail").forEach(p=>{p.addEventListener("click",async()=>{const h=p.dataset.pollId;await ve(h)})}),document.querySelectorAll(".end-poll").forEach(p=>{p.addEventListener("click",async()=>{if(confirm("确定要结束这个投票吗?"))try{const h=localStorage.getItem("token");if(!(await fetch(`http://localhost:3000/api/polls/${p.dataset.pollId}/end`,{method:"PUT",headers:{Authorization:`Bearer ${h}`}})).ok)throw new Error("结束投票失败");alert("投票已结束!"),await se(v)}catch(h){alert("操作失败: "+h.message)}})}),document.querySelectorAll(".delete-poll").forEach(p=>{p.addEventListener("click",async()=>{if(confirm("确定要删除这个投票吗?"))try{const h=localStorage.getItem("token");if(!(await fetch(`http://localhost:3000/api/polls/${p.dataset.pollId}`,{method:"DELETE",headers:{Authorization:`Bearer ${h}`}})).ok)throw new Error("删除投票失败");alert("投票已删除!"),await se(v)}catch(h){alert("操作失败: "+h.message)}})})}catch(b){console.error("加载投票列表失败:",b),v.innerHTML=`
1230
1230
  <div class="view-header">
1231
1231
  <h2>🗳️ 投票管理</h2>
1232
1232
  </div>
1233
- <div class="empty-state">加载失败: ${x.message}</div>
1234
- `}}async function ve(v){try{const x=localStorage.getItem("token"),w=await fetch(`http://localhost:3000/api/polls/${v}`,{headers:{Authorization:`Bearer ${x}`}});if(!w.ok)throw new Error("获取投票详情失败");const L=(await w.json()).poll,k=L.options.reduce((g,b)=>g+b.votes.length,0),p=L.status==="ended"||L.endTime&&new Date(L.endTime)<new Date,h=`
1233
+ <div class="empty-state">加载失败: ${b.message}</div>
1234
+ `}}async function ve(v){try{const b=localStorage.getItem("token"),w=await fetch(`http://localhost:3000/api/polls/${v}`,{headers:{Authorization:`Bearer ${b}`}});if(!w.ok)throw new Error("获取投票详情失败");const L=(await w.json()).poll,k=L.options.reduce((g,f)=>g+f.votes.length,0),p=L.status==="ended"||L.endTime&&new Date(L.endTime)<new Date,h=`
1235
1235
  <div id="pollDetailModal" class="modal" style="display: flex;">
1236
1236
  <div class="modal-content" style="max-width: 800px; max-height: 90vh; overflow-y: auto;">
1237
1237
  <div class="modal-header">
@@ -1278,7 +1278,7 @@
1278
1278
  </div>
1279
1279
 
1280
1280
  <h3 style="margin-bottom: 16px;">投票选项</h3>
1281
- ${L.options.map((g,b)=>{const E=k>0?(g.votes.length/k*100).toFixed(1):0;return`
1281
+ ${L.options.map((g,f)=>{const E=k>0?(g.votes.length/k*100).toFixed(1):0;return`
1282
1282
  <div style="margin-bottom: 16px; padding: 16px; background: var(--bg-tertiary); border-radius: 8px;">
1283
1283
  <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
1284
1284
  <span style="font-weight: 500; font-size: 16px;">${g.text}</span>
@@ -1299,7 +1299,7 @@
1299
1299
  </div>
1300
1300
  </div>
1301
1301
  </div>
1302
- `,o=document.getElementById("pollDetailModal");o&&o.remove(),document.body.insertAdjacentHTML("beforeend",h),document.getElementById("closePollDetailModal").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()}),document.getElementById("closePollDetailBtn").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()})}catch(x){console.error("加载投票详情失败:",x),alert("加载投票详情失败: "+x.message)}}async function U(v){v.innerHTML=`
1302
+ `,o=document.getElementById("pollDetailModal");o&&o.remove(),document.body.insertAdjacentHTML("beforeend",h),document.getElementById("closePollDetailModal").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()}),document.getElementById("closePollDetailBtn").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()})}catch(b){console.error("加载投票详情失败:",b),alert("加载投票详情失败: "+b.message)}}async function P(v){v.innerHTML=`
1303
1303
  <div class="view-header">
1304
1304
  <h2>🔍 搜索</h2>
1305
1305
  </div>
@@ -1321,18 +1321,18 @@
1321
1321
  </div>
1322
1322
  <div class="search-results" id="searchResults"></div>
1323
1323
  </div>
1324
- `;const x=document.getElementById("searchInput"),w=document.getElementById("searchBtn"),B=document.getElementById("searchResults"),L=async()=>{const k=x.value.trim();if(!k){B.innerHTML='<div class="empty-state">请输入搜索关键词</div>';return}const p={messages:document.getElementById("filterMessages").checked,documents:document.getElementById("filterDocuments").checked,tasks:document.getElementById("filterTasks").checked};B.innerHTML='<div class="loading">搜索中...</div>';try{const h=[];if(p.messages&&c)try{const o=await s.getGroupMessages(c._id);o.messages&&o.messages.filter(b=>b.content.toLowerCase().includes(k.toLowerCase())).forEach(b=>{h.push({type:"message",title:`消息 - ${b.username}`,content:b.content,time:b.timestamp,group:c.name})})}catch(o){console.error("搜索消息失败:",o)}if(p.documents)try{if(c){const o=await s.getDocuments(c._id);o.documents&&o.documents.filter(b=>b.title.toLowerCase().includes(k.toLowerCase())||b.content.toLowerCase().includes(k.toLowerCase())).forEach(b=>{h.push({type:"document",title:b.title,content:b.content.substring(0,200),time:b.updatedAt,id:b._id,group:c.name})})}}catch(o){console.error("搜索文档失败:",o)}if(p.tasks&&c)try{const o=await s.getTasks(c._id);o.tasks&&o.tasks.filter(b=>b.title.toLowerCase().includes(k.toLowerCase())||b.description&&b.description.toLowerCase().includes(k.toLowerCase())).forEach(b=>{h.push({type:"task",title:b.title,content:b.description||"",time:b.updatedAt,id:b._id,status:b.status,group:c.name})})}catch(o){console.error("搜索任务失败:",o)}h.length===0?B.innerHTML='<div class="empty-state">未找到相关结果</div>':B.innerHTML=h.map(o=>`
1324
+ `;const b=document.getElementById("searchInput"),w=document.getElementById("searchBtn"),B=document.getElementById("searchResults"),L=async()=>{const k=b.value.trim();if(!k){B.innerHTML='<div class="empty-state">请输入搜索关键词</div>';return}const p={messages:document.getElementById("filterMessages").checked,documents:document.getElementById("filterDocuments").checked,tasks:document.getElementById("filterTasks").checked};B.innerHTML='<div class="loading">搜索中...</div>';try{const h=[];if(p.messages&&c)try{const o=await s.getGroupMessages(c._id);o.messages&&o.messages.filter(f=>f.content.toLowerCase().includes(k.toLowerCase())).forEach(f=>{h.push({type:"message",title:`消息 - ${f.username}`,content:f.content,time:f.timestamp,group:c.name})})}catch(o){console.error("搜索消息失败:",o)}if(p.documents)try{if(c){const o=await s.getDocuments(c._id);o.documents&&o.documents.filter(f=>f.title.toLowerCase().includes(k.toLowerCase())||f.content.toLowerCase().includes(k.toLowerCase())).forEach(f=>{h.push({type:"document",title:f.title,content:f.content.substring(0,200),time:f.updatedAt,id:f._id,group:c.name})})}}catch(o){console.error("搜索文档失败:",o)}if(p.tasks&&c)try{const o=await s.getTasks(c._id);o.tasks&&o.tasks.filter(f=>f.title.toLowerCase().includes(k.toLowerCase())||f.description&&f.description.toLowerCase().includes(k.toLowerCase())).forEach(f=>{h.push({type:"task",title:f.title,content:f.description||"",time:f.updatedAt,id:f._id,status:f.status,group:c.name})})}catch(o){console.error("搜索任务失败:",o)}h.length===0?B.innerHTML='<div class="empty-state">未找到相关结果</div>':B.innerHTML=h.map(o=>`
1325
1325
  <div class="search-result-item">
1326
1326
  <div class="result-header">
1327
1327
  <span class="result-type">${{message:"💬",document:"📄",task:"📋"}[o.type]} ${o.type==="message"?"消息":o.type==="document"?"文档":"任务"}</span>
1328
1328
  <span class="result-time">${new Date(o.time).toLocaleString()}</span>
1329
1329
  </div>
1330
- <h4>${z(o.title,k)}</h4>
1331
- <p>${z(o.content,k)}</p>
1330
+ <h4>${A(o.title,k)}</h4>
1331
+ <p>${A(o.content,k)}</p>
1332
1332
  ${o.group?`<span class="result-group">群组: ${o.group}</span>`:""}
1333
1333
  ${o.status?`<span class="result-status">状态: ${$(o.status)}</span>`:""}
1334
1334
  </div>
1335
- `).join("")}catch(h){B.innerHTML=`<div class="empty-state">搜索失败: ${h.message}</div>`}};w.addEventListener("click",L),x.addEventListener("keypress",k=>{k.key==="Enter"&&L()})}function z(v,x){if(!x)return v;const w=new RegExp(`(${x})`,"gi");return v.replace(w,"<mark>$1</mark>")}function V(v){return{document_create:"创建文档",document_update:"更新文档",document_delete:"删除文档",content_edit:"编辑内容",title_edit:"修改标题",document_permission_change:"权限修改"}[v]||v}function $(v){return{pending:"待处理",in_progress:"进行中",completed:"已完成",terminated:"已终止"}[v]||v}async function M(v){var x;if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const w=localStorage.getItem("token"),B=await fetch(`http://localhost:3000/api/knowledge/group/${c._id}`,{headers:{Authorization:`Bearer ${w}`}});if(!B.ok)throw new Error(`HTTP ${B.status}: ${B.statusText}`);const L=await B.json();console.log("知识库数据:",L);const k=((x=L.data)==null?void 0:x.knowledgeList)||[];console.log("知识库条目数量:",k.length),v.innerHTML=`
1335
+ `).join("")}catch(h){B.innerHTML=`<div class="empty-state">搜索失败: ${h.message}</div>`}};w.addEventListener("click",L),b.addEventListener("keypress",k=>{k.key==="Enter"&&L()})}function A(v,b){if(!b)return v;const w=new RegExp(`(${b})`,"gi");return v.replace(w,"<mark>$1</mark>")}function V(v){return{document_create:"创建文档",document_update:"更新文档",document_delete:"删除文档",content_edit:"编辑内容",title_edit:"修改标题",document_permission_change:"权限修改"}[v]||v}function $(v){return{pending:"待处理",in_progress:"进行中",completed:"已完成",terminated:"已终止"}[v]||v}async function M(v){var b;if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const w=localStorage.getItem("token"),B=await fetch(`http://localhost:3000/api/knowledge/group/${c._id}`,{headers:{Authorization:`Bearer ${w}`}});if(!B.ok)throw new Error(`HTTP ${B.status}: ${B.statusText}`);const L=await B.json();console.log("知识库数据:",L);const k=((b=L.data)==null?void 0:b.knowledgeList)||[];console.log("知识库条目数量:",k.length),v.innerHTML=`
1336
1336
  <div class="view-header">
1337
1337
  <h2>📚 知识库管理 - ${c.name}</h2>
1338
1338
  <button class="btn-primary" id="createKnowledgeBtn">➕ 创建知识条目</button>
@@ -1381,14 +1381,14 @@
1381
1381
  </div>
1382
1382
  ${h.tags&&h.tags.length>0?`
1383
1383
  <div class="tags" style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 15px;">
1384
- ${h.tags.map(b=>`<span class="tag" style="background: var(--primary); color: white; padding: 4px 10px; border-radius: 12px; font-size: 12px;">${b}</span>`).join("")}
1384
+ ${h.tags.map(f=>`<span class="tag" style="background: var(--primary); color: white; padding: 4px 10px; border-radius: 12px; font-size: 12px;">${f}</span>`).join("")}
1385
1385
  </div>
1386
1386
  `:""}
1387
1387
  <div style="display: flex; gap: 10px;">
1388
1388
  <button class="btn-secondary btn-sm" data-id="${h._id}" data-action="edit" style="flex: 1;">✏️ 编辑</button>
1389
1389
  <button class="btn-danger btn-sm" data-id="${h._id}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
1390
1390
  </div>
1391
- `,o.onmouseenter=()=>{o.style.transform="translateY(-4px)",o.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},o.onmouseleave=()=>{o.style.transform="translateY(0)",o.style.boxShadow="none"},p.appendChild(o)}),document.querySelectorAll('[data-action="edit"]').forEach(h=>{h.addEventListener("click",async()=>{var g;const o=k.find(b=>b._id===h.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=o.title,document.querySelector('[name="content"]').value=o.content,document.querySelector('[name="tags"]').value=((g=o.tags)==null?void 0:g.join(", "))||"",document.getElementById("isSharedCheckbox").checked=o.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=o._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="download"]').forEach(h=>{h.addEventListener("click",async()=>{try{const o=await fetch(`http://localhost:3000/api/backup/download/${h.dataset.filename}`,{method:"GET",headers:{Authorization:`Bearer ${w}`}});if(!o.ok)throw new Error("下载失败");const g=await o.blob(),b=window.URL.createObjectURL(g),E=document.createElement("a");E.href=b,E.download=h.dataset.filename,document.body.appendChild(E),E.click(),window.URL.revokeObjectURL(b),document.body.removeChild(E)}catch(o){alert("下载失败: "+o.message)}})}),document.querySelectorAll('[data-action="delete"]').forEach(h=>{h.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:3000/api/knowledge/${h.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${w}`}}),alert("删除成功!"),await M(v)}catch(o){alert("删除失败: "+o.message)}})})),document.getElementById("createKnowledgeBtn").addEventListener("click",()=>{document.getElementById("modalTitle").textContent="创建知识条目",document.getElementById("knowledgeForm").reset(),delete document.getElementById("knowledgeForm").dataset.editId,document.getElementById("knowledgeModal").classList.remove("hidden")}),document.getElementById("closeKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("knowledgeForm").addEventListener("submit",async h=>{h.preventDefault();const o=new FormData(h.target),g={title:o.get("title"),content:o.get("content"),tags:o.get("tags").split(",").map(b=>b.trim()).filter(b=>b),groupId:c._id,isShared:document.getElementById("isSharedCheckbox").checked};try{const b=h.target.dataset.editId,E=b?`http://localhost:3000/api/knowledge/${b}`:"http://localhost:3000/api/knowledge",G=await fetch(E,{method:b?"PUT":"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},body:JSON.stringify(g)});if(!G.ok){const ee=await G.json();throw new Error(ee.message||"操作失败")}const J=await G.json();console.log("知识库操作结果:",J),alert(b?"更新成功!":"创建成功!"),document.getElementById("knowledgeModal").classList.add("hidden"),await M(v)}catch(b){console.error("知识库操作错误:",b),alert("操作失败: "+b.message)}})}catch(w){v.innerHTML=`<div class="empty-state">加载失败: ${w.message}</div>`}}function N(v){if(!v)return"未设置";if(typeof v=="string")return{document_create:"📄 文档创建时",document_update:"✏️ 文档更新时",document_delete:"🗑️ 文档删除时",task_create:"📋 任务创建时",task_complete:"✅ 任务完成时",task_overdue:"⏰ 任务逾期时",member_join:"👥 成员加入时",group_create:"🏢 群组创建时",scheduled:"⏱️ 定时触发",manual:"🖱️ 手动触发"}[v]||v;const x=[];if(v.event){const w={document_created:"📄 文档创建",document_updated:"✏️ 文档更新",document_deleted:"🗑️ 文档删除",task_created:"📋 任务创建",task_completed:"✅ 任务完成",task_overdue:"⏰ 任务逾期",member_joined:"👥 成员加入",group_created:"🏢 群组创建",message_sent:"💬 消息发送",file_uploaded:"📎 文件上传"};x.push(w[v.event]||v.event)}if(v.conditions&&Object.keys(v.conditions).length>0){const w=[];for(const[B,L]of Object.entries(v.conditions)){const p={group:"群组",user:"用户",keyword:"关键词",status:"状态",priority:"优先级"}[B]||B;w.push(`${p}=${L}`)}w.length>0&&x.push(`(条件: ${w.join(", ")})`)}return v.schedule&&x.push(`⏱️ 定时: ${v.schedule}`),x.length>0?x.join(" "):"自定义触发条件"}async function H(v){var x;if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const w=localStorage.getItem("token"),k=((x=(await(await fetch(`http://localhost:3000/api/workflows/group/${c._id}`,{headers:{Authorization:`Bearer ${w}`}})).json()).data)==null?void 0:x.workflows)||[];v.innerHTML=`
1391
+ `,o.onmouseenter=()=>{o.style.transform="translateY(-4px)",o.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},o.onmouseleave=()=>{o.style.transform="translateY(0)",o.style.boxShadow="none"},p.appendChild(o)}),document.querySelectorAll('[data-action="edit"]').forEach(h=>{h.addEventListener("click",async()=>{var g;const o=k.find(f=>f._id===h.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=o.title,document.querySelector('[name="content"]').value=o.content,document.querySelector('[name="tags"]').value=((g=o.tags)==null?void 0:g.join(", "))||"",document.getElementById("isSharedCheckbox").checked=o.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=o._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="download"]').forEach(h=>{h.addEventListener("click",async()=>{try{const o=await fetch(`http://localhost:3000/api/backup/download/${h.dataset.filename}`,{method:"GET",headers:{Authorization:`Bearer ${w}`}});if(!o.ok)throw new Error("下载失败");const g=await o.blob(),f=window.URL.createObjectURL(g),E=document.createElement("a");E.href=f,E.download=h.dataset.filename,document.body.appendChild(E),E.click(),window.URL.revokeObjectURL(f),document.body.removeChild(E)}catch(o){alert("下载失败: "+o.message)}})}),document.querySelectorAll('[data-action="delete"]').forEach(h=>{h.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:3000/api/knowledge/${h.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${w}`}}),alert("删除成功!"),await M(v)}catch(o){alert("删除失败: "+o.message)}})})),document.getElementById("createKnowledgeBtn").addEventListener("click",()=>{document.getElementById("modalTitle").textContent="创建知识条目",document.getElementById("knowledgeForm").reset(),delete document.getElementById("knowledgeForm").dataset.editId,document.getElementById("knowledgeModal").classList.remove("hidden")}),document.getElementById("closeKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("knowledgeForm").addEventListener("submit",async h=>{h.preventDefault();const o=new FormData(h.target),g={title:o.get("title"),content:o.get("content"),tags:o.get("tags").split(",").map(f=>f.trim()).filter(f=>f),groupId:c._id,isShared:document.getElementById("isSharedCheckbox").checked};try{const f=h.target.dataset.editId,E=f?`http://localhost:3000/api/knowledge/${f}`:"http://localhost:3000/api/knowledge",G=await fetch(E,{method:f?"PUT":"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},body:JSON.stringify(g)});if(!G.ok){const ee=await G.json();throw new Error(ee.message||"操作失败")}const J=await G.json();console.log("知识库操作结果:",J),alert(f?"更新成功!":"创建成功!"),document.getElementById("knowledgeModal").classList.add("hidden"),await M(v)}catch(f){console.error("知识库操作错误:",f),alert("操作失败: "+f.message)}})}catch(w){v.innerHTML=`<div class="empty-state">加载失败: ${w.message}</div>`}}function N(v){if(!v)return"未设置";if(typeof v=="string")return{document_create:"📄 文档创建时",document_update:"✏️ 文档更新时",document_delete:"🗑️ 文档删除时",task_create:"📋 任务创建时",task_complete:"✅ 任务完成时",task_overdue:"⏰ 任务逾期时",member_join:"👥 成员加入时",group_create:"🏢 群组创建时",scheduled:"⏱️ 定时触发",manual:"🖱️ 手动触发"}[v]||v;const b=[];if(v.event){const w={document_created:"📄 文档创建",document_updated:"✏️ 文档更新",document_deleted:"🗑️ 文档删除",task_created:"📋 任务创建",task_completed:"✅ 任务完成",task_overdue:"⏰ 任务逾期",member_joined:"👥 成员加入",group_created:"🏢 群组创建",message_sent:"💬 消息发送",file_uploaded:"📎 文件上传"};b.push(w[v.event]||v.event)}if(v.conditions&&Object.keys(v.conditions).length>0){const w=[];for(const[B,L]of Object.entries(v.conditions)){const p={group:"群组",user:"用户",keyword:"关键词",status:"状态",priority:"优先级"}[B]||B;w.push(`${p}=${L}`)}w.length>0&&b.push(`(条件: ${w.join(", ")})`)}return v.schedule&&b.push(`⏱️ 定时: ${v.schedule}`),b.length>0?b.join(" "):"自定义触发条件"}async function H(v){var b;if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const w=localStorage.getItem("token"),k=((b=(await(await fetch(`http://localhost:3000/api/workflows/group/${c._id}`,{headers:{Authorization:`Bearer ${w}`}})).json()).data)==null?void 0:b.workflows)||[];v.innerHTML=`
1392
1392
  <div class="view-header">
1393
1393
  <h2>⚙️ 工作流管理 - ${c.name}</h2>
1394
1394
  <button class="btn-primary" id="createWorkflowBtn">➕ 创建工作流</button>
@@ -1468,7 +1468,7 @@
1468
1468
  </button>
1469
1469
  <button class="btn-danger btn-sm" data-id="${h._id}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
1470
1470
  </div>
1471
- `,o.onmouseenter=()=>{o.style.transform="translateY(-4px)",o.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},o.onmouseleave=()=>{o.style.transform="translateY(0)",o.style.boxShadow="none"},p.appendChild(o)}),document.querySelectorAll('[data-action="toggle"]').forEach(h=>{h.addEventListener("click",async()=>{try{await fetch(`http://localhost:3000/api/workflows/${h.dataset.id}/toggle`,{method:"POST",headers:{Authorization:`Bearer ${w}`}}),await H(v)}catch(o){alert("操作失败: "+o.message)}})}),document.querySelectorAll('[data-action="delete"]').forEach(h=>{h.addEventListener("click",async()=>{if(confirm("确定要删除这个工作流吗?"))try{await fetch(`http://localhost:3000/api/workflows/${h.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${w}`}}),alert("删除成功!"),await H(v)}catch(o){alert("删除失败: "+o.message)}})})),document.getElementById("createWorkflowBtn").addEventListener("click",()=>{document.getElementById("workflowModal").classList.remove("hidden")}),document.getElementById("closeWorkflowModal").addEventListener("click",()=>{document.getElementById("workflowModal").classList.add("hidden")}),document.getElementById("workflowForm").addEventListener("submit",async h=>{h.preventDefault();const o=new FormData(h.target),g={name:o.get("name"),description:o.get("description"),trigger:o.get("trigger"),groupId:c._id,actions:[]};try{await fetch("http://localhost:3000/api/workflows",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},body:JSON.stringify(g)}),alert("创建成功!"),document.getElementById("workflowModal").classList.add("hidden"),await H(v)}catch(b){alert("创建失败: "+b.message)}})}catch(w){v.innerHTML=`<div class="empty-state">加载失败: ${w.message}</div>`}}async function _(v){var x;try{const w=localStorage.getItem("token"),k=((x=(await(await fetch("http://localhost:3000/api/backup/list",{headers:{Authorization:`Bearer ${w}`}})).json()).data)==null?void 0:x.backups)||[];v.innerHTML=`
1471
+ `,o.onmouseenter=()=>{o.style.transform="translateY(-4px)",o.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},o.onmouseleave=()=>{o.style.transform="translateY(0)",o.style.boxShadow="none"},p.appendChild(o)}),document.querySelectorAll('[data-action="toggle"]').forEach(h=>{h.addEventListener("click",async()=>{try{await fetch(`http://localhost:3000/api/workflows/${h.dataset.id}/toggle`,{method:"POST",headers:{Authorization:`Bearer ${w}`}}),await H(v)}catch(o){alert("操作失败: "+o.message)}})}),document.querySelectorAll('[data-action="delete"]').forEach(h=>{h.addEventListener("click",async()=>{if(confirm("确定要删除这个工作流吗?"))try{await fetch(`http://localhost:3000/api/workflows/${h.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${w}`}}),alert("删除成功!"),await H(v)}catch(o){alert("删除失败: "+o.message)}})})),document.getElementById("createWorkflowBtn").addEventListener("click",()=>{document.getElementById("workflowModal").classList.remove("hidden")}),document.getElementById("closeWorkflowModal").addEventListener("click",()=>{document.getElementById("workflowModal").classList.add("hidden")}),document.getElementById("workflowForm").addEventListener("submit",async h=>{h.preventDefault();const o=new FormData(h.target),g={name:o.get("name"),description:o.get("description"),trigger:o.get("trigger"),groupId:c._id,actions:[]};try{await fetch("http://localhost:3000/api/workflows",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${w}`},body:JSON.stringify(g)}),alert("创建成功!"),document.getElementById("workflowModal").classList.add("hidden"),await H(v)}catch(f){alert("创建失败: "+f.message)}})}catch(w){v.innerHTML=`<div class="empty-state">加载失败: ${w.message}</div>`}}async function _(v){var b;try{const w=localStorage.getItem("token"),k=((b=(await(await fetch("http://localhost:3000/api/backup/list",{headers:{Authorization:`Bearer ${w}`}})).json()).data)==null?void 0:b.backups)||[];v.innerHTML=`
1472
1472
  <div class="view-header">
1473
1473
  <h2>💾 备份管理</h2>
1474
1474
  <button class="btn-primary" id="createBackupBtn">➕ 创建备份</button>
@@ -1489,7 +1489,7 @@
1489
1489
  <button class="btn-primary btn-sm" data-backup-name="${h.name}" data-filename="${h.filename}" data-action="download" style="flex: 1;">⬇️ 下载</button>
1490
1490
  <button class="btn-danger btn-sm" data-backup-name="${h.name}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
1491
1491
  </div>
1492
- `,o.onmouseenter=()=>{o.style.transform="translateY(-4px)",o.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},o.onmouseleave=()=>{o.style.transform="translateY(0)",o.style.boxShadow="none"},p.appendChild(o)}),document.querySelectorAll('[data-action="download"]').forEach(h=>{h.addEventListener("click",async()=>{try{const o=h.dataset.backupName,g=h.dataset.filename,b=localStorage.getItem("token");console.log("开始下载备份:",{backupName:o,filename:g});const E=await fetch(`http://localhost:3000/api/backup/download/${o}`,{method:"GET",headers:{Authorization:`Bearer ${b}`}});if(!E.ok)throw new Error(`下载失败: ${E.status} ${E.statusText}`);const C=await E.blob();console.log("文件下载成功,大小:",C.size,"bytes");const G=window.URL.createObjectURL(C),J=document.createElement("a");J.href=G,J.download=g,J.style.display="none",document.body.appendChild(J),J.click(),setTimeout(()=>{document.body.removeChild(J),window.URL.revokeObjectURL(G)},100);const ee=h.textContent;h.textContent="✅ 下载成功",h.disabled=!0,setTimeout(()=>{h.textContent=ee,h.disabled=!1},2e3)}catch(o){console.error("下载失败:",o),alert("下载失败: "+o.message),h.textContent="⬇️ 下载",h.disabled=!1}})}),document.querySelectorAll('[data-action="delete"]').forEach(h=>{h.addEventListener("click",async()=>{if(confirm("确定要删除这个备份吗?"))try{const o=h.dataset.backupName;console.log("删除备份:",o);const g=await fetch(`http://localhost:3000/api/backup/${o}`,{method:"DELETE",headers:{Authorization:`Bearer ${w}`}});if(!g.ok)throw new Error(`删除失败: ${g.status}`);alert("删除成功!"),await _(v)}catch(o){console.error("删除失败:",o),alert("删除失败: "+o.message)}})})),document.getElementById("createBackupBtn").addEventListener("click",async()=>{if(confirm("确定要创建新备份吗?这可能需要一些时间。")){const h=document.getElementById("createBackupBtn");h.disabled=!0,h.textContent="⏳ 创建中...";try{await fetch("http://localhost:3000/api/backup/create",{method:"POST",headers:{Authorization:`Bearer ${w}`}}),alert("备份创建成功!"),await _(v)}catch(o){alert("创建失败: "+o.message)}finally{h.disabled=!1,h.textContent="➕ 创建备份"}}})}catch(w){v.innerHTML=`<div class="empty-state">加载失败: ${w.message}</div>`}}async function O(v){v.innerHTML='<div class="empty-state">AI助手功能开发中...</div>'}async function Z(v){v.innerHTML=`
1492
+ `,o.onmouseenter=()=>{o.style.transform="translateY(-4px)",o.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},o.onmouseleave=()=>{o.style.transform="translateY(0)",o.style.boxShadow="none"},p.appendChild(o)}),document.querySelectorAll('[data-action="download"]').forEach(h=>{h.addEventListener("click",async()=>{try{const o=h.dataset.backupName,g=h.dataset.filename,f=localStorage.getItem("token");console.log("开始下载备份:",{backupName:o,filename:g});const E=await fetch(`http://localhost:3000/api/backup/download/${o}`,{method:"GET",headers:{Authorization:`Bearer ${f}`}});if(!E.ok)throw new Error(`下载失败: ${E.status} ${E.statusText}`);const C=await E.blob();console.log("文件下载成功,大小:",C.size,"bytes");const G=window.URL.createObjectURL(C),J=document.createElement("a");J.href=G,J.download=g,J.style.display="none",document.body.appendChild(J),J.click(),setTimeout(()=>{document.body.removeChild(J),window.URL.revokeObjectURL(G)},100);const ee=h.textContent;h.textContent="✅ 下载成功",h.disabled=!0,setTimeout(()=>{h.textContent=ee,h.disabled=!1},2e3)}catch(o){console.error("下载失败:",o),alert("下载失败: "+o.message),h.textContent="⬇️ 下载",h.disabled=!1}})}),document.querySelectorAll('[data-action="delete"]').forEach(h=>{h.addEventListener("click",async()=>{if(confirm("确定要删除这个备份吗?"))try{const o=h.dataset.backupName;console.log("删除备份:",o);const g=await fetch(`http://localhost:3000/api/backup/${o}`,{method:"DELETE",headers:{Authorization:`Bearer ${w}`}});if(!g.ok)throw new Error(`删除失败: ${g.status}`);alert("删除成功!"),await _(v)}catch(o){console.error("删除失败:",o),alert("删除失败: "+o.message)}})})),document.getElementById("createBackupBtn").addEventListener("click",async()=>{if(confirm("确定要创建新备份吗?这可能需要一些时间。")){const h=document.getElementById("createBackupBtn");h.disabled=!0,h.textContent="⏳ 创建中...";try{await fetch("http://localhost:3000/api/backup/create",{method:"POST",headers:{Authorization:`Bearer ${w}`}}),alert("备份创建成功!"),await _(v)}catch(o){alert("创建失败: "+o.message)}finally{h.disabled=!1,h.textContent="➕ 创建备份"}}})}catch(w){v.innerHTML=`<div class="empty-state">加载失败: ${w.message}</div>`}}async function O(v){v.innerHTML='<div class="empty-state">AI助手功能开发中...</div>'}async function Z(v){v.innerHTML=`
1493
1493
  <div class="view-header">
1494
1494
  <h2>📤 数据导出</h2>
1495
1495
  </div>
@@ -1534,7 +1534,7 @@
1534
1534
  <div id="historyList">加载中...</div>
1535
1535
  </div>
1536
1536
  </div>
1537
- `;try{const x=localStorage.getItem("token"),B=await(await fetch("http://localhost:3000/api/export/history",{headers:{Authorization:`Bearer ${x}`}})).json(),L=document.getElementById("historyList");B.exports&&B.exports.length>0?L.innerHTML=B.exports.map(k=>`
1537
+ `;try{const b=localStorage.getItem("token"),B=await(await fetch("http://localhost:3000/api/export/history",{headers:{Authorization:`Bearer ${b}`}})).json(),L=document.getElementById("historyList");B.exports&&B.exports.length>0?L.innerHTML=B.exports.map(k=>`
1538
1538
  <div class="export-item" style="display: flex; justify-content: space-between; align-items: center; padding: 15px; background: var(--bg); border-radius: 8px; margin-bottom: 10px;">
1539
1539
  <div>
1540
1540
  <div style="font-weight: 600; margin-bottom: 5px;">📦 ${k.format.toUpperCase()} 导出</div>
@@ -1542,7 +1542,7 @@
1542
1542
  </div>
1543
1543
  <a href="http://localhost:3000/api/export/download/${k.filename}" class="btn-sm btn-primary" download style="text-decoration: none;">⬇️ 下载</a>
1544
1544
  </div>
1545
- `).join(""):L.innerHTML='<div class="empty-state">暂无导出记录</div>'}catch{document.getElementById("historyList").innerHTML='<div class="empty-state">加载失败</div>'}document.getElementById("exportBtn").addEventListener("click",async()=>{const x={groups:document.getElementById("exportGroups").checked,documents:document.getElementById("exportDocuments").checked,tasks:document.getElementById("exportTasks").checked,messages:document.getElementById("exportMessages").checked,files:document.getElementById("exportFiles").checked,format:document.getElementById("exportFormat").value},w=document.getElementById("exportBtn");w.disabled=!0,w.textContent="⏳ 导出中...";try{const B=localStorage.getItem("token"),L=await fetch("http://localhost:3000/api/export",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${B}`},body:JSON.stringify(x)});if(L.ok){const k=await L.blob(),p=window.URL.createObjectURL(k),h=document.createElement("a");h.href=p,h.download=`export-${Date.now()}.${x.format}`,h.click(),alert("导出成功!"),await Z(v)}else throw new Error("导出失败")}catch(B){alert("导出失败: "+B.message)}finally{w.disabled=!1,w.textContent="🚀 开始导出"}})}async function Y(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}v.innerHTML=`
1545
+ `).join(""):L.innerHTML='<div class="empty-state">暂无导出记录</div>'}catch{document.getElementById("historyList").innerHTML='<div class="empty-state">加载失败</div>'}document.getElementById("exportBtn").addEventListener("click",async()=>{const b={groups:document.getElementById("exportGroups").checked,documents:document.getElementById("exportDocuments").checked,tasks:document.getElementById("exportTasks").checked,messages:document.getElementById("exportMessages").checked,files:document.getElementById("exportFiles").checked,format:document.getElementById("exportFormat").value},w=document.getElementById("exportBtn");w.disabled=!0,w.textContent="⏳ 导出中...";try{const B=localStorage.getItem("token"),L=await fetch("http://localhost:3000/api/export",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${B}`},body:JSON.stringify(b)});if(L.ok){const k=await L.blob(),p=window.URL.createObjectURL(k),h=document.createElement("a");h.href=p,h.download=`export-${Date.now()}.${b.format}`,h.click(),alert("导出成功!"),await Z(v)}else throw new Error("导出失败")}catch(B){alert("导出失败: "+B.message)}finally{w.disabled=!1,w.textContent="🚀 开始导出"}})}async function Y(v){if(!c){v.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}v.innerHTML=`
1546
1546
  <div class="view-header">
1547
1547
  <h2>🎨 协作白板 - ${c.name}</h2>
1548
1548
  <div style="display: flex; gap: 10px;">
@@ -1564,7 +1564,7 @@
1564
1564
  <span class="user-badge">👤 ${r.username}</span>
1565
1565
  </div>
1566
1566
  </div>
1567
- `;const x=document.getElementById("whiteboard"),w=x.getContext("2d");let B=!1,L="pen",k="#000000",p=3;document.querySelectorAll(".tool-btn").forEach(g=>{g.addEventListener("click",()=>{document.querySelectorAll(".tool-btn").forEach(b=>b.classList.remove("active")),g.classList.add("active"),L=g.dataset.tool})}),document.getElementById("colorPicker").addEventListener("change",g=>{k=g.target.value}),document.getElementById("brushSize").addEventListener("input",g=>{p=g.target.value});let h=0,o=0;x.addEventListener("mousedown",g=>{B=!0;const b=x.getBoundingClientRect();h=g.clientX-b.left,o=g.clientY-b.top}),x.addEventListener("mousemove",g=>{if(!B)return;const b=x.getBoundingClientRect(),E=g.clientX-b.left,C=g.clientY-b.top;w.beginPath(),w.moveTo(h,o),w.lineTo(E,C),w.strokeStyle=L==="eraser"?"#ffffff":k,w.lineWidth=p,w.lineCap="round",w.stroke(),h=E,o=C,t.sendWhiteboardData(c._id,{tool:L,color:k,size:p,from:{x:h,y:o},to:{x:E,y:C}})}),x.addEventListener("mouseup",()=>{B=!1}),x.addEventListener("mouseleave",()=>{B=!1}),document.getElementById("clearCanvas").addEventListener("click",()=>{confirm("确定要清空画布吗?")&&w.clearRect(0,0,x.width,x.height)}),document.getElementById("saveCanvas").addEventListener("click",()=>{const g=x.toDataURL("image/png"),b=document.createElement("a");b.download=`whiteboard-${Date.now()}.png`,b.href=g,b.click(),alert("白板已保存!")}),t.on("whiteboard_draw",g=>{g.groupId===c._id&&g.userId!==l&&(w.beginPath(),w.moveTo(g.from.x,g.from.y),w.lineTo(g.to.x,g.to.y),w.strokeStyle=g.tool==="eraser"?"#ffffff":g.color,w.lineWidth=g.size,w.lineCap="round",w.stroke())})}async function fe(v){v.innerHTML=`
1567
+ `;const b=document.getElementById("whiteboard"),w=b.getContext("2d");let B=!1,L="pen",k="#000000",p=3;document.querySelectorAll(".tool-btn").forEach(g=>{g.addEventListener("click",()=>{document.querySelectorAll(".tool-btn").forEach(f=>f.classList.remove("active")),g.classList.add("active"),L=g.dataset.tool})}),document.getElementById("colorPicker").addEventListener("change",g=>{k=g.target.value}),document.getElementById("brushSize").addEventListener("input",g=>{p=g.target.value});let h=0,o=0;b.addEventListener("mousedown",g=>{B=!0;const f=b.getBoundingClientRect();h=g.clientX-f.left,o=g.clientY-f.top}),b.addEventListener("mousemove",g=>{if(!B)return;const f=b.getBoundingClientRect(),E=g.clientX-f.left,C=g.clientY-f.top;w.beginPath(),w.moveTo(h,o),w.lineTo(E,C),w.strokeStyle=L==="eraser"?"#ffffff":k,w.lineWidth=p,w.lineCap="round",w.stroke(),h=E,o=C,t.sendWhiteboardData(c._id,{tool:L,color:k,size:p,from:{x:h,y:o},to:{x:E,y:C}})}),b.addEventListener("mouseup",()=>{B=!1}),b.addEventListener("mouseleave",()=>{B=!1}),document.getElementById("clearCanvas").addEventListener("click",()=>{confirm("确定要清空画布吗?")&&w.clearRect(0,0,b.width,b.height)}),document.getElementById("saveCanvas").addEventListener("click",()=>{const g=b.toDataURL("image/png"),f=document.createElement("a");f.download=`whiteboard-${Date.now()}.png`,f.href=g,f.click(),alert("白板已保存!")}),t.on("whiteboard_draw",g=>{g.groupId===c._id&&g.userId!==l&&(w.beginPath(),w.moveTo(g.from.x,g.from.y),w.lineTo(g.to.x,g.to.y),w.strokeStyle=g.tool==="eraser"?"#ffffff":g.color,w.lineWidth=g.size,w.lineCap="round",w.stroke())})}async function xe(v){v.innerHTML=`
1568
1568
  <div class="view-header" style="margin-bottom: 30px;">
1569
1569
  <h2 style="display: flex; align-items: center; gap: 12px; font-size: 28px;">
1570
1570
  <span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">⚙️ 设置中心</span>
@@ -1660,7 +1660,7 @@
1660
1660
  <button class="btn-primary" id="saveSettingsBtn" style="padding: 12px 32px; border-radius: 10px; font-weight: 600; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; cursor: pointer; transition: transform 0.2s;">💾 保存设置</button>
1661
1661
  </div>
1662
1662
  </div>
1663
- `,document.querySelectorAll(".settings-card").forEach(w=>{w.addEventListener("mouseenter",()=>{w.style.transform="translateY(-4px)",w.style.boxShadow="0 8px 24px rgba(0,0,0,0.12)"}),w.addEventListener("mouseleave",()=>{w.style.transform="translateY(0)",w.style.boxShadow="0 2px 8px rgba(0,0,0,0.05)"})}),document.querySelectorAll('input[type="email"], select').forEach(w=>{w.addEventListener("focus",()=>{w.style.borderColor="var(--primary)"}),w.addEventListener("blur",()=>{w.style.borderColor="var(--border)"})}),document.getElementById("changePasswordBtn").addEventListener("click",()=>{prompt("请输入新密码:")&&alert("密码修改功能开发中...")}),document.getElementById("resetSettingsBtn").addEventListener("click",()=>{confirm("确定要重置所有设置吗?")&&location.reload()}),document.getElementById("saveSettingsBtn").addEventListener("click",()=>{const w={email:document.getElementById("userEmail").value,emailNotifications:document.getElementById("emailNotifications").checked,desktopNotifications:document.getElementById("desktopNotifications").checked,soundNotifications:document.getElementById("soundNotifications").checked,theme:document.getElementById("themeSelect").value,language:document.getElementById("languageSelect").value};localStorage.setItem("userSettings",JSON.stringify(w)),ie(w.theme),alert("✅ 设置已保存!")}),document.getElementById("themeSelect").addEventListener("change",w=>{ie(w.target.value)});const x=localStorage.getItem("userSettings");if(x){const w=JSON.parse(x);w.email&&(document.getElementById("userEmail").value=w.email),document.getElementById("emailNotifications").checked=w.emailNotifications!==!1,document.getElementById("desktopNotifications").checked=w.desktopNotifications!==!1,document.getElementById("soundNotifications").checked=w.soundNotifications!==!1,w.theme&&(document.getElementById("themeSelect").value=w.theme,ie(w.theme)),w.language&&(document.getElementById("languageSelect").value=w.language)}}function ie(v){const x=document.documentElement,w={dark:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#0f172a",bgCard:"#1e293b",bgHover:"#334155",textPrimary:"#f1f5f9",textSecondary:"#94a3b8",border:"#334155"},blue:{primary:"#3b82f6",primaryDark:"#2563eb",secondary:"#06b6d4",bgDark:"#0c1222",bgCard:"#1a2332",bgHover:"#2a3442",textPrimary:"#e0f2fe",textSecondary:"#7dd3fc",border:"#2a3442"},green:{primary:"#10b981",primaryDark:"#059669",secondary:"#34d399",bgDark:"#0a1f1a",bgCard:"#1a2f2a",bgHover:"#2a3f3a",textPrimary:"#d1fae5",textSecondary:"#6ee7b7",border:"#2a3f3a"},orange:{primary:"#f59e0b",primaryDark:"#d97706",secondary:"#fb923c",bgDark:"#1f1a0a",bgCard:"#2f2a1a",bgHover:"#3f3a2a",textPrimary:"#fef3c7",textSecondary:"#fcd34d",border:"#3f3a2a"},pink:{primary:"#ec4899",primaryDark:"#db2777",secondary:"#f472b6",bgDark:"#1f0a1a",bgCard:"#2f1a2a",bgHover:"#3f2a3a",textPrimary:"#fce7f3",textSecondary:"#f9a8d4",border:"#3f2a3a"},light:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#ffffff",bgCard:"#f8fafc",bgHover:"#e2e8f0",textPrimary:"#0f172a",textSecondary:"#475569",border:"#cbd5e1"}},B=w[v]||w.dark;x.style.setProperty("--primary",B.primary),x.style.setProperty("--primary-dark",B.primaryDark),x.style.setProperty("--secondary",B.secondary),x.style.setProperty("--bg-dark",B.bgDark),x.style.setProperty("--bg-card",B.bgCard),x.style.setProperty("--bg-hover",B.bgHover),x.style.setProperty("--text-primary",B.textPrimary),x.style.setProperty("--text-secondary",B.textSecondary),x.style.setProperty("--border",B.border),localStorage.setItem("currentTheme",v)}async function we(v){v.innerHTML=`
1663
+ `,document.querySelectorAll(".settings-card").forEach(w=>{w.addEventListener("mouseenter",()=>{w.style.transform="translateY(-4px)",w.style.boxShadow="0 8px 24px rgba(0,0,0,0.12)"}),w.addEventListener("mouseleave",()=>{w.style.transform="translateY(0)",w.style.boxShadow="0 2px 8px rgba(0,0,0,0.05)"})}),document.querySelectorAll('input[type="email"], select').forEach(w=>{w.addEventListener("focus",()=>{w.style.borderColor="var(--primary)"}),w.addEventListener("blur",()=>{w.style.borderColor="var(--border)"})}),document.getElementById("changePasswordBtn").addEventListener("click",()=>{prompt("请输入新密码:")&&alert("密码修改功能开发中...")}),document.getElementById("resetSettingsBtn").addEventListener("click",()=>{confirm("确定要重置所有设置吗?")&&location.reload()}),document.getElementById("saveSettingsBtn").addEventListener("click",()=>{const w={email:document.getElementById("userEmail").value,emailNotifications:document.getElementById("emailNotifications").checked,desktopNotifications:document.getElementById("desktopNotifications").checked,soundNotifications:document.getElementById("soundNotifications").checked,theme:document.getElementById("themeSelect").value,language:document.getElementById("languageSelect").value};localStorage.setItem("userSettings",JSON.stringify(w)),ie(w.theme),alert("✅ 设置已保存!")}),document.getElementById("themeSelect").addEventListener("change",w=>{ie(w.target.value)});const b=localStorage.getItem("userSettings");if(b){const w=JSON.parse(b);w.email&&(document.getElementById("userEmail").value=w.email),document.getElementById("emailNotifications").checked=w.emailNotifications!==!1,document.getElementById("desktopNotifications").checked=w.desktopNotifications!==!1,document.getElementById("soundNotifications").checked=w.soundNotifications!==!1,w.theme&&(document.getElementById("themeSelect").value=w.theme,ie(w.theme)),w.language&&(document.getElementById("languageSelect").value=w.language)}}function ie(v){const b=document.documentElement,w={dark:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#0f172a",bgCard:"#1e293b",bgHover:"#334155",textPrimary:"#f1f5f9",textSecondary:"#94a3b8",border:"#334155"},blue:{primary:"#3b82f6",primaryDark:"#2563eb",secondary:"#06b6d4",bgDark:"#0c1222",bgCard:"#1a2332",bgHover:"#2a3442",textPrimary:"#e0f2fe",textSecondary:"#7dd3fc",border:"#2a3442"},green:{primary:"#10b981",primaryDark:"#059669",secondary:"#34d399",bgDark:"#0a1f1a",bgCard:"#1a2f2a",bgHover:"#2a3f3a",textPrimary:"#d1fae5",textSecondary:"#6ee7b7",border:"#2a3f3a"},orange:{primary:"#f59e0b",primaryDark:"#d97706",secondary:"#fb923c",bgDark:"#1f1a0a",bgCard:"#2f2a1a",bgHover:"#3f3a2a",textPrimary:"#fef3c7",textSecondary:"#fcd34d",border:"#3f3a2a"},pink:{primary:"#ec4899",primaryDark:"#db2777",secondary:"#f472b6",bgDark:"#1f0a1a",bgCard:"#2f1a2a",bgHover:"#3f2a3a",textPrimary:"#fce7f3",textSecondary:"#f9a8d4",border:"#3f2a3a"},light:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#ffffff",bgCard:"#f8fafc",bgHover:"#e2e8f0",textPrimary:"#0f172a",textSecondary:"#475569",border:"#cbd5e1"}},B=w[v]||w.dark;b.style.setProperty("--primary",B.primary),b.style.setProperty("--primary-dark",B.primaryDark),b.style.setProperty("--secondary",B.secondary),b.style.setProperty("--bg-dark",B.bgDark),b.style.setProperty("--bg-card",B.bgCard),b.style.setProperty("--bg-hover",B.bgHover),b.style.setProperty("--text-primary",B.textPrimary),b.style.setProperty("--text-secondary",B.textSecondary),b.style.setProperty("--border",B.border),localStorage.setItem("currentTheme",v)}async function we(v){v.innerHTML=`
1664
1664
  <div class="view-header" style="margin-bottom: 30px;">
1665
1665
  <h2 style="display: flex; align-items: center; gap: 12px; font-size: 28px;">
1666
1666
  <span style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">❓ 帮助中心</span>
@@ -1840,7 +1840,7 @@
1840
1840
  </div>
1841
1841
  </div>
1842
1842
  </div>
1843
- `,document.querySelectorAll(".help-card").forEach(x=>{x.addEventListener("mouseenter",()=>{x.style.transform="translateY(-4px)",x.style.boxShadow="0 8px 24px rgba(0,0,0,0.12)"}),x.addEventListener("mouseleave",()=>{x.style.transform="translateY(0)";const w=x.style.background.includes("gradient");x.style.boxShadow=w?"0 4px 12px rgba(102, 126, 234, 0.3)":"0 2px 8px rgba(0,0,0,0.05)"})})}async function ae(v){const x=document.getElementById("contentArea");switch(v){case"groups":await A(x);break;case"tasks":await F(x);break;case"documents":await W(x);break;case"chat":await K(x);break;case"files":await oe(x);break;case"search":await U(x);break;case"call":await te(x);break;case"audit":await me(x);break;case"polls":await se(x);break;case"knowledge":await M(x);break;case"workflow":await H(x);break;case"backup":await _(x);break;case"export":await Z(x);break;case"ai":await O(x);break;case"export":await Z(x);break;case"whiteboard":await Y(x);break;case"settings":await fe(x);break;case"help":await we(x);break}}ae("groups")}function Qr(r){const t=document.documentElement,i={dark:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#0f172a",bgCard:"#1e293b",bgHover:"#334155",textPrimary:"#f1f5f9",textSecondary:"#94a3b8",border:"#334155"},blue:{primary:"#3b82f6",primaryDark:"#2563eb",secondary:"#06b6d4",bgDark:"#0c1222",bgCard:"#1a2332",bgHover:"#2a3442",textPrimary:"#e0f2fe",textSecondary:"#7dd3fc",border:"#2a3442"},green:{primary:"#10b981",primaryDark:"#059669",secondary:"#34d399",bgDark:"#0a1f1a",bgCard:"#1a2f2a",bgHover:"#2a3f3a",textPrimary:"#d1fae5",textSecondary:"#6ee7b7",border:"#2a3f3a"},orange:{primary:"#f59e0b",primaryDark:"#d97706",secondary:"#fb923c",bgDark:"#1f1a0a",bgCard:"#2f2a1a",bgHover:"#3f3a2a",textPrimary:"#fef3c7",textSecondary:"#fcd34d",border:"#3f3a2a"},pink:{primary:"#ec4899",primaryDark:"#db2777",secondary:"#f472b6",bgDark:"#1f0a1a",bgCard:"#2f1a2a",bgHover:"#3f2a3a",textPrimary:"#fce7f3",textSecondary:"#f9a8d4",border:"#3f2a3a"},light:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#ffffff",bgCard:"#f8fafc",bgHover:"#e2e8f0",textPrimary:"#0f172a",textSecondary:"#475569",border:"#cbd5e1"}},s=i[r]||i.dark;t.style.setProperty("--primary",s.primary),t.style.setProperty("--primary-dark",s.primaryDark),t.style.setProperty("--secondary",s.secondary),t.style.setProperty("--bg-dark",s.bgDark),t.style.setProperty("--bg-card",s.bgCard),t.style.setProperty("--bg-hover",s.bgHover),t.style.setProperty("--text-primary",s.textPrimary),t.style.setProperty("--text-secondary",s.textSecondary),t.style.setProperty("--border",s.border)}function ea(r,t){const i=document.getElementById("app"),s=new Ft,m=new Je,l=r.id||r._id;let c=null,u=[];function P(U){if(U.startsWith("[白板作品]")){const z=U.replace("[白板作品]","").trim(),V=z.includes("/api/files/")&&z.includes("/download");let $=z;if(V&&!z.includes("token=")){const M=localStorage.getItem("token");$=z.includes("?")?`${z}&token=${M}`:`${z}?token=${M}`}return`
1843
+ `,document.querySelectorAll(".help-card").forEach(b=>{b.addEventListener("mouseenter",()=>{b.style.transform="translateY(-4px)",b.style.boxShadow="0 8px 24px rgba(0,0,0,0.12)"}),b.addEventListener("mouseleave",()=>{b.style.transform="translateY(0)";const w=b.style.background.includes("gradient");b.style.boxShadow=w?"0 4px 12px rgba(102, 126, 234, 0.3)":"0 2px 8px rgba(0,0,0,0.05)"})})}async function ae(v){const b=document.getElementById("contentArea");switch(v){case"groups":await D(b);break;case"tasks":await U(b);break;case"documents":await W(b);break;case"chat":await K(b);break;case"files":await oe(b);break;case"search":await P(b);break;case"call":await te(b);break;case"audit":await me(b);break;case"polls":await se(b);break;case"knowledge":await M(b);break;case"workflow":await H(b);break;case"backup":await _(b);break;case"export":await Z(b);break;case"ai":await O(b);break;case"export":await Z(b);break;case"whiteboard":await Y(b);break;case"settings":await xe(b);break;case"help":await we(b);break}}ae("groups")}function Qr(r){const t=document.documentElement,i={dark:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#0f172a",bgCard:"#1e293b",bgHover:"#334155",textPrimary:"#f1f5f9",textSecondary:"#94a3b8",border:"#334155"},blue:{primary:"#3b82f6",primaryDark:"#2563eb",secondary:"#06b6d4",bgDark:"#0c1222",bgCard:"#1a2332",bgHover:"#2a3442",textPrimary:"#e0f2fe",textSecondary:"#7dd3fc",border:"#2a3442"},green:{primary:"#10b981",primaryDark:"#059669",secondary:"#34d399",bgDark:"#0a1f1a",bgCard:"#1a2f2a",bgHover:"#2a3f3a",textPrimary:"#d1fae5",textSecondary:"#6ee7b7",border:"#2a3f3a"},orange:{primary:"#f59e0b",primaryDark:"#d97706",secondary:"#fb923c",bgDark:"#1f1a0a",bgCard:"#2f2a1a",bgHover:"#3f3a2a",textPrimary:"#fef3c7",textSecondary:"#fcd34d",border:"#3f3a2a"},pink:{primary:"#ec4899",primaryDark:"#db2777",secondary:"#f472b6",bgDark:"#1f0a1a",bgCard:"#2f1a2a",bgHover:"#3f2a3a",textPrimary:"#fce7f3",textSecondary:"#f9a8d4",border:"#3f2a3a"},light:{primary:"#6366f1",primaryDark:"#4f46e5",secondary:"#8b5cf6",bgDark:"#ffffff",bgCard:"#f8fafc",bgHover:"#e2e8f0",textPrimary:"#0f172a",textSecondary:"#475569",border:"#cbd5e1"}},s=i[r]||i.dark;t.style.setProperty("--primary",s.primary),t.style.setProperty("--primary-dark",s.primaryDark),t.style.setProperty("--secondary",s.secondary),t.style.setProperty("--bg-dark",s.bgDark),t.style.setProperty("--bg-card",s.bgCard),t.style.setProperty("--bg-hover",s.bgHover),t.style.setProperty("--text-primary",s.textPrimary),t.style.setProperty("--text-secondary",s.textSecondary),t.style.setProperty("--border",s.border)}function ea(r,t){const i=document.getElementById("app"),s=new Ut,m=new Je,l=r.id||r._id;let c=null,u=[];function F(P){if(P.startsWith("[白板作品]")){const A=P.replace("[白板作品]","").trim(),V=A.includes("/api/files/")&&A.includes("/download");let $=A;if(V&&!A.includes("token=")){const M=localStorage.getItem("token");$=A.includes("?")?`${A}&token=${M}`:`${A}?token=${M}`}return`
1844
1844
  <div style="background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%); padding: 16px; border-radius: 12px; box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);">
1845
1845
  <div style="margin-bottom: 12px; font-weight: 600; color: white; display: flex; align-items: center; gap: 6px; font-size: 15px;">
1846
1846
  <span style="font-size: 18px;">🎨</span>
@@ -1856,13 +1856,13 @@
1856
1856
  <div style="font-size: 48px; margin-bottom: 10px;">⚠️</div>
1857
1857
  <div style="font-weight: 600; margin-bottom: 5px;">图片加载失败</div>
1858
1858
  <div style="font-size: 12px;">图片可能已被删除或URL无效</div>
1859
- <button onclick="navigator.clipboard.writeText('${z}'); alert('图片URL已复制到剪贴板');" style="margin-top: 10px; padding: 6px 12px; background: rgba(255,255,255,0.2); color: white; border: none; border-radius: 6px; cursor: pointer;">复制图片URL</button>
1859
+ <button onclick="navigator.clipboard.writeText('${A}'); alert('图片URL已复制到剪贴板');" style="margin-top: 10px; padding: 6px 12px; background: rgba(255,255,255,0.2); color: white; border: none; border-radius: 6px; cursor: pointer;">复制图片URL</button>
1860
1860
  </div>
1861
1861
  <div style="margin-top: 10px; font-size: 12px; color: rgba(255,255,255,0.8);">点击图片查看大图</div>
1862
1862
  </div>
1863
1863
  </div>
1864
- `}if(U.startsWith("[投票]")){const z=U.replace("[投票]","").trim();return`
1865
- <div class="poll-card" data-poll-id="${z}" style="background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%); border: 2px solid rgba(99, 102, 241, 0.3); border-radius: 12px; padding: 16px; cursor: pointer; transition: all 0.3s;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 12px rgba(99, 102, 241, 0.2)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'" onclick="viewPollDetail('${z}')">
1864
+ `}if(P.startsWith("[投票]")){const A=P.replace("[投票]","").trim();return`
1865
+ <div class="poll-card" data-poll-id="${A}" style="background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%); border: 2px solid rgba(99, 102, 241, 0.3); border-radius: 12px; padding: 16px; cursor: pointer; transition: all 0.3s;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 4px 12px rgba(99, 102, 241, 0.2)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'" onclick="viewPollDetail('${A}')">
1866
1866
  <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 12px;">
1867
1867
  <span style="font-size: 32px;">📊</span>
1868
1868
  <div style="flex: 1;">
@@ -1874,7 +1874,7 @@
1874
1874
  📋 查看投票详情
1875
1875
  </div>
1876
1876
  </div>
1877
- `}return U}window.viewPollDetail=async U=>{try{const V=(await s.getPoll(U)).poll,$=V.options.reduce((Y,fe)=>Y+fe.votes.length,0),M=V.options.some(Y=>Y.votes.includes(l)),N=V.status==="ended"||V.endTime&&new Date(V.endTime)<new Date;let H="";V.options.forEach((Y,fe)=>{const ie=$>0?(Y.votes.length/$*100).toFixed(1):0,we=Y.votes.includes(l);H+=`
1877
+ `}return P}window.viewPollDetail=async P=>{try{const V=(await s.getPoll(P)).poll,$=V.options.reduce((Y,xe)=>Y+xe.votes.length,0),M=V.options.some(Y=>Y.votes.includes(l)),N=V.status==="ended"||V.endTime&&new Date(V.endTime)<new Date;let H="";V.options.forEach((Y,xe)=>{const ie=$>0?(Y.votes.length/$*100).toFixed(1):0,we=Y.votes.includes(l);H+=`
1878
1878
  <div class="poll-option" style="margin-bottom: 12px; padding: 12px; background: var(--bg-tertiary); border-radius: 8px; border: 2px solid ${we?"var(--primary)":"var(--border)"};">
1879
1879
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
1880
1880
  <div style="display: flex; align-items: center; gap: 8px;">
@@ -1942,11 +1942,11 @@
1942
1942
  <h3 style="margin-bottom: 16px; color: var(--text-primary);">投票选项</h3>
1943
1943
  ${!N&&!M?`
1944
1944
  <form id="voteForm">
1945
- ${V.options.map((Y,fe)=>{const ie=$>0?(Y.votes.length/$*100).toFixed(1):0;return`
1945
+ ${V.options.map((Y,xe)=>{const ie=$>0?(Y.votes.length/$*100).toFixed(1):0;return`
1946
1946
  <div class="poll-option" style="margin-bottom: 12px; padding: 12px; background: var(--bg-tertiary); border-radius: 8px; border: 2px solid var(--border); cursor: pointer;" onmouseover="this.style.borderColor='var(--primary)'" onmouseout="this.style.borderColor='var(--border)'">
1947
1947
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
1948
1948
  <div style="display: flex; align-items: center; gap: 8px;">
1949
- <input type="${V.allowMultiple?"checkbox":"radio"}" name="poll-option" value="${fe}" style="width: 18px; height: 18px; cursor: pointer;">
1949
+ <input type="${V.allowMultiple?"checkbox":"radio"}" name="poll-option" value="${xe}" style="width: 18px; height: 18px; cursor: pointer;">
1950
1950
  <span style="font-weight: 500; color: var(--text-primary);">${Y.text}</span>
1951
1951
  </div>
1952
1952
  <span style="font-weight: 600; color: var(--primary);">${Y.votes.length} 票 (${ie}%)</span>
@@ -1970,7 +1970,7 @@
1970
1970
  </div>
1971
1971
  </div>
1972
1972
  </div>
1973
- `,O=document.getElementById("pollDetailModal");O&&O.remove(),document.body.insertAdjacentHTML("beforeend",_),document.getElementById("closePollDetailModal").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()}),document.getElementById("closePollDetailBtn").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()});const Z=document.getElementById("voteForm");Z&&!N&&!M&&Z.addEventListener("submit",async Y=>{Y.preventDefault();const fe=Array.from(document.querySelectorAll('input[name="poll-option"]:checked')).map(ie=>parseInt(ie.value));if(fe.length===0){alert("请选择至少一个选项!");return}try{await s.vote(U,fe),alert("投票成功!"),document.getElementById("pollDetailModal").remove();const ie=document.querySelector(".nav-item.active");if(ie&&ie.dataset.view==="tasks"){const we=document.getElementById("contentArea");await F(we)}}catch(ie){console.error("投票失败:",ie),alert("投票失败:"+ie.message)}})}catch(z){console.error("加载投票详情失败:",z),alert("加载投票详情失败:"+z.message)}},i.innerHTML=`
1973
+ `,O=document.getElementById("pollDetailModal");O&&O.remove(),document.body.insertAdjacentHTML("beforeend",_),document.getElementById("closePollDetailModal").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()}),document.getElementById("closePollDetailBtn").addEventListener("click",()=>{document.getElementById("pollDetailModal").remove()});const Z=document.getElementById("voteForm");Z&&!N&&!M&&Z.addEventListener("submit",async Y=>{Y.preventDefault();const xe=Array.from(document.querySelectorAll('input[name="poll-option"]:checked')).map(ie=>parseInt(ie.value));if(xe.length===0){alert("请选择至少一个选项!");return}try{await s.vote(P,xe),alert("投票成功!"),document.getElementById("pollDetailModal").remove();const ie=document.querySelector(".nav-item.active");if(ie&&ie.dataset.view==="tasks"){const we=document.getElementById("contentArea");await U(we)}}catch(ie){console.error("投票失败:",ie),alert("投票失败:"+ie.message)}})}catch(A){console.error("加载投票详情失败:",A),alert("加载投票详情失败:"+A.message)}},i.innerHTML=`
1974
1974
  <div class="dashboard">
1975
1975
  <aside class="sidebar">
1976
1976
  <div class="sidebar-header">
@@ -2020,7 +2020,7 @@
2020
2020
  <div id="contentArea"></div>
2021
2021
  </main>
2022
2022
  </div>
2023
- `,document.querySelectorAll(".nav-item").forEach(U=>{U.addEventListener("click",()=>{document.querySelectorAll(".nav-item").forEach(V=>V.classList.remove("active")),U.classList.add("active");const z=U.dataset.view;A(z)})}),document.getElementById("logoutBtn").addEventListener("click",()=>{m.logout()});async function A(U){const z=document.getElementById("contentArea");switch(U){case"groups":await D(z);break;case"allgroups":await R(z);break;case"tasks":await F(z);break;case"documents":await W(z);break;case"files":await oe(z);break;case"chat":await K(z);break;case"search":await te(z);break;case"knowledge":await ve(z);break}}async function D(U){u=(await s.getGroups()).groups,U.innerHTML=`
2023
+ `,document.querySelectorAll(".nav-item").forEach(P=>{P.addEventListener("click",()=>{document.querySelectorAll(".nav-item").forEach(V=>V.classList.remove("active")),P.classList.add("active");const A=P.dataset.view;D(A)})}),document.getElementById("logoutBtn").addEventListener("click",()=>{m.logout()});async function D(P){const A=document.getElementById("contentArea");switch(P){case"groups":await z(A);break;case"allgroups":await R(A);break;case"tasks":await U(A);break;case"documents":await W(A);break;case"files":await oe(A);break;case"chat":await K(A);break;case"search":await te(A);break;case"knowledge":await ve(A);break}}async function z(P){u=(await s.getGroups()).groups,P.innerHTML=`
2024
2024
  <div class="view-header">
2025
2025
  <h2>我的群组</h2>
2026
2026
  </div>
@@ -2037,12 +2037,12 @@
2037
2037
  <button class="btn-select" data-id="${$._id}">进入群组</button>
2038
2038
  <button class="btn-secondary" data-id="${$._id}" data-action="leave">退出群组</button>
2039
2039
  </div>
2040
- `,V.appendChild(M)}),document.querySelectorAll(".btn-select").forEach($=>{$.addEventListener("click",()=>{c=u.find(M=>M._id===$.dataset.id),t.joinGroup(c._id),alert(`已进入群组: ${c.name}`)})}),document.querySelectorAll('[data-action="leave"]').forEach($=>{$.addEventListener("click",async()=>{if(confirm("确定要退出该群组吗?"))try{await s.leaveGroup($.dataset.id),alert("已退出群组"),await D(U)}catch(M){alert("退出失败: "+M.message)}})})}async function R(U){const z=await s.getAllGroups(),$=(await s.getGroups()).groups.map(N=>N._id);U.innerHTML=`
2040
+ `,V.appendChild(M)}),document.querySelectorAll(".btn-select").forEach($=>{$.addEventListener("click",()=>{c=u.find(M=>M._id===$.dataset.id),t.joinGroup(c._id),alert(`已进入群组: ${c.name}`)})}),document.querySelectorAll('[data-action="leave"]').forEach($=>{$.addEventListener("click",async()=>{if(confirm("确定要退出该群组吗?"))try{await s.leaveGroup($.dataset.id),alert("已退出群组"),await z(P)}catch(M){alert("退出失败: "+M.message)}})})}async function R(P){const A=await s.getAllGroups(),$=(await s.getGroups()).groups.map(N=>N._id);P.innerHTML=`
2041
2041
  <div class="view-header">
2042
2042
  <h2>所有群组</h2>
2043
2043
  </div>
2044
2044
  <div class="groups-grid" id="allGroupsList"></div>
2045
- `;const M=document.getElementById("allGroupsList");z.groups.forEach(N=>{const H=$.includes(N._id),_=document.createElement("div");_.className="group-card",_.innerHTML=`
2045
+ `;const M=document.getElementById("allGroupsList");A.groups.forEach(N=>{const H=$.includes(N._id),_=document.createElement("div");_.className="group-card",_.innerHTML=`
2046
2046
  <h3>${N.name}</h3>
2047
2047
  <p>${N.description||"暂无描述"}</p>
2048
2048
  <div class="group-stats">
@@ -2050,12 +2050,12 @@
2050
2050
  <span>📄 ${N.documents.length} 文档</span>
2051
2051
  </div>
2052
2052
  ${H?'<div style="color: var(--success); margin-top: 10px;">✓ 已加入</div>':`<button class="btn-primary" data-id="${N._id}" data-action="join">加入群组</button>`}
2053
- `,M.appendChild(_)}),document.querySelectorAll('[data-action="join"]').forEach(N=>{N.addEventListener("click",async()=>{try{await s.joinGroup(N.dataset.id),alert("加入成功!"),await R(U)}catch(H){alert("加入失败: "+H.message)}})})}async function F(U){try{const z=await s.getMyTasks();let V=[];try{const N=(await s.getGroups()).groups;for(const H of N)try{const _=await s.getGroupPolls(H._id);_.polls&&Array.isArray(_.polls)&&(V=V.concat(_.polls.map(O=>({...O,groupName:H.name}))))}catch(_){console.error(`获取群组 ${H.name} 的投票失败:`,_)}}catch(M){console.error("获取投票失败:",M)}U.innerHTML=`
2053
+ `,M.appendChild(_)}),document.querySelectorAll('[data-action="join"]').forEach(N=>{N.addEventListener("click",async()=>{try{await s.joinGroup(N.dataset.id),alert("加入成功!"),await R(P)}catch(H){alert("加入失败: "+H.message)}})})}async function U(P){try{const A=await s.getMyTasks();let V=[];try{const N=(await s.getGroups()).groups;for(const H of N)try{const _=await s.getGroupPolls(H._id);_.polls&&Array.isArray(_.polls)&&(V=V.concat(_.polls.map(O=>({...O,groupName:H.name}))))}catch(_){console.error(`获取群组 ${H.name} 的投票失败:`,_)}}catch(M){console.error("获取投票失败:",M)}P.innerHTML=`
2054
2054
  <div class="view-header">
2055
2055
  <h2>我的任务</h2>
2056
2056
  </div>
2057
2057
  <div class="tasks-list" id="tasksList"></div>
2058
- `;const $=document.getElementById("tasksList");if(z.tasks.length===0&&V.length===0){$.innerHTML='<div class="empty-state">暂无任务</div>';return}z.tasks.forEach(M=>{const N=document.createElement("div");N.className=`task-card status-${M.status}`,N.innerHTML=`
2058
+ `;const $=document.getElementById("tasksList");if(A.tasks.length===0&&V.length===0){$.innerHTML='<div class="empty-state">暂无任务</div>';return}A.tasks.forEach(M=>{const N=document.createElement("div");N.className=`task-card status-${M.status}`,N.innerHTML=`
2059
2059
  <h3>${M.title}</h3>
2060
2060
  <p>${M.description}</p>
2061
2061
  <div class="task-meta">
@@ -2083,17 +2083,17 @@
2083
2083
  <div class="task-actions">
2084
2084
  <button class="btn-primary btn-sm" data-poll-id="${M._id}" data-action="view-poll">查看详情</button>
2085
2085
  </div>
2086
- `,$.appendChild(O)}),document.querySelectorAll('[data-action="start"], [data-action="complete"]').forEach(M=>{M.addEventListener("click",async()=>{const N=M.dataset.id,_=M.dataset.action==="start"?"in_progress":"completed";try{await s.updateTaskStatus(N,_),await F(U)}catch(O){alert("操作失败: "+O.message)}})}),document.querySelectorAll('[data-action="view-poll"]').forEach(M=>{M.addEventListener("click",()=>{const N=M.dataset.pollId;window.viewPollDetail(N)})})}catch(z){console.error("获取任务失败:",z),U.innerHTML=`
2086
+ `,$.appendChild(O)}),document.querySelectorAll('[data-action="start"], [data-action="complete"]').forEach(M=>{M.addEventListener("click",async()=>{const N=M.dataset.id,_=M.dataset.action==="start"?"in_progress":"completed";try{await s.updateTaskStatus(N,_),await U(P)}catch(O){alert("操作失败: "+O.message)}})}),document.querySelectorAll('[data-action="view-poll"]').forEach(M=>{M.addEventListener("click",()=>{const N=M.dataset.pollId;window.viewPollDetail(N)})})}catch(A){console.error("获取任务失败:",A),P.innerHTML=`
2087
2087
  <div class="view-header">
2088
2088
  <h2>我的任务</h2>
2089
2089
  </div>
2090
- <div class="empty-state">加载任务失败: ${z.message}</div>
2091
- `}}async function W(U){if(!c){U.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}const z=await s.getDocuments(c._id);U.innerHTML=`
2090
+ <div class="empty-state">加载任务失败: ${A.message}</div>
2091
+ `}}async function W(P){if(!c){P.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}const A=await s.getDocuments(c._id);P.innerHTML=`
2092
2092
  <div class="view-header">
2093
2093
  <h2>共享文档 - ${c.name}</h2>
2094
2094
  </div>
2095
2095
  <div class="documents-list" id="docsList"></div>
2096
- `;const V=document.getElementById("docsList");if(z.documents.length===0){V.innerHTML='<div class="empty-state">暂无文档</div>';return}z.documents.forEach($=>{const M=document.createElement("div");M.className="document-card",M.innerHTML=`
2096
+ `;const V=document.getElementById("docsList");if(A.documents.length===0){V.innerHTML='<div class="empty-state">暂无文档</div>';return}A.documents.forEach($=>{const M=document.createElement("div");M.className="document-card",M.innerHTML=`
2097
2097
  <h3>📄 ${$.title}</h3>
2098
2098
  <div class="doc-meta">
2099
2099
  <span>创建者: ${$.creator.username}</span>
@@ -2103,7 +2103,7 @@
2103
2103
  <button class="btn-edit" data-id="${$._id}">
2104
2104
  ${$.permission==="readonly"?"查看":"编辑"}
2105
2105
  </button>
2106
- `,V.appendChild(M)}),document.querySelectorAll(".btn-edit").forEach($=>{$.addEventListener("click",()=>{ue(U,$.dataset.id)})})}async function ue(U,z){const $=(await s.getDocument(z)).document;U.innerHTML=`
2106
+ `,V.appendChild(M)}),document.querySelectorAll(".btn-edit").forEach($=>{$.addEventListener("click",()=>{ue(P,$.dataset.id)})})}async function ue(P,A){const $=(await s.getDocument(A)).document;P.innerHTML=`
2107
2107
  <div class="view-header">
2108
2108
  <button class="btn-back" id="backBtn">← 返回</button>
2109
2109
  <h2>${$.title}</h2>
@@ -2121,7 +2121,7 @@
2121
2121
  <span>最后编辑: ${new Date($.updatedAt).toLocaleString()}</span>
2122
2122
  </div>
2123
2123
  </div>
2124
- `;const M=new Quill("#editor",{theme:"snow",modules:{toolbar:$.permission==="readonly"?!1:[[{header:[1,2,3,!1]}],["bold","italic","underline","strike"],[{list:"ordered"},{list:"bullet"}],[{color:[]},{background:[]}],["link","image","code-block"],["clean"]]},readOnly:$.permission==="readonly"});if(M.root.innerHTML=$.content||"",$.permission==="editable"){let N,H;M.on("text-change",()=>{clearTimeout(N),clearTimeout(H),t.sendTyping(z,r.username,!0),N=setTimeout(()=>{t.sendTyping(z,r.username,!1)},1e3),H=setTimeout(async()=>{const _=M.root.innerHTML;try{await s.updateDocument(z,_)}catch(O){console.error("自动保存失败:",O)}},2e3)}),document.getElementById("saveBtn").addEventListener("click",async()=>{try{const _=M.root.innerHTML;await s.updateDocument(z,_),alert("保存成功!")}catch(_){alert("保存失败: "+_.message)}})}t.on("document_update",N=>{if(N.documentId===z&&N.userId!==r.id){const H=M.getSelection();M.root.innerHTML=N.content,H&&M.setSelection(H)}}),t.on("typing",N=>{if(N.documentId===z&&N.userId!==r.id){const H=document.getElementById("onlineUsers");if(N.isTyping)H.innerHTML+=`<span class="user-badge typing" data-user="${N.userId}">✏️ ${N.username}</span>`;else{const _=H.querySelector(`[data-user="${N.userId}"]`);_&&_.remove()}}}),document.getElementById("backBtn").addEventListener("click",()=>{W(U)})}async function oe(U){if(!c){U.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const z=await s.getGroupFiles(c._id);U.innerHTML=`
2124
+ `;const M=new Quill("#editor",{theme:"snow",modules:{toolbar:$.permission==="readonly"?!1:[[{header:[1,2,3,!1]}],["bold","italic","underline","strike"],[{list:"ordered"},{list:"bullet"}],[{color:[]},{background:[]}],["link","image","code-block"],["clean"]]},readOnly:$.permission==="readonly"});if(M.root.innerHTML=$.content||"",$.permission==="editable"){let N,H;M.on("text-change",()=>{clearTimeout(N),clearTimeout(H),t.sendTyping(A,r.username,!0),N=setTimeout(()=>{t.sendTyping(A,r.username,!1)},1e3),H=setTimeout(async()=>{const _=M.root.innerHTML;try{await s.updateDocument(A,_)}catch(O){console.error("自动保存失败:",O)}},2e3)}),document.getElementById("saveBtn").addEventListener("click",async()=>{try{const _=M.root.innerHTML;await s.updateDocument(A,_),alert("保存成功!")}catch(_){alert("保存失败: "+_.message)}})}t.on("document_update",N=>{if(N.documentId===A&&N.userId!==r.id){const H=M.getSelection();M.root.innerHTML=N.content,H&&M.setSelection(H)}}),t.on("typing",N=>{if(N.documentId===A&&N.userId!==r.id){const H=document.getElementById("onlineUsers");if(N.isTyping)H.innerHTML+=`<span class="user-badge typing" data-user="${N.userId}">✏️ ${N.username}</span>`;else{const _=H.querySelector(`[data-user="${N.userId}"]`);_&&_.remove()}}}),document.getElementById("backBtn").addEventListener("click",()=>{W(P)})}async function oe(P){if(!c){P.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const A=await s.getGroupFiles(c._id);P.innerHTML=`
2125
2125
  <div class="view-header">
2126
2126
  <h2>文件共享 - ${c.name}</h2>
2127
2127
  <button class="btn-primary" id="uploadFileBtn">📤 上传文件</button>
@@ -2152,7 +2152,7 @@
2152
2152
  </form>
2153
2153
  </div>
2154
2154
  </div>
2155
- `;const V=document.getElementById("filesList");!z.files||z.files.length===0?V.innerHTML='<div class="empty-state">暂无文件</div>':(z.files.forEach($=>{const M=document.createElement("div");M.className="file-card";const N=be($.mimetype),H=xe($.size),_=$.uploader._id||$.uploader.id||$.uploader,O=String(_)===String(l);M.innerHTML=`
2155
+ `;const V=document.getElementById("filesList");!A.files||A.files.length===0?V.innerHTML='<div class="empty-state">暂无文件</div>':(A.files.forEach($=>{const M=document.createElement("div");M.className="file-card";const N=fe($.mimetype),H=be($.size),_=$.uploader._id||$.uploader.id||$.uploader,O=String(_)===String(l);M.innerHTML=`
2156
2156
  <div class="file-icon">${N}</div>
2157
2157
  <div class="file-info">
2158
2158
  <h4>${$.originalName}</h4>
@@ -2167,12 +2167,12 @@
2167
2167
  <a href="${s.getFileDownloadUrl($._id)}" class="btn-primary" download>下载</a>
2168
2168
  ${O?`<button class="btn-danger" data-id="${$._id}" data-action="delete-file">删除</button>`:""}
2169
2169
  </div>
2170
- `,V.appendChild(M)}),document.querySelectorAll('[data-action="delete-file"]').forEach($=>{$.addEventListener("click",async()=>{if(confirm("确定要删除这个文件吗?"))try{await s.deleteFile($.dataset.id),alert("文件删除成功!"),await oe(U)}catch(M){alert("删除失败: "+M.message)}})})),document.getElementById("uploadFileBtn").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.remove("hidden")}),document.getElementById("closeUploadModal").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("cancelUpload").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("uploadFileForm").addEventListener("submit",async $=>{$.preventDefault();const M=document.getElementById("fileInput"),N=document.getElementById("fileDescription").value;if(!M.files[0]){alert("请选择文件");return}try{await s.uploadFile(c._id,M.files[0],N),alert("文件上传成功!"),document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset(),await oe(U)}catch(H){alert("上传失败: "+H.message)}})}catch(z){console.error("获取文件列表失败:",z),U.innerHTML=`
2170
+ `,V.appendChild(M)}),document.querySelectorAll('[data-action="delete-file"]').forEach($=>{$.addEventListener("click",async()=>{if(confirm("确定要删除这个文件吗?"))try{await s.deleteFile($.dataset.id),alert("文件删除成功!"),await oe(P)}catch(M){alert("删除失败: "+M.message)}})})),document.getElementById("uploadFileBtn").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.remove("hidden")}),document.getElementById("closeUploadModal").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("cancelUpload").addEventListener("click",()=>{document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset()}),document.getElementById("uploadFileForm").addEventListener("submit",async $=>{$.preventDefault();const M=document.getElementById("fileInput"),N=document.getElementById("fileDescription").value;if(!M.files[0]){alert("请选择文件");return}try{await s.uploadFile(c._id,M.files[0],N),alert("文件上传成功!"),document.getElementById("uploadFileModal").classList.add("hidden"),document.getElementById("uploadFileForm").reset(),await oe(P)}catch(H){alert("上传失败: "+H.message)}})}catch(A){console.error("获取文件列表失败:",A),P.innerHTML=`
2171
2171
  <div class="view-header">
2172
2172
  <h2>文件共享</h2>
2173
2173
  </div>
2174
- <div class="empty-state">加载文件失败: ${z.message}</div>
2175
- `}}function be(U){return U.startsWith("image/")?"🖼️":U==="application/pdf"?"📕":U.includes("word")||U.includes("document")?"📘":U.includes("excel")||U.includes("spreadsheet")?"📗":U.includes("zip")||U.includes("compressed")?"📦":"📄"}function xe(U){if(U===0)return"0 Bytes";const z=1024,V=["Bytes","KB","MB","GB"],$=Math.floor(Math.log(U)/Math.log(z));return Math.round(U/Math.pow(z,$)*100)/100+" "+V[$]}async function K(U){if(!c){U.innerHTML=`
2174
+ <div class="empty-state">加载文件失败: ${A.message}</div>
2175
+ `}}function fe(P){return P.startsWith("image/")?"🖼️":P==="application/pdf"?"📕":P.includes("word")||P.includes("document")?"📘":P.includes("excel")||P.includes("spreadsheet")?"📗":P.includes("zip")||P.includes("compressed")?"📦":"📄"}function be(P){if(P===0)return"0 Bytes";const A=1024,V=["Bytes","KB","MB","GB"],$=Math.floor(Math.log(P)/Math.log(A));return Math.round(P/Math.pow(A,$)*100)/100+" "+V[$]}async function K(P){if(!c){P.innerHTML=`
2176
2176
  <div class="empty-state" style="text-align: center; padding: 60px 20px; background: var(--bg-secondary); border-radius: 16px; border: 2px dashed var(--border);">
2177
2177
  <div style="font-size: 64px; margin-bottom: 20px;">💬</div>
2178
2178
  <h3 style="font-size: 24px; margin-bottom: 12px; color: var(--text-primary);">群聊</h3>
@@ -2181,7 +2181,7 @@
2181
2181
  前往我的群组
2182
2182
  </button>
2183
2183
  </div>
2184
- `;return}try{let z=function(k,p,h="💬"){"Notification"in window&&Notification.permission==="granted"&&new Notification(k,{body:p,icon:"/icon.png",badge:"/icon.png",tag:"chat-message"})},V=function(){const k=document.getElementById("whiteboard");if(!k||k.dataset.initialized)return;k.dataset.initialized="true";const p=k.getContext("2d");k.width=k.offsetWidth,k.height=k.offsetHeight;let h=!1,o="pen",g="#667eea",b=3;document.querySelectorAll(".tool-btn").forEach(E=>{E.addEventListener("click",()=>{o=E.dataset.tool,document.querySelectorAll(".tool-btn").forEach(C=>{C.style.background="var(--bg-secondary)",C.style.color="var(--text-primary)",C.style.border="1px solid var(--border)"}),E.style.background="var(--primary)",E.style.color="white",E.style.border="none"})}),document.getElementById("colorPicker").addEventListener("change",E=>{g=E.target.value}),document.getElementById("brushSize").addEventListener("input",E=>{b=E.target.value}),document.getElementById("clearCanvas").addEventListener("click",()=>{confirm("确定要清空画布吗?")&&(p.clearRect(0,0,k.width,k.height),t.sendWhiteboardClear(c._id))}),document.getElementById("sendWhiteboardBtn").addEventListener("click",async()=>{try{const E=k.toDataURL("image/png"),C=document.createElement("canvas");C.width=k.width,C.height=k.height;const G=C.toDataURL("image/png");if(E===G){alert("画布是空的,请先绘制内容!");return}if(E.length*.75/1024/1024<1)t.sendChatMessage(c._id,r.username,`[白板作品]${E}`),alert("白板作品已发送到群聊!");else{const ee=await fetch(E).then(X=>X.blob()),S=new FormData;S.append("file",ee,`whiteboard-${Date.now()}.png`),S.append("groupId",c._id),S.append("description","协作白板作品");const j=localStorage.getItem("token"),T=await fetch("http://localhost:3000/api/files/upload",{method:"POST",headers:{Authorization:`Bearer ${j}`},body:S});if(T.ok){const re=`http://localhost:3000/api/files/${(await T.json()).file._id}/download?token=${j}`;t.sendChatMessage(c._id,r.username,`[白板作品]${re}`),alert("白板作品已发送到群聊!")}else throw new Error("上传失败")}}catch(E){console.error("发送白板失败:",E),alert("发送失败,请重试!")}}),k.addEventListener("mousedown",E=>{h=!0;const C=k.getBoundingClientRect(),G=E.clientX-C.left,J=E.clientY-C.top;p.beginPath(),p.moveTo(G,J)}),k.addEventListener("mousemove",E=>{if(!h)return;const C=k.getBoundingClientRect(),G=E.clientX-C.left,J=E.clientY-C.top;p.lineWidth=b,p.lineCap="round",o==="pen"?(p.strokeStyle=g,p.globalCompositeOperation="source-over"):o==="eraser"&&(p.globalCompositeOperation="destination-out"),p.lineTo(G,J),p.stroke(),t.sendWhiteboardDraw(c._id,{tool:o,color:g,size:b,x:G,y:J})}),k.addEventListener("mouseup",()=>{h=!1}),k.addEventListener("mouseleave",()=>{h=!1}),t.on("whiteboard_draw",E=>{E.groupId===c._id&&(p.lineWidth=E.size,p.lineCap="round",E.tool==="pen"?(p.strokeStyle=E.color,p.globalCompositeOperation="source-over"):E.tool==="eraser"&&(p.globalCompositeOperation="destination-out"),p.lineTo(E.x,E.y),p.stroke())}),t.on("whiteboard_clear",E=>{E.groupId===c._id&&p.clearRect(0,0,k.width,k.height)})};const M=(await s.getGroup(c._id)).group,N=!!M.mutedAll,H=(M.mutedUsers||[]).map(String).includes(String(l)),_=!N&&!H;U.innerHTML=`
2184
+ `;return}try{let A=function(k,p,h="💬"){"Notification"in window&&Notification.permission==="granted"&&new Notification(k,{body:p,icon:"/icon.png",badge:"/icon.png",tag:"chat-message"})},V=function(){const k=document.getElementById("whiteboard");if(!k||k.dataset.initialized)return;k.dataset.initialized="true";const p=k.getContext("2d");k.width=k.offsetWidth,k.height=k.offsetHeight;let h=!1,o="pen",g="#667eea",f=3;document.querySelectorAll(".tool-btn").forEach(E=>{E.addEventListener("click",()=>{o=E.dataset.tool,document.querySelectorAll(".tool-btn").forEach(C=>{C.style.background="var(--bg-secondary)",C.style.color="var(--text-primary)",C.style.border="1px solid var(--border)"}),E.style.background="var(--primary)",E.style.color="white",E.style.border="none"})}),document.getElementById("colorPicker").addEventListener("change",E=>{g=E.target.value}),document.getElementById("brushSize").addEventListener("input",E=>{f=E.target.value}),document.getElementById("clearCanvas").addEventListener("click",()=>{confirm("确定要清空画布吗?")&&(p.clearRect(0,0,k.width,k.height),t.sendWhiteboardClear(c._id))}),document.getElementById("sendWhiteboardBtn").addEventListener("click",async()=>{try{const E=k.toDataURL("image/png"),C=document.createElement("canvas");C.width=k.width,C.height=k.height;const G=C.toDataURL("image/png");if(E===G){alert("画布是空的,请先绘制内容!");return}if(E.length*.75/1024/1024<1)t.sendChatMessage(c._id,r.username,`[白板作品]${E}`),alert("白板作品已发送到群聊!");else{const ee=await fetch(E).then(X=>X.blob()),S=new FormData;S.append("file",ee,`whiteboard-${Date.now()}.png`),S.append("groupId",c._id),S.append("description","协作白板作品");const j=localStorage.getItem("token"),T=await fetch("http://localhost:3000/api/files/upload",{method:"POST",headers:{Authorization:`Bearer ${j}`},body:S});if(T.ok){const re=`http://localhost:3000/api/files/${(await T.json()).file._id}/download?token=${j}`;t.sendChatMessage(c._id,r.username,`[白板作品]${re}`),alert("白板作品已发送到群聊!")}else throw new Error("上传失败")}}catch(E){console.error("发送白板失败:",E),alert("发送失败,请重试!")}}),k.addEventListener("mousedown",E=>{h=!0;const C=k.getBoundingClientRect(),G=E.clientX-C.left,J=E.clientY-C.top;p.beginPath(),p.moveTo(G,J)}),k.addEventListener("mousemove",E=>{if(!h)return;const C=k.getBoundingClientRect(),G=E.clientX-C.left,J=E.clientY-C.top;p.lineWidth=f,p.lineCap="round",o==="pen"?(p.strokeStyle=g,p.globalCompositeOperation="source-over"):o==="eraser"&&(p.globalCompositeOperation="destination-out"),p.lineTo(G,J),p.stroke(),t.sendWhiteboardDraw(c._id,{tool:o,color:g,size:f,x:G,y:J})}),k.addEventListener("mouseup",()=>{h=!1}),k.addEventListener("mouseleave",()=>{h=!1}),t.on("whiteboard_draw",E=>{E.groupId===c._id&&(p.lineWidth=E.size,p.lineCap="round",E.tool==="pen"?(p.strokeStyle=E.color,p.globalCompositeOperation="source-over"):E.tool==="eraser"&&(p.globalCompositeOperation="destination-out"),p.lineTo(E.x,E.y),p.stroke())}),t.on("whiteboard_clear",E=>{E.groupId===c._id&&p.clearRect(0,0,k.width,k.height)})};const M=(await s.getGroup(c._id)).group,N=!!M.mutedAll,H=(M.mutedUsers||[]).map(String).includes(String(l)),_=!N&&!H;P.innerHTML=`
2185
2185
  <div class="view-header" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px; margin-bottom: 20px;">
2186
2186
  <h2 style="margin: 0; display: flex; align-items: center; gap: 12px;">
2187
2187
  <span style="font-size: 32px;">💬</span>
@@ -2256,7 +2256,7 @@
2256
2256
  <div style="font-size: 48px; margin-bottom: 16px;">💬</div>
2257
2257
  <p>还没有消息,开始聊天吧!</p>
2258
2258
  </div>
2259
- `:(k.messages.forEach(p=>{const h=document.createElement("div"),o=String(p.sender)===String(l)||p.username===r.username,g=P(p.content),b=p.content.startsWith("[白板作品]")||p.content.startsWith("[投票]"),E=p.content.startsWith("[白板作品]");h.className=`message ${o?"own":""}`,h.style.cssText=`
2259
+ `:(k.messages.forEach(p=>{const h=document.createElement("div"),o=String(p.sender)===String(l)||p.username===r.username,g=F(p.content),f=p.content.startsWith("[白板作品]")||p.content.startsWith("[投票]"),E=p.content.startsWith("[白板作品]");h.className=`message ${o?"own":""}`,h.style.cssText=`
2260
2260
  margin-bottom: 16px;
2261
2261
  display: flex;
2262
2262
  flex-direction: column;
@@ -2266,25 +2266,25 @@
2266
2266
  <span class="message-user">${p.username}</span>
2267
2267
  <span class="message-time">${new Date(p.timestamp).toLocaleTimeString("zh-CN")}</span>
2268
2268
  </div>
2269
- <div class="message-content" style="background: ${E||b?"transparent":o?"linear-gradient(135deg, #667eea 0%, #764ba2 100%)":"var(--bg-tertiary)"}; color: ${o&&!b?"white":"var(--text-primary)"}; padding: ${b?"0":"12px 16px"}; border-radius: 16px; max-width: ${b?"90%":"70%"}; word-wrap: break-word; box-shadow: ${o&&!b?"0 4px 12px rgba(102, 126, 234, 0.3)":"0 2px 8px rgba(0,0,0,0.05)"};">${g}</div>
2269
+ <div class="message-content" style="background: ${E||f?"transparent":o?"linear-gradient(135deg, #667eea 0%, #764ba2 100%)":"var(--bg-tertiary)"}; color: ${o&&!f?"white":"var(--text-primary)"}; padding: ${f?"0":"12px 16px"}; border-radius: 16px; max-width: ${f?"90%":"70%"}; word-wrap: break-word; box-shadow: ${o&&!f?"0 4px 12px rgba(102, 126, 234, 0.3)":"0 2px 8px rgba(0,0,0,0.05)"};">${g}</div>
2270
2270
  `,O.appendChild(h)}),O.scrollTop=O.scrollHeight))}catch(k){console.error("加载历史消息失败:",k),O.innerHTML=`
2271
2271
  <div style="text-align: center; padding: 40px; color: var(--danger);">
2272
2272
  <div style="font-size: 48px; margin-bottom: 16px;">⚠️</div>
2273
2273
  <p>加载历史消息失败</p>
2274
2274
  <p style="font-size: 14px; color: var(--text-tertiary);">${k.message}</p>
2275
2275
  </div>
2276
- `}const fe=document.getElementById("emojiBtn"),ie=document.getElementById("emojiPicker");_&&(fe.addEventListener("click",()=>{ie.classList.toggle("hidden")}),ie.addEventListener("emoji-click",k=>{Z.value+=k.detail.unicode,Z.focus(),ie.classList.add("hidden")}),document.addEventListener("click",k=>{!fe.contains(k.target)&&!ie.contains(k.target)&&ie.classList.add("hidden")})),"Notification"in window&&Notification.permission==="default"&&Notification.requestPermission(),t.on("chat_message",k=>{if(k.groupId===c._id){const p=document.createElement("div"),h=String(k.userId)===String(l)||k.username===r.username;p.className=`message ${h?"own":""}`,p.style.cssText=`
2276
+ `}const xe=document.getElementById("emojiBtn"),ie=document.getElementById("emojiPicker");_&&(xe.addEventListener("click",()=>{ie.classList.toggle("hidden")}),ie.addEventListener("emoji-click",k=>{Z.value+=k.detail.unicode,Z.focus(),ie.classList.add("hidden")}),document.addEventListener("click",k=>{!xe.contains(k.target)&&!ie.contains(k.target)&&ie.classList.add("hidden")})),"Notification"in window&&Notification.permission==="default"&&Notification.requestPermission(),t.on("chat_message",k=>{if(k.groupId===c._id){const p=document.createElement("div"),h=String(k.userId)===String(l)||k.username===r.username;p.className=`message ${h?"own":""}`,p.style.cssText=`
2277
2277
  margin-bottom: 16px;
2278
2278
  display: flex;
2279
2279
  flex-direction: column;
2280
2280
  align-items: ${h?"flex-end":"flex-start"};
2281
- `;const o=P(k.content),g=k.content.startsWith("[白板作品]")||k.content.startsWith("[投票]"),b=k.content.startsWith("[白板作品]");p.innerHTML=`
2281
+ `;const o=F(k.content),g=k.content.startsWith("[白板作品]")||k.content.startsWith("[投票]"),f=k.content.startsWith("[白板作品]");p.innerHTML=`
2282
2282
  <div class="message-header" style="display: flex; gap: 8px; margin-bottom: 4px; font-size: 12px; color: var(--text-tertiary);">
2283
2283
  <span class="message-user">${k.username}</span>
2284
2284
  <span class="message-time">${new Date(k.timestamp).toLocaleTimeString("zh-CN")}</span>
2285
2285
  </div>
2286
- <div class="message-content" style="background: ${b||g?"transparent":h?"linear-gradient(135deg, #667eea 0%, #764ba2 100%)":"var(--bg-tertiary)"}; color: ${h&&!g?"white":"var(--text-primary)"}; padding: ${g?"0":"12px 16px"}; border-radius: 16px; max-width: ${g?"90%":"70%"}; word-wrap: break-word; box-shadow: ${h&&!g?"0 4px 12px rgba(102, 126, 234, 0.3)":"0 2px 8px rgba(0,0,0,0.05)"};">${o}</div>
2287
- `,O.appendChild(p),O.scrollTop=O.scrollHeight,h||z(`${k.username} 在 ${c.name}`,k.content.startsWith("[")?"发送了特殊消息":k.content)}}),t.on("chat_blocked",k=>{if(k.groupId===c._id){const p=document.createElement("div");p.style.cssText=`
2286
+ <div class="message-content" style="background: ${f||g?"transparent":h?"linear-gradient(135deg, #667eea 0%, #764ba2 100%)":"var(--bg-tertiary)"}; color: ${h&&!g?"white":"var(--text-primary)"}; padding: ${g?"0":"12px 16px"}; border-radius: 16px; max-width: ${g?"90%":"70%"}; word-wrap: break-word; box-shadow: ${h&&!g?"0 4px 12px rgba(102, 126, 234, 0.3)":"0 2px 8px rgba(0,0,0,0.05)"};">${o}</div>
2287
+ `,O.appendChild(p),O.scrollTop=O.scrollHeight,h||A(`${k.username} 在 ${c.name}`,k.content.startsWith("[")?"发送了特殊消息":k.content)}}),t.on("chat_blocked",k=>{if(k.groupId===c._id){const p=document.createElement("div");p.style.cssText=`
2288
2288
  text-align: center;
2289
2289
  padding: 12px;
2290
2290
  margin: 16px auto;
@@ -2300,7 +2300,7 @@
2300
2300
  color: white;
2301
2301
  border-radius: 8px;
2302
2302
  max-width: 80%;
2303
- `,p.textContent=`${k.username} 已响应点名`,O.appendChild(p),O.scrollTop=O.scrollHeight}});const we=()=>{if(!_){alert(N?"全体禁言中,无法发言":"你已被禁言");return}const k=Z.value.trim();if(k)try{t.sendChatMessage(c._id,r.username,k),Z.value=""}catch(p){console.error("发送消息失败:",p),alert("发送失败: "+p.message)}};_&&(Y.addEventListener("click",we),Z.addEventListener("keypress",k=>{k.key==="Enter"&&!k.shiftKey&&(k.preventDefault(),we())}));const ae=document.querySelectorAll(".chat-tab"),v=document.querySelectorAll(".tab-content");ae.forEach(k=>{k.addEventListener("click",()=>{const p=k.dataset.tab;ae.forEach(h=>{h.dataset.tab===p?(h.style.background="var(--primary)",h.style.color="white"):(h.style.background="transparent",h.style.color="var(--text-primary)")}),v.forEach(h=>{h.dataset.content===p?h.style.display="block":h.style.display="none"}),p==="whiteboard"&&V()})});const x=document.getElementById("aiChat"),w=document.getElementById("aiInput"),B=document.getElementById("aiSendBtn"),L=async()=>{const k=w.value.trim();if(!k)return;const p=document.createElement("div");p.style.cssText=`
2303
+ `,p.textContent=`${k.username} 已响应点名`,O.appendChild(p),O.scrollTop=O.scrollHeight}});const we=()=>{if(!_){alert(N?"全体禁言中,无法发言":"你已被禁言");return}const k=Z.value.trim();if(k)try{t.sendChatMessage(c._id,r.username,k),Z.value=""}catch(p){console.error("发送消息失败:",p),alert("发送失败: "+p.message)}};_&&(Y.addEventListener("click",we),Z.addEventListener("keypress",k=>{k.key==="Enter"&&!k.shiftKey&&(k.preventDefault(),we())}));const ae=document.querySelectorAll(".chat-tab"),v=document.querySelectorAll(".tab-content");ae.forEach(k=>{k.addEventListener("click",()=>{const p=k.dataset.tab;ae.forEach(h=>{h.dataset.tab===p?(h.style.background="var(--primary)",h.style.color="white"):(h.style.background="transparent",h.style.color="var(--text-primary)")}),v.forEach(h=>{h.dataset.content===p?h.style.display="block":h.style.display="none"}),p==="whiteboard"&&V()})});const b=document.getElementById("aiChat"),w=document.getElementById("aiInput"),B=document.getElementById("aiSendBtn"),L=async()=>{const k=w.value.trim();if(!k)return;const p=document.createElement("div");p.style.cssText=`
2304
2304
  background: var(--primary);
2305
2305
  color: white;
2306
2306
  padding: 12px 16px;
@@ -2309,7 +2309,7 @@
2309
2309
  max-width: 80%;
2310
2310
  margin-left: auto;
2311
2311
  word-wrap: break-word;
2312
- `,p.textContent=k,x.appendChild(p),w.value="";const h=document.createElement("div");h.style.cssText=`
2312
+ `,p.textContent=k,b.appendChild(p),w.value="";const h=document.createElement("div");h.style.cssText=`
2313
2313
  background: var(--bg-tertiary);
2314
2314
  color: var(--text-secondary);
2315
2315
  padding: 12px 16px;
@@ -2317,7 +2317,7 @@
2317
2317
  margin-bottom: 16px;
2318
2318
  max-width: 80%;
2319
2319
  font-style: italic;
2320
- `,h.textContent="🤔 思考中...",x.appendChild(h),x.scrollTop=x.scrollHeight;try{const o=localStorage.getItem("token"),b=await(await fetch("http://localhost:3000/api/ai/ask",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({question:k,groupId:c==null?void 0:c._id})})).json();h.remove();const E=document.createElement("div");E.style.cssText=`
2320
+ `,h.textContent="🤔 思考中...",b.appendChild(h),b.scrollTop=b.scrollHeight;try{const o=localStorage.getItem("token"),f=await(await fetch("http://localhost:3000/api/ai/ask",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({question:k,groupId:c==null?void 0:c._id})})).json();h.remove();const E=document.createElement("div");E.style.cssText=`
2321
2321
  background: var(--bg-tertiary);
2322
2322
  color: var(--text-primary);
2323
2323
  padding: 12px 16px;
@@ -2326,21 +2326,21 @@
2326
2326
  max-width: 80%;
2327
2327
  line-height: 1.6;
2328
2328
  word-wrap: break-word;
2329
- `,E.textContent=b.answer||"抱歉,我无法回答这个问题。",x.appendChild(E),x.scrollTop=x.scrollHeight}catch(o){h.remove();const g=document.createElement("div");g.style.cssText=`
2329
+ `,E.textContent=f.answer||"抱歉,我无法回答这个问题。",b.appendChild(E),b.scrollTop=b.scrollHeight}catch(o){h.remove();const g=document.createElement("div");g.style.cssText=`
2330
2330
  background: var(--danger);
2331
2331
  color: white;
2332
2332
  padding: 12px 16px;
2333
2333
  border-radius: 12px;
2334
2334
  margin-bottom: 16px;
2335
2335
  max-width: 80%;
2336
- `,g.textContent="抱歉,发生了错误: "+o.message,x.appendChild(g),x.scrollTop=x.scrollHeight}};B.addEventListener("click",L),w.addEventListener("keypress",k=>{k.key==="Enter"&&!k.shiftKey&&(k.preventDefault(),L())})}catch(z){console.error("加载群聊失败:",z),U.innerHTML=`
2336
+ `,g.textContent="抱歉,发生了错误: "+o.message,b.appendChild(g),b.scrollTop=b.scrollHeight}};B.addEventListener("click",L),w.addEventListener("keypress",k=>{k.key==="Enter"&&!k.shiftKey&&(k.preventDefault(),L())})}catch(A){console.error("加载群聊失败:",A),P.innerHTML=`
2337
2337
  <div class="empty-state" style="text-align: center; padding: 60px 20px;">
2338
2338
  <div style="font-size: 64px; margin-bottom: 20px;">⚠️</div>
2339
2339
  <h3 style="font-size: 24px; margin-bottom: 12px; color: var(--danger);">加载失败</h3>
2340
- <p style="color: var(--text-secondary); margin-bottom: 24px;">${z.message}</p>
2340
+ <p style="color: var(--text-secondary); margin-bottom: 24px;">${A.message}</p>
2341
2341
  <button class="btn-primary" onclick="location.reload()">重新加载</button>
2342
2342
  </div>
2343
- `}}async function te(U){U.innerHTML=`
2343
+ `}}async function te(P){P.innerHTML=`
2344
2344
  <div class="view-header">
2345
2345
  <h2>🔍 搜索</h2>
2346
2346
  </div>
@@ -2362,7 +2362,7 @@
2362
2362
  </div>
2363
2363
  <div class="search-results" id="searchResults"></div>
2364
2364
  </div>
2365
- `;const z=document.getElementById("searchInput"),V=document.getElementById("searchBtn"),$=document.getElementById("searchResults"),M=async()=>{const N=z.value.trim();if(!N){$.innerHTML='<div class="empty-state">请输入搜索关键词</div>';return}const H={messages:document.getElementById("filterMessages").checked,documents:document.getElementById("filterDocuments").checked,tasks:document.getElementById("filterTasks").checked};$.innerHTML='<div class="loading">搜索中...</div>';try{const _=[];if(H.messages&&c)try{const O=await s.getGroupMessages(c._id);O.messages&&O.messages.filter(Y=>Y.content.toLowerCase().includes(N.toLowerCase())).forEach(Y=>{_.push({type:"message",title:`消息 - ${Y.username}`,content:Y.content,time:Y.timestamp,group:c.name})})}catch(O){console.error("搜索消息失败:",O)}if(H.documents)try{if(c){const O=await s.getDocuments(c._id);O.documents&&O.documents.filter(Y=>Y.title.toLowerCase().includes(N.toLowerCase())||Y.content.toLowerCase().includes(N.toLowerCase())).forEach(Y=>{_.push({type:"document",title:Y.title,content:Y.content.substring(0,200),time:Y.updatedAt,id:Y._id,group:c.name})})}}catch(O){console.error("搜索文档失败:",O)}if(H.tasks)try{const O=await s.getMyTasks();O.tasks&&O.tasks.filter(Y=>Y.title.toLowerCase().includes(N.toLowerCase())||Y.description&&Y.description.toLowerCase().includes(N.toLowerCase())).forEach(Y=>{_.push({type:"task",title:Y.title,content:Y.description||"",time:Y.updatedAt,id:Y._id,status:Y.status})})}catch(O){console.error("搜索任务失败:",O)}_.length===0?$.innerHTML='<div class="empty-state">未找到相关结果</div>':$.innerHTML=_.map(O=>`
2365
+ `;const A=document.getElementById("searchInput"),V=document.getElementById("searchBtn"),$=document.getElementById("searchResults"),M=async()=>{const N=A.value.trim();if(!N){$.innerHTML='<div class="empty-state">请输入搜索关键词</div>';return}const H={messages:document.getElementById("filterMessages").checked,documents:document.getElementById("filterDocuments").checked,tasks:document.getElementById("filterTasks").checked};$.innerHTML='<div class="loading">搜索中...</div>';try{const _=[];if(H.messages&&c)try{const O=await s.getGroupMessages(c._id);O.messages&&O.messages.filter(Y=>Y.content.toLowerCase().includes(N.toLowerCase())).forEach(Y=>{_.push({type:"message",title:`消息 - ${Y.username}`,content:Y.content,time:Y.timestamp,group:c.name})})}catch(O){console.error("搜索消息失败:",O)}if(H.documents)try{if(c){const O=await s.getDocuments(c._id);O.documents&&O.documents.filter(Y=>Y.title.toLowerCase().includes(N.toLowerCase())||Y.content.toLowerCase().includes(N.toLowerCase())).forEach(Y=>{_.push({type:"document",title:Y.title,content:Y.content.substring(0,200),time:Y.updatedAt,id:Y._id,group:c.name})})}}catch(O){console.error("搜索文档失败:",O)}if(H.tasks)try{const O=await s.getMyTasks();O.tasks&&O.tasks.filter(Y=>Y.title.toLowerCase().includes(N.toLowerCase())||Y.description&&Y.description.toLowerCase().includes(N.toLowerCase())).forEach(Y=>{_.push({type:"task",title:Y.title,content:Y.description||"",time:Y.updatedAt,id:Y._id,status:Y.status})})}catch(O){console.error("搜索任务失败:",O)}_.length===0?$.innerHTML='<div class="empty-state">未找到相关结果</div>':$.innerHTML=_.map(O=>`
2366
2366
  <div class="search-result-item">
2367
2367
  <div class="result-header">
2368
2368
  <span class="result-type">${{message:"💬",document:"📄",task:"📋"}[O.type]} ${O.type==="message"?"消息":O.type==="document"?"文档":"任务"}</span>
@@ -2373,7 +2373,7 @@
2373
2373
  ${O.group?`<span class="result-group">群组: ${O.group}</span>`:""}
2374
2374
  ${O.status?`<span class="result-status">状态: ${se(O.status)}</span>`:""}
2375
2375
  </div>
2376
- `).join("")}catch(_){$.innerHTML=`<div class="empty-state">搜索失败: ${_.message}</div>`}};V.addEventListener("click",M),z.addEventListener("keypress",N=>{N.key==="Enter"&&M()})}function me(U,z){if(!z)return U;const V=new RegExp(`(${z})`,"gi");return U.replace(V,"<mark>$1</mark>")}function se(U){return{pending:"待处理",in_progress:"进行中",completed:"已完成",terminated:"已终止"}[U]||U}async function ve(U){if(!c){U.innerHTML=`
2376
+ `).join("")}catch(_){$.innerHTML=`<div class="empty-state">搜索失败: ${_.message}</div>`}};V.addEventListener("click",M),A.addEventListener("keypress",N=>{N.key==="Enter"&&M()})}function me(P,A){if(!A)return P;const V=new RegExp(`(${A})`,"gi");return P.replace(V,"<mark>$1</mark>")}function se(P){return{pending:"待处理",in_progress:"进行中",completed:"已完成",terminated:"已终止"}[P]||P}async function ve(P){if(!c){P.innerHTML=`
2377
2377
  <div class="empty-state" style="text-align: center; padding: 60px 20px; background: var(--bg-secondary); border-radius: 16px; border: 2px dashed var(--border);">
2378
2378
  <div style="font-size: 64px; margin-bottom: 20px;">📚</div>
2379
2379
  <h3 style="font-size: 24px; margin-bottom: 12px; color: var(--text-primary);">知识库</h3>
@@ -2382,7 +2382,7 @@
2382
2382
  前往我的群组
2383
2383
  </button>
2384
2384
  </div>
2385
- `;return}try{const z=localStorage.getItem("token"),V=await fetch(`http://localhost:3000/api/knowledge/group/${c._id}`,{headers:{Authorization:`Bearer ${z}`}});if(!V.ok)throw new Error(`HTTP ${V.status}: ${V.statusText}`);const $=await V.json();let M=[];Array.isArray($)?M=$:$.data&&Array.isArray($.data)?M=$.data:$.data&&$.data.knowledgeList&&Array.isArray($.data.knowledgeList)?M=$.data.knowledgeList:$.items&&Array.isArray($.items)?M=$.items:$.knowledge&&Array.isArray($.knowledge)&&(M=$.knowledge),U.innerHTML=`
2385
+ `;return}try{const A=localStorage.getItem("token"),V=await fetch(`http://localhost:3000/api/knowledge/group/${c._id}`,{headers:{Authorization:`Bearer ${A}`}});if(!V.ok)throw new Error(`HTTP ${V.status}: ${V.statusText}`);const $=await V.json();let M=[];Array.isArray($)?M=$:$.data&&Array.isArray($.data)?M=$.data:$.data&&$.data.knowledgeList&&Array.isArray($.data.knowledgeList)?M=$.data.knowledgeList:$.items&&Array.isArray($.items)?M=$.items:$.knowledge&&Array.isArray($.knowledge)&&(M=$.knowledge),P.innerHTML=`
2386
2386
  <div class="view-header">
2387
2387
  <h2>📚 知识库 - ${c.name}</h2>
2388
2388
  <button class="btn-primary" id="createKnowledgeBtn">📝 创建知识条目</button>
@@ -2443,14 +2443,14 @@
2443
2443
  <button class="btn-secondary btn-sm" data-id="${H._id}" data-action="edit" style="flex: 1;">✏️ 编辑</button>
2444
2444
  <button class="btn-danger btn-sm" data-id="${H._id}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
2445
2445
  </div>
2446
- `,_.onmouseenter=()=>{_.style.transform="translateY(-4px)",_.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},_.onmouseleave=()=>{_.style.transform="translateY(0)",_.style.boxShadow="none"},N.appendChild(_)}),document.querySelectorAll('[data-action="edit"]').forEach(H=>{H.addEventListener("click",async()=>{var O;const _=M.find(Z=>Z._id===H.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=_.title,document.querySelector('[name="content"]').value=_.content,document.querySelector('[name="tags"]').value=((O=_.tags)==null?void 0:O.join(", "))||"",document.getElementById("isSharedCheckbox").checked=_.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=_._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="delete"]').forEach(H=>{H.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:3000/api/knowledge/${H.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${z}`}}),alert("删除成功!"),await ve(U)}catch(_){alert("删除失败: "+_.message)}})})),document.getElementById("createKnowledgeBtn").addEventListener("click",()=>{document.getElementById("modalTitle").textContent="创建知识条目",document.getElementById("knowledgeForm").reset(),delete document.getElementById("knowledgeForm").dataset.editId,document.getElementById("knowledgeModal").classList.remove("hidden")}),document.getElementById("closeKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("cancelKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("knowledgeForm").addEventListener("submit",async H=>{H.preventDefault();const _=new FormData(H.target),O={title:_.get("title"),content:_.get("content"),tags:_.get("tags").split(",").map(Z=>Z.trim()).filter(Z=>Z),groupId:c._id,isShared:document.getElementById("isSharedCheckbox").checked};try{const Z=H.target.dataset.editId,Y=Z?`http://localhost:3000/api/knowledge/${Z}`:"http://localhost:3000/api/knowledge";if(!(await fetch(Y,{method:Z?"PUT":"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${z}`},body:JSON.stringify(O)})).ok)throw new Error("操作失败");alert(Z?"更新成功!":"创建成功!"),document.getElementById("knowledgeModal").classList.add("hidden"),await ve(U)}catch(Z){alert("操作失败: "+Z.message)}})}catch(z){console.error("加载知识库失败:",z),U.innerHTML=`
2446
+ `,_.onmouseenter=()=>{_.style.transform="translateY(-4px)",_.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},_.onmouseleave=()=>{_.style.transform="translateY(0)",_.style.boxShadow="none"},N.appendChild(_)}),document.querySelectorAll('[data-action="edit"]').forEach(H=>{H.addEventListener("click",async()=>{var O;const _=M.find(Z=>Z._id===H.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=_.title,document.querySelector('[name="content"]').value=_.content,document.querySelector('[name="tags"]').value=((O=_.tags)==null?void 0:O.join(", "))||"",document.getElementById("isSharedCheckbox").checked=_.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=_._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="delete"]').forEach(H=>{H.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:3000/api/knowledge/${H.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${A}`}}),alert("删除成功!"),await ve(P)}catch(_){alert("删除失败: "+_.message)}})})),document.getElementById("createKnowledgeBtn").addEventListener("click",()=>{document.getElementById("modalTitle").textContent="创建知识条目",document.getElementById("knowledgeForm").reset(),delete document.getElementById("knowledgeForm").dataset.editId,document.getElementById("knowledgeModal").classList.remove("hidden")}),document.getElementById("closeKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("cancelKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("knowledgeForm").addEventListener("submit",async H=>{H.preventDefault();const _=new FormData(H.target),O={title:_.get("title"),content:_.get("content"),tags:_.get("tags").split(",").map(Z=>Z.trim()).filter(Z=>Z),groupId:c._id,isShared:document.getElementById("isSharedCheckbox").checked};try{const Z=H.target.dataset.editId,Y=Z?`http://localhost:3000/api/knowledge/${Z}`:"http://localhost:3000/api/knowledge";if(!(await fetch(Y,{method:Z?"PUT":"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${A}`},body:JSON.stringify(O)})).ok)throw new Error("操作失败");alert(Z?"更新成功!":"创建成功!"),document.getElementById("knowledgeModal").classList.add("hidden"),await ve(P)}catch(Z){alert("操作失败: "+Z.message)}})}catch(A){console.error("加载知识库失败:",A),P.innerHTML=`
2447
2447
  <div class="view-header">
2448
2448
  <h2>📚 知识库 - ${c.name}</h2>
2449
2449
  </div>
2450
2450
  <div class="empty-state" style="text-align: center; padding: 40px 20px;">
2451
2451
  <div style="font-size: 48px; margin-bottom: 16px;">⚠️</div>
2452
2452
  <h3 style="margin-bottom: 8px; color: var(--danger);">加载失败</h3>
2453
- <p style="color: var(--text-secondary); margin-bottom: 16px;">${z.message}</p>
2453
+ <p style="color: var(--text-secondary); margin-bottom: 16px;">${A.message}</p>
2454
2454
  <button class="btn-primary" onclick="location.reload()">重新加载</button>
2455
2455
  </div>
2456
- `}}A("groups")}class ta{constructor(){this.authService=new Je,this.wsService=new xn,this.currentUser=null,this.init()}async init(){const t=localStorage.getItem("token");if(t)try{this.currentUser=await this.authService.getCurrentUser(),this.wsService.connect(t),this.renderDashboard()}catch(i){console.error("认证失败:",i),this.renderLogin()}else this.renderLogin()}renderLogin(){vn(async(t,i)=>{this.currentUser=t,localStorage.setItem("token",i),this.wsService.connect(i),this.renderDashboard()})}renderDashboard(){this.currentUser.role==="admin"?Zr(this.currentUser,this.wsService):ea(this.currentUser,this.wsService)}}new ta;
2456
+ `}}D("groups")}class ta{constructor(){this.authService=new Je,this.wsService=new bn,this.currentUser=null,this.init()}async init(){const t=localStorage.getItem("token");if(t)try{this.currentUser=await this.authService.getCurrentUser(),this.wsService.connect(t),this.renderDashboard()}catch(i){console.error("认证失败:",i),this.renderLogin()}else this.renderLogin()}renderLogin(){vn(async(t,i)=>{this.currentUser=t,localStorage.setItem("token",i),this.wsService.connect(i),this.renderDashboard()})}renderDashboard(){this.currentUser.role==="admin"?Zr(this.currentUser,this.wsService):ea(this.currentUser,this.wsService)}}new ta;