aicq-chat-plugin 2.5.9 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/index.html CHANGED
@@ -3,131 +3,142 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta name="theme-color" content="#D97757">
6
7
  <title>AICQ 加密聊天</title>
8
+ <link rel="icon" type="image/png" sizes="32x32" href="/icon-32.png">
9
+ <link rel="icon" type="image/png" sizes="16x16" href="/icon-16.png">
10
+ <link rel="icon" type="image/x-icon" href="/favicon.ico">
7
11
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
8
12
  <script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
9
13
  <script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
10
14
  <script src="https://cdn.jsdelivr.net/npm/marked@12.0.0/marked.min.js"></script>
11
15
  <style>
12
16
  *{margin:0;padding:0;box-sizing:border-box}
13
- :root{--primary:#4f46e5;--primary-light:#6366f1;--bg:#0f172a;--bg2:#1e293b;--bg3:#334155;--text:#f1f5f9;--text2:#94a3b8;--border:#475569;--success:#22c55e;--danger:#ef4444;--warning:#f59e0b;--info:#3b82f6;--bubble-me:#4f46e5;--bubble-them:#334155}
14
- body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans SC",sans-serif;background:var(--bg);color:var(--text);display:flex;height:100vh;overflow:hidden}
17
+ :root{--primary:#D97757;--primary-light:#C4613F;--primary-lighter:rgba(217,119,87,0.1);--accent:#D97757;--accent-hover:#C4613F;--accent-light:rgba(217,119,87,0.1);--bg:#FAF9F6;--bg2:#F5F1EB;--bg-warm:#F5F1EB;--bg3:#FFFFFF;--bg-card:#FFFFFF;--text:#2D2A26;--text2:#6B6560;--text-sec:#6B6560;--text-muted:#9B958E;--border:#E8DFD3;--beige:#E8DFD3;--success:#4CAF7D;--green:#4CAF7D;--danger:#E05555;--red:#E05555;--warning:#E5A54B;--amber:#E5A54B;--brown:#8B6F4E;--brown-light:rgba(139,111,78,0.1);--cream:#F0EAE0;--info:#5B8DEF;--blue:#5B8DEF;--purple:#7B6CB0;--bubble-me:#D97757;--bubble-them:#FFFFFF;--shadow-sm:0 1px 3px rgba(45,42,38,0.06);--shadow-md:0 4px 16px rgba(45,42,38,0.08);--shadow-lg:0 8px 32px rgba(45,42,38,0.1);--radius:12px;--radius-sm:8px;--radius-lg:20px;--transition:all 0.25s cubic-bezier(0.4,0,0.2,1)}
18
+ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans SC",sans-serif;background:var(--bg);color:var(--text);display:flex;height:100vh;overflow:hidden;-webkit-font-smoothing:antialiased}
15
19
  /* Layout */
16
20
  .app{display:flex;width:100%;height:100%}
17
- .right-panel{width:280px;background:var(--bg2);border-right:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0}
21
+ .right-panel{width:280px;background:var(--bg3);border-right:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0}
18
22
  .main-panel{flex:1;display:flex;flex-direction:column;min-width:0}
19
23
  .chat-area{flex:1;overflow:hidden;display:flex;flex-direction:column}
20
24
  /* Right Panel */
21
25
  .agent-select{padding:12px;border-bottom:1px solid var(--border)}
22
- .agent-select select{width:100%;padding:8px 12px;background:var(--bg3);color:var(--text);border:1px solid var(--border);border-radius:6px;font-size:14px;cursor:pointer}
26
+ .agent-select select{width:100%;padding:8px 12px;background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:10px;font-size:14px;cursor:pointer}
23
27
  .action-buttons{display:flex;gap:6px;padding:10px 12px;border-bottom:1px solid var(--border)}
24
- .action-btn{flex:1;padding:7px 4px;background:var(--bg3);color:var(--text2);border:none;border-radius:6px;cursor:pointer;font-size:12px;display:flex;flex-direction:column;align-items:center;gap:3px;transition:all .2s}
25
- .action-btn:hover{background:var(--primary);color:#fff}
28
+ .action-btn{flex:1;padding:7px 4px;background:var(--cream);color:var(--text2);border:1px solid var(--border);border-radius:10px;cursor:pointer;font-size:12px;display:flex;flex-direction:column;align-items:center;gap:3px;transition:var(--transition)}
29
+ .action-btn:hover{background:var(--primary);color:#fff;border-color:var(--primary)}
26
30
  .action-btn .icon{font-size:18px}
27
31
  .list-section{flex:1;overflow-y:auto}
28
- .list-section h4{padding:10px 12px 6px;color:var(--text2);font-size:12px;text-transform:uppercase;letter-spacing:1px}
29
- .friend-item,.group-item{display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer;transition:background .15s;border-left:3px solid transparent}
30
- .friend-item:hover,.group-item:hover{background:var(--bg3)}
31
- .friend-item.active,.group-item.active{background:rgba(79,70,229,.2);border-left-color:var(--primary)}
32
- .avatar{width:36px;height:36px;border-radius:50%;background:var(--primary);display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:600;flex-shrink:0;color:#fff;overflow:hidden}
33
- .avatar img{width:100%;height:100%;object-fit:cover;border-radius:50%}
32
+ .list-section h4{padding:10px 12px 6px;color:var(--text-muted);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:1.5px}
33
+ .friend-item,.group-item{display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer;transition:var(--transition);border-left:3px solid transparent}
34
+ .friend-item:hover,.group-item:hover{background:var(--cream)}
35
+ .friend-item.active,.group-item.active{background:var(--primary-lighter);border-left-color:var(--primary)}
36
+ .avatar{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,var(--primary),var(--brown));display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:600;flex-shrink:0;color:#fff;overflow:hidden}
37
+ .avatar img{width:100%;height:100%;object-fit:cover;border-radius:12px}
34
38
  .avatar.online{box-shadow:0 0 0 2px var(--success)}
35
39
  .info{flex:1;min-width:0}
36
40
  .info .name{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
37
41
  .info .status{font-size:11px;color:var(--text2)}
38
42
  .badge-online{color:var(--success);font-size:10px}
39
43
  .badge-offline{color:var(--text2);font-size:10px}
40
- .silent-badge{font-size:9px;background:var(--warning);color:#000;padding:1px 4px;border-radius:3px;margin-left:4px}
44
+ .silent-badge{font-size:9px;background:var(--amber);color:#fff;padding:1px 4px;border-radius:4px;margin-left:4px}
41
45
  /* Chat Header */
42
- .chat-header{padding:12px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;background:var(--bg2)}
46
+ .chat-header{padding:12px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;background:var(--bg3)}
43
47
  .chat-header .avatar{width:40px;height:40px;font-size:16px}
44
48
  .chat-header .info .name{font-size:16px}
45
49
  .chat-header .actions{margin-left:auto;display:flex;gap:8px}
46
- .chat-header .actions button{background:none;border:none;color:var(--text2);cursor:pointer;font-size:18px;padding:4px 8px;border-radius:4px}
47
- .chat-header .actions button:hover{background:var(--bg3);color:var(--text)}
50
+ .chat-header .actions button{background:none;border:none;color:var(--text2);cursor:pointer;font-size:18px;padding:4px 8px;border-radius:var(--radius-sm);transition:var(--transition)}
51
+ .chat-header .actions button:hover{background:var(--cream);color:var(--primary)}
48
52
  /* Messages */
49
- .messages-container{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:4px}
53
+ .messages-container{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:4px;background:var(--bg2)}
50
54
  .load-more{text-align:center;padding:8px;color:var(--text2);font-size:12px;cursor:pointer}
51
55
  .load-more:hover{color:var(--primary)}
52
56
  .msg-row{display:flex;max-width:75%;gap:8px}
53
57
  .msg-row.me{margin-left:auto;flex-direction:row-reverse}
54
58
  .msg-row.them{margin-right:auto}
55
- .msg-bubble{padding:10px 14px;border-radius:12px;font-size:14px;line-height:1.6;word-break:break-word;position:relative;max-width:100%}
56
- .msg-row.me .msg-bubble{background:var(--bubble-me);color:#fff;border-bottom-right-radius:4px}
57
- .msg-row.them .msg-bubble{background:var(--bubble-them);color:var(--text);border-bottom-left-radius:4px}
59
+ .msg-bubble{padding:10px 14px;border-radius:14px;font-size:14px;line-height:1.6;word-break:break-word;position:relative;max-width:100%}
60
+ .msg-row.me .msg-bubble{background:var(--bubble-me);color:#fff;border-top-right-radius:4px}
61
+ .msg-row.them .msg-bubble{background:var(--bubble-them);border:1px solid var(--border);color:var(--text);border-top-left-radius:4px}
58
62
  .msg-bubble img{max-width:300px;max-height:300px;border-radius:8px;margin-top:6px;cursor:pointer}
59
63
  .msg-bubble .file-link{display:flex;align-items:center;gap:6px;padding:6px 10px;background:rgba(255,255,255,.1);border-radius:6px;margin-top:6px;cursor:pointer;color:inherit;text-decoration:none}
60
64
  .msg-bubble .file-link:hover{background:rgba(255,255,255,.2)}
61
65
  .msg-time{font-size:10px;color:var(--text2);margin-top:4px;text-align:right}
66
+ .msg-row.me .msg-time{color:rgba(255,255,255,0.6)}
62
67
  .msg-row.them .msg-time{text-align:left}
63
68
  .msg-actions{position:absolute;top:-8px;right:-4px;display:none;gap:2px}
64
69
  .msg-row.me .msg-actions{right:auto;left:-4px}
65
70
  .msg-row:hover .msg-actions{display:flex}
66
- .msg-action-btn{width:24px;height:24px;border-radius:50%;background:var(--bg3);border:none;color:var(--text2);cursor:pointer;font-size:11px;display:flex;align-items:center;justify-content:center}
67
- .msg-action-btn:hover{background:var(--primary);color:#fff}
68
- .msg-action-btn.danger:hover{background:var(--danger)}
71
+ .msg-action-btn{width:24px;height:24px;border-radius:var(--radius-sm);background:var(--bg3);border:1px solid var(--border);color:var(--text2);cursor:pointer;font-size:11px;display:flex;align-items:center;justify-content:center;transition:var(--transition)}
72
+ .msg-action-btn:hover{background:var(--primary);color:#fff;border-color:var(--primary)}
73
+ .msg-action-btn.danger:hover{background:var(--danger);border-color:var(--danger)}
69
74
  /* Mention */
70
75
  .mention{color:var(--info);font-weight:600;cursor:pointer}
71
76
  .mention:hover{text-decoration:underline}
72
77
  /* Input Area */
73
- .input-area{padding:12px 16px;border-top:1px solid var(--border);background:var(--bg2);display:flex;flex-direction:column;gap:8px}
78
+ .input-area{padding:12px 16px;border-top:1px solid var(--border);background:var(--bg3);display:flex;flex-direction:column;gap:8px}
74
79
  .input-top{display:flex;gap:8px;align-items:center}
75
- .input-top input{flex:1;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:8px;color:var(--text);font-size:14px;outline:none}
76
- .input-top input:focus{border-color:var(--primary)}
77
- .send-btn{padding:10px 20px;background:var(--primary);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:500;transition:background .2s}
78
- .send-btn:hover{background:var(--primary-light)}
79
- .send-btn:disabled{opacity:.5;cursor:not-allowed}
80
+ .input-top input{flex:1;padding:10px 14px;background:var(--bg);border:1px solid var(--border);border-radius:12px;color:var(--text);font-size:14px;outline:none;transition:var(--transition)}
81
+ .input-top input:focus{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-lighter)}
82
+ .send-btn{padding:10px 20px;background:var(--primary);color:#fff;border:none;border-radius:10px;cursor:pointer;font-size:14px;font-weight:500;box-shadow:0 4px 16px rgba(217,119,87,0.3);transition:var(--transition)}
83
+ .send-btn:hover{background:var(--primary-light);transform:scale(1.05)}
84
+ .send-btn:disabled{opacity:.5;cursor:not-allowed;transform:none}
80
85
  .input-toolbar{display:flex;gap:4px}
81
- .tool-btn{background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px 8px;border-radius:4px}
82
- .tool-btn:hover{background:var(--bg3);color:var(--text)}
86
+ .tool-btn{background:none;border:none;color:var(--text2);cursor:pointer;font-size:16px;padding:4px 8px;border-radius:var(--radius-sm);transition:var(--transition)}
87
+ .tool-btn:hover{background:var(--cream);color:var(--primary)}
83
88
  /* Modals */
84
- .modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);display:none;align-items:center;justify-content:center;z-index:1000}
89
+ .modal-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(45,42,38,0.4);display:none;align-items:center;justify-content:center;z-index:1000}
85
90
  .modal-overlay.show{display:flex}
86
- .modal{background:var(--bg2);border:1px solid var(--border);border-radius:12px;padding:24px;max-width:480px;width:90%;max-height:80vh;overflow-y:auto}
91
+ .modal{background:var(--bg3);border:1px solid var(--border);border-radius:20px;padding:24px;max-width:480px;width:90%;max-height:80vh;overflow-y:auto;box-shadow:var(--shadow-lg)}
87
92
  .modal h3{margin-bottom:16px;font-size:18px}
88
93
  .modal .form-group{margin-bottom:14px}
89
94
  .modal label{display:block;margin-bottom:6px;font-size:13px;color:var(--text2)}
90
- .modal input,.modal select,.modal textarea{width:100%;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:14px}
95
+ .modal input,.modal select,.modal textarea{width:100%;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:10px;color:var(--text);font-size:14px;transition:var(--transition)}
96
+ .modal input:focus,.modal select:focus,.modal textarea:focus{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-lighter);outline:none}
91
97
  .modal textarea{min-height:80px;resize:vertical}
92
98
  .modal .btn-row{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}
93
- .modal .btn{padding:8px 16px;border:none;border-radius:6px;cursor:pointer;font-size:14px;transition:all .2s}
99
+ .modal .btn{padding:8px 16px;border:none;border-radius:10px;cursor:pointer;font-size:14px;transition:var(--transition)}
94
100
  .modal .btn-primary{background:var(--primary);color:#fff}
95
101
  .modal .btn-primary:hover{background:var(--primary-light)}
96
- .modal .btn-secondary{background:var(--bg3);color:var(--text)}
102
+ .modal .btn-secondary{background:var(--cream);color:var(--text);border:1px solid var(--border)}
103
+ .modal .btn-secondary:hover{background:var(--primary-lighter);border-color:var(--primary);color:var(--primary)}
97
104
  .modal .btn-danger{background:var(--danger);color:#fff}
98
105
  .qr-container{text-align:center;margin:16px 0}
99
106
  .qr-container img{max-width:256px;border-radius:8px}
100
- .key-display{background:var(--bg);padding:10px;border-radius:6px;font-family:monospace;font-size:12px;word-break:break-all;margin:8px 0;color:var(--text2)}
101
- .warning-box{background:rgba(239,68,68,.15);border:1px solid var(--danger);border-radius:6px;padding:12px;margin:12px 0;color:#fca5a5;font-size:13px}
107
+ .key-display{background:var(--bg);padding:10px;border-radius:var(--radius-sm);font-family:monospace;font-size:12px;word-break:break-all;margin:8px 0;color:var(--text-muted)}
108
+ .warning-box{background:rgba(224,85,85,0.08);border:1px solid var(--danger);border-radius:var(--radius-sm);padding:12px;margin:12px 0;color:var(--danger);font-size:13px}
102
109
  /* Empty State */
103
- .empty-state{flex:1;display:flex;align-items:center;justify-content:center;color:var(--text2);font-size:16px;flex-direction:column;gap:12px}
110
+ .empty-state{flex:1;display:flex;align-items:center;justify-content:center;color:var(--text-muted);font-size:16px;flex-direction:column;gap:12px}
104
111
  .empty-state .icon{font-size:48px;opacity:.3}
105
112
  /* Mention dropdown */
106
- .mention-dropdown{position:absolute;bottom:100%;left:0;background:var(--bg2);border:1px solid var(--border);border-radius:6px;max-height:200px;overflow-y:auto;z-index:100;display:none;min-width:200px}
113
+ .mention-dropdown{position:absolute;bottom:100%;left:0;background:var(--bg3);border:1px solid var(--border);border-radius:10px;max-height:200px;overflow-y:auto;z-index:100;display:none;min-width:200px;box-shadow:var(--shadow-md)}
107
114
  .mention-dropdown.show{display:block}
108
115
  .mention-option{padding:8px 12px;cursor:pointer;font-size:13px;display:flex;align-items:center;gap:8px}
109
- .mention-option:hover{background:var(--bg3)}
116
+ .mention-option:hover{background:var(--cream)}
110
117
  /* Scrollbar */
111
118
  ::-webkit-scrollbar{width:6px}
112
- ::-webkit-scrollbar-track{background:var(--bg)}
119
+ ::-webkit-scrollbar-track{background:transparent}
113
120
  ::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}
114
- ::-webkit-scrollbar-thumb:hover{background:var(--text2)}
121
+ ::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}
115
122
  /* Markdown in bubbles */
116
123
  .msg-bubble p{margin:4px 0}
117
- .msg-bubble code{background:rgba(255,255,255,.1);padding:1px 4px;border-radius:3px;font-size:13px}
118
- .msg-bubble pre{background:rgba(0,0,0,.2);padding:8px;border-radius:6px;overflow-x:auto;margin:6px 0}
124
+ .msg-row.them .msg-bubble code{background:rgba(0,0,0,0.05);padding:1px 4px;border-radius:3px;font-size:13px}
125
+ .msg-row.me .msg-bubble code{background:rgba(255,255,255,0.2);padding:1px 4px;border-radius:3px;font-size:13px}
126
+ .msg-row.them .msg-bubble pre{background:rgba(0,0,0,0.04);padding:8px;border-radius:6px;overflow-x:auto;margin:6px 0}
127
+ .msg-row.me .msg-bubble pre{background:rgba(255,255,255,0.15);padding:8px;border-radius:6px;overflow-x:auto;margin:6px 0}
119
128
  .msg-bubble pre code{background:none;padding:0}
120
129
  .msg-bubble blockquote{border-left:3px solid var(--primary);padding-left:10px;margin:6px 0;color:var(--text2)}
121
130
  .msg-bubble ul,.msg-bubble ol{padding-left:20px;margin:4px 0}
122
- .msg-bubble a{color:var(--info)}
131
+ .msg-row.them .msg-bubble a{color:var(--primary)}
132
+ .msg-row.me .msg-bubble a{color:#fff;text-decoration:underline}
123
133
  .msg-bubble table{border-collapse:collapse;margin:6px 0}
124
- .msg-bubble th,.msg-bubble td{border:1px solid var(--border);padding:4px 8px;font-size:13px}
134
+ .msg-bubble th{background:var(--cream);border:1px solid var(--border);padding:4px 8px;font-size:13px}
135
+ .msg-bubble td{border:1px solid var(--border);padding:4px 8px;font-size:13px}
125
136
  /* Toast */
126
- .toast{position:fixed;top:20px;left:50%;transform:translateX(-50%);background:var(--bg2);border:1px solid var(--border);color:var(--text);padding:12px 24px;border-radius:8px;font-size:14px;z-index:9999;box-shadow:0 4px 20px rgba(0,0,0,.5);max-width:90%;text-align:center;opacity:0;transition:opacity .3s;pointer-events:none}
137
+ .toast{position:fixed;top:20px;left:50%;transform:translateX(-50%);background:var(--bg3);border:1px solid var(--border);color:var(--text);padding:12px 24px;border-radius:var(--radius);font-size:14px;z-index:9999;box-shadow:var(--shadow-lg);max-width:90%;text-align:center;opacity:0;transition:opacity .3s;pointer-events:none}
127
138
  .toast.show{opacity:1}
128
- .toast.warning{border-color:var(--warning);background:rgba(245,158,11,.15);color:#fcd34d}
139
+ .toast.warning{border-color:var(--warning);background:rgba(229,165,75,0.1);color:var(--warning)}
129
140
  /* Backup section */
130
- .backup-section{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:12px;margin-top:8px}
141
+ .backup-section{background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);padding:12px;margin-top:8px}
131
142
  .backup-section h4{font-size:14px;margin-bottom:8px;color:var(--text)}
132
143
  .backup-section p{font-size:12px;color:var(--text2);line-height:1.6;margin:4px 0}
133
144
  .backup-section .warning-box{font-size:12px;padding:8px;margin:8px 0}
@@ -137,7 +148,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans S
137
148
  .key-match-row{display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid var(--border)}
138
149
  .key-match-row:last-child{border-bottom:none}
139
150
  .key-match-row label{font-size:13px;color:var(--text2);min-width:120px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
140
- .key-match-row select{flex:1;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px}
151
+ .key-match-row select{flex:1;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:10px;color:var(--text);font-size:13px}
141
152
  </style>
142
153
  </head>
143
154
  <body>
@@ -993,20 +1004,37 @@ function showChatInfo() {
993
1004
  : `好友: ${currentTarget.name}\nID: ${currentTarget.id}\n状态: ${currentTarget.isOnline ? '在线' : '离线'}`);
994
1005
  }
995
1006
 
1007
+ // ─── Image Resize Utility ───────────────────────────────────────────
1008
+ function resizePluginImage(file,maxW,maxH,quality=0.8){
1009
+ return new Promise((resolve,reject)=>{
1010
+ if(!file.type.startsWith('image/')){reject(new Error('Not an image'));return;}
1011
+ const img=new Image();const url=URL.createObjectURL(file);
1012
+ img.onload=()=>{
1013
+ let w=img.width,h=img.height;
1014
+ if(w<=maxW&&h<=maxH&&file.size<=512*1024){URL.revokeObjectURL(url);resolve(file);return;}
1015
+ const ratio=Math.min(maxW/w,maxH/h,1);w=Math.round(w*ratio);h=Math.round(h*ratio);
1016
+ const canvas=document.createElement('canvas');canvas.width=w;canvas.height=h;
1017
+ const ctx=canvas.getContext('2d');ctx.drawImage(img,0,0,w,h);
1018
+ canvas.toBlob(blob=>{URL.revokeObjectURL(url);if(!blob){reject(new Error('Resize failed'));return;}resolve(new File([blob],file.name.replace(/\.\w+$/,'.jpg'),{type:'image/jpeg',lastModified:Date.now()}));},'image/jpeg',quality);
1019
+ };
1020
+ img.onerror=()=>{URL.revokeObjectURL(url);reject(new Error('Image load failed'));};
1021
+ img.src=url;
1022
+ });
1023
+ }
1024
+
996
1025
  // ─── Avatar Upload ──────────────────────────────────────────────────
997
1026
  async function handlePluginAvatarUpload(input) {
998
- const file = input.files && input.files[0];
999
- if (!file || !currentAgentId) return;
1000
- if (!file.type.startsWith('image/')) { alert('请选择图片文件'); return; }
1001
- if (file.size > 2 * 1024 * 1024) { alert('图片不能超过2MB'); return; }
1027
+ const rawFile = input.files && input.files[0];
1028
+ if (!rawFile || !currentAgentId) return;
1029
+ if (!rawFile.type.startsWith('image/')) { alert('请选择图片文件'); return; }
1002
1030
  try {
1031
+ const file = await resizePluginImage(rawFile, 256, 256, 0.85); // resize for avatar
1003
1032
  const formData = new FormData();
1004
1033
  formData.append('avatar', file);
1005
1034
  formData.append('agent_id', currentAgentId);
1006
1035
  const resp = await fetch(API + '/api/identity/avatar', { method: 'POST', body: formData });
1007
1036
  const data = await resp.json();
1008
1037
  if (data.success || data.avatar) {
1009
- // Update the settings avatar display
1010
1038
  const avatarUrl = data.avatar || (data.account && data.account.avatar);
1011
1039
  if (avatarUrl) {
1012
1040
  document.getElementById('settingsAvatar').innerHTML = `<img src="${avatarUrl}" alt="头像">`;
Binary file