collabdocchat 1.2.13 → 2.0.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.
Files changed (63) hide show
  1. package/README.md +219 -218
  2. package/index.html +2 -0
  3. package/install-and-start.bat +5 -0
  4. package/install-and-start.sh +5 -0
  5. package/package.json +9 -2
  6. package/scripts/generate-docs.js +448 -0
  7. package/scripts/pre-publish-check.js +213 -0
  8. package/scripts/start-app.js +15 -15
  9. package/server/index.js +38 -6
  10. package/server/middleware/cache.js +115 -0
  11. package/server/middleware/errorHandler.js +209 -0
  12. package/server/models/Document.js +66 -59
  13. package/server/models/File.js +49 -43
  14. package/server/models/Group.js +6 -0
  15. package/server/models/KnowledgeBase.js +254 -0
  16. package/server/models/Message.js +43 -0
  17. package/server/models/Task.js +87 -55
  18. package/server/models/User.js +67 -60
  19. package/server/models/Workflow.js +249 -0
  20. package/server/routes/ai.js +327 -0
  21. package/server/routes/audit.js +245 -210
  22. package/server/routes/backup.js +108 -0
  23. package/server/routes/chunked-upload.js +343 -0
  24. package/server/routes/export.js +440 -0
  25. package/server/routes/files.js +294 -218
  26. package/server/routes/groups.js +182 -0
  27. package/server/routes/knowledge.js +509 -0
  28. package/server/routes/tasks.js +257 -110
  29. package/server/routes/workflows.js +380 -0
  30. package/server/utils/backup.js +439 -0
  31. package/server/utils/cache.js +223 -0
  32. package/server/utils/workflow-engine.js +479 -0
  33. package/server/websocket/enhanced.js +509 -0
  34. package/server/websocket/index.js +233 -1
  35. package/src/components/knowledge-modal.js +485 -0
  36. package/src/components/optimized-poll-detail.js +724 -0
  37. package/src/main.js +5 -0
  38. package/src/pages/admin-dashboard.js +2248 -44
  39. package/src/pages/optimized-backup-view.js +616 -0
  40. package/src/pages/optimized-knowledge-view.js +803 -0
  41. package/src/pages/optimized-task-detail.js +843 -0
  42. package/src/pages/optimized-workflow-view.js +806 -0
  43. package/src/pages/simplified-workflows.js +651 -0
  44. package/src/pages/user-dashboard.js +677 -58
  45. package/src/services/api.js +64 -0
  46. package/src/services/auth.js +1 -1
  47. package/src/services/websocket.js +124 -16
  48. package/src/styles/collaboration-modern.js +708 -0
  49. package/src/styles/enhancements.css +392 -0
  50. package/src/styles/main.css +620 -1420
  51. package/src/styles/responsive.css +1000 -0
  52. package/src/styles/sidebar-fix.css +60 -0
  53. package/src/utils/ai-assistant.js +1398 -0
  54. package/src/utils/chat-enhancements.js +509 -0
  55. package/src/utils/collaboration-enhancer.js +1151 -0
  56. package/src/utils/feature-integrator.js +1724 -0
  57. package/src/utils/onboarding-guide.js +734 -0
  58. package/src/utils/performance.js +394 -0
  59. package/src/utils/permission-manager.js +890 -0
  60. package/src/utils/responsive-handler.js +491 -0
  61. package/src/utils/theme-manager.js +811 -0
  62. package/src/utils/ui-enhancements-loader.js +329 -0
  63. package/USAGE.md +0 -298
@@ -0,0 +1,1724 @@
1
+ /**
2
+ * 功能集成器
3
+ * 将所有增强功能集成到仪表板中
4
+ */
5
+
6
+ import { ChatEnhancements, OnlineStatusManager, MessageNotificationManager } from './chat-enhancements.js';
7
+ import { AIAssistant } from './ai-assistant.js';
8
+ import { themeManager } from './theme-manager.js';
9
+ import { permissionManager } from './permission-manager.js';
10
+ import { onboardingGuide } from './onboarding-guide.js';
11
+ import { CollaborationEnhancer } from './collaboration-enhancer.js';
12
+
13
+ export class FeatureIntegrator {
14
+ constructor(apiService, wsService, user) {
15
+ this.apiService = apiService;
16
+ this.wsService = wsService;
17
+ this.user = user;
18
+
19
+ // 初始化各个功能模块
20
+ this.chatEnhancements = new ChatEnhancements(apiService, wsService, user.id || user._id);
21
+ this.onlineStatus = new OnlineStatusManager(wsService);
22
+ this.notifications = new MessageNotificationManager();
23
+ this.aiAssistant = new AIAssistant(apiService);
24
+ this.collaboration = new CollaborationEnhancer(apiService, wsService);
25
+
26
+ // 初始化主题
27
+ themeManager.init();
28
+
29
+ // 设置在线状态监听
30
+ this.onlineStatus.setupListeners();
31
+ }
32
+
33
+ /**
34
+ * 添加设置菜单到侧边栏
35
+ */
36
+ addSettingsMenu(sidebar) {
37
+ const settingsHTML = `
38
+ <div class="sidebar-footer">
39
+ <button class="nav-item" data-view="settings">
40
+ <span class="icon">⚙️</span> 设置
41
+ </button>
42
+ <button class="nav-item" data-view="help">
43
+ <span class="icon">❓</span> 帮助
44
+ </button>
45
+ </div>
46
+ `;
47
+
48
+ sidebar.insertAdjacentHTML('beforeend', settingsHTML);
49
+ }
50
+
51
+ /**
52
+ * 渲染设置页面(优化后的卡片式布局)
53
+ */
54
+ renderSettingsView(container) {
55
+ container.innerHTML = `
56
+ <div class="view-header">
57
+ <h2>⚙️ 设置</h2>
58
+ </div>
59
+
60
+ <div class="settings-cards-grid">
61
+ <div class="setting-card" data-setting="theme">
62
+ <div class="setting-icon">🎨</div>
63
+ <h3>主题设置</h3>
64
+ <p>选择主题风格和颜色方案</p>
65
+ <button class="btn-card-action">进入设置 →</button>
66
+ </div>
67
+
68
+ <div class="setting-card" data-setting="notifications">
69
+ <div class="setting-icon">🔔</div>
70
+ <h3>通知设置</h3>
71
+ <p>管理通知偏好和提醒方式</p>
72
+ <button class="btn-card-action">进入设置 →</button>
73
+ </div>
74
+
75
+ <div class="setting-card" data-setting="ai">
76
+ <div class="setting-icon">🤖</div>
77
+ <h3>AI 助手</h3>
78
+ <p>配置 AI 功能和智能建议</p>
79
+ <button class="btn-card-action">进入设置 →</button>
80
+ </div>
81
+
82
+ ${this.user.role === 'admin' ? `
83
+ <div class="setting-card" data-setting="permissions">
84
+ <div class="setting-icon">🔒</div>
85
+ <h3>权限管理</h3>
86
+ <p>设置用户权限和访问控制</p>
87
+ <button class="btn-card-action">进入设置 →</button>
88
+ </div>
89
+ ` : ''}
90
+
91
+ <div class="setting-card" data-setting="data">
92
+ <div class="setting-icon">📊</div>
93
+ <h3>数据管理</h3>
94
+ <p>导出数据和备份管理</p>
95
+ <button class="btn-card-action">进入设置 →</button>
96
+ </div>
97
+
98
+ <div class="setting-card" data-setting="language">
99
+ <div class="setting-icon">🌐</div>
100
+ <h3>语言设置</h3>
101
+ <p>选择界面显示语言</p>
102
+ <button class="btn-card-action">进入设置 →</button>
103
+ </div>
104
+ </div>
105
+
106
+ <!-- 详细设置面板 -->
107
+ <div class="setting-detail-panel hidden" id="settingDetailPanel">
108
+ <button class="btn-back" id="backToSettings">← 返回</button>
109
+ <div id="settingDetailContent"></div>
110
+ </div>
111
+ `;
112
+
113
+ // 添加样式
114
+ this.addSettingsStyles();
115
+
116
+ // 绑定事件
117
+ container.querySelectorAll('.setting-card').forEach(card => {
118
+ card.addEventListener('click', () => {
119
+ const setting = card.dataset.setting;
120
+ this.showSettingDetail(setting, container);
121
+ });
122
+ });
123
+ }
124
+
125
+ /**
126
+ * 添加设置界面样式
127
+ */
128
+ addSettingsStyles() {
129
+ if (document.getElementById('settings-modern-styles')) return;
130
+
131
+ const style = document.createElement('style');
132
+ style.id = 'settings-modern-styles';
133
+ style.textContent = `
134
+ /* 设置页面容器 - 添加高度限制和滚动 */
135
+ #contentArea {
136
+ max-height: calc(100vh - 40px);
137
+ overflow-y: auto;
138
+ overflow-x: hidden;
139
+ padding-right: 10px;
140
+ }
141
+
142
+ /* 自定义滚动条 */
143
+ #contentArea::-webkit-scrollbar {
144
+ width: 8px;
145
+ }
146
+
147
+ #contentArea::-webkit-scrollbar-track {
148
+ background: var(--bg-dark);
149
+ border-radius: 4px;
150
+ }
151
+
152
+ #contentArea::-webkit-scrollbar-thumb {
153
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
154
+ border-radius: 4px;
155
+ }
156
+
157
+ #contentArea::-webkit-scrollbar-thumb:hover {
158
+ background: linear-gradient(135deg, var(--secondary) 0%, var(--primary) 100%);
159
+ }
160
+
161
+ .settings-cards-grid {
162
+ display: grid;
163
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
164
+ gap: 20px;
165
+ margin-top: 20px;
166
+ }
167
+
168
+ .setting-card {
169
+ background: linear-gradient(135deg, var(--bg-card) 0%, rgba(99,102,241,0.05) 100%);
170
+ border: 2px solid var(--border);
171
+ border-radius: 16px;
172
+ padding: 24px;
173
+ cursor: pointer;
174
+ transition: all 0.3s ease;
175
+ text-align: center;
176
+ animation: fadeInUp 0.5s ease;
177
+ }
178
+
179
+ .setting-card:hover {
180
+ transform: translateY(-8px);
181
+ box-shadow: 0 12px 32px rgba(99,102,241,0.2);
182
+ border-color: var(--primary);
183
+ }
184
+
185
+ .setting-icon {
186
+ font-size: 48px;
187
+ margin-bottom: 16px;
188
+ }
189
+
190
+ .setting-card h3 {
191
+ margin: 0 0 8px;
192
+ font-size: 18px;
193
+ color: var(--text-primary);
194
+ }
195
+
196
+ .setting-card p {
197
+ margin: 0 0 16px;
198
+ font-size: 14px;
199
+ color: var(--text-secondary);
200
+ line-height: 1.5;
201
+ }
202
+
203
+ .btn-card-action {
204
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
205
+ color: white;
206
+ border: none;
207
+ padding: 10px 20px;
208
+ border-radius: 8px;
209
+ font-weight: 600;
210
+ cursor: pointer;
211
+ transition: all 0.3s ease;
212
+ }
213
+
214
+ .btn-card-action:hover {
215
+ transform: scale(1.05);
216
+ box-shadow: 0 4px 12px rgba(99,102,241,0.4);
217
+ }
218
+
219
+ .setting-detail-panel {
220
+ margin-top: 20px;
221
+ animation: fadeIn 0.3s ease;
222
+ }
223
+
224
+ .setting-detail-panel.hidden {
225
+ display: none;
226
+ }
227
+
228
+ .btn-back {
229
+ margin-bottom: 20px;
230
+ padding: 10px 20px;
231
+ background: var(--bg-hover);
232
+ border: none;
233
+ border-radius: 8px;
234
+ color: var(--text-primary);
235
+ font-weight: 600;
236
+ cursor: pointer;
237
+ transition: all 0.3s ease;
238
+ }
239
+
240
+ .btn-back:hover {
241
+ background: var(--border);
242
+ }
243
+
244
+ @media (max-width: 768px) {
245
+ .settings-cards-grid {
246
+ grid-template-columns: 1fr;
247
+ }
248
+ }
249
+ `;
250
+ document.head.appendChild(style);
251
+ }
252
+
253
+ /**
254
+ * 添加详细设置样式
255
+ */
256
+ addDetailSettingsStyles() {
257
+ if (document.getElementById('detail-settings-styles')) return;
258
+
259
+ const style = document.createElement('style');
260
+ style.id = 'detail-settings-styles';
261
+ style.textContent = `
262
+ /* 详细设置容器 */
263
+ .settings-detail-modern {
264
+ animation: fadeInUp 0.5s ease;
265
+ }
266
+
267
+ /* 设置头部 */
268
+ .settings-header-modern {
269
+ text-align: center;
270
+ padding: 40px 20px;
271
+ background: linear-gradient(135deg, var(--bg-card) 0%, rgba(99,102,241,0.05) 100%);
272
+ border-radius: 20px;
273
+ margin-bottom: 30px;
274
+ border: 2px solid var(--border);
275
+ }
276
+
277
+ .settings-icon-large {
278
+ font-size: 64px;
279
+ margin-bottom: 20px;
280
+ animation: bounce 2s infinite;
281
+ }
282
+
283
+ .settings-header-modern h2 {
284
+ margin: 0 0 10px;
285
+ font-size: 32px;
286
+ font-weight: 800;
287
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
288
+ -webkit-background-clip: text;
289
+ -webkit-text-fill-color: transparent;
290
+ background-clip: text;
291
+ }
292
+
293
+ .settings-header-modern p {
294
+ margin: 0;
295
+ font-size: 16px;
296
+ color: var(--text-secondary);
297
+ }
298
+
299
+ /* 设置卡片容器 */
300
+ .settings-cards-container {
301
+ display: flex;
302
+ flex-direction: column;
303
+ gap: 20px;
304
+ margin-bottom: 30px;
305
+ }
306
+
307
+ /* 设置卡片详情 */
308
+ .setting-card-detail {
309
+ background: var(--bg-card);
310
+ border: 2px solid var(--border);
311
+ border-radius: 16px;
312
+ padding: 24px;
313
+ display: flex;
314
+ align-items: flex-start;
315
+ gap: 20px;
316
+ transition: all 0.3s ease;
317
+ }
318
+
319
+ .setting-card-detail:hover {
320
+ border-color: var(--primary);
321
+ box-shadow: 0 8px 24px rgba(99,102,241,0.15);
322
+ transform: translateX(5px);
323
+ }
324
+
325
+ .setting-card-detail.active {
326
+ border-color: var(--success);
327
+ background: linear-gradient(90deg, rgba(16,185,129,0.05) 0%, transparent 100%);
328
+ }
329
+
330
+ .setting-card-icon {
331
+ width: 60px;
332
+ height: 60px;
333
+ border-radius: 12px;
334
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
335
+ display: flex;
336
+ align-items: center;
337
+ justify-content: center;
338
+ font-size: 28px;
339
+ flex-shrink: 0;
340
+ }
341
+
342
+ .setting-card-content {
343
+ flex: 1;
344
+ }
345
+
346
+ .setting-card-header {
347
+ display: flex;
348
+ justify-content: space-between;
349
+ align-items: center;
350
+ margin-bottom: 8px;
351
+ }
352
+
353
+ .setting-card-content h4 {
354
+ margin: 0;
355
+ font-size: 18px;
356
+ font-weight: 700;
357
+ color: var(--text-primary);
358
+ }
359
+
360
+ .setting-card-content p {
361
+ margin: 0;
362
+ font-size: 14px;
363
+ color: var(--text-secondary);
364
+ line-height: 1.6;
365
+ }
366
+
367
+ /* 切换开关 */
368
+ .toggle-switch {
369
+ position: relative;
370
+ display: inline-block;
371
+ width: 60px;
372
+ height: 30px;
373
+ }
374
+
375
+ .toggle-switch input {
376
+ opacity: 0;
377
+ width: 0;
378
+ height: 0;
379
+ }
380
+
381
+ .toggle-slider {
382
+ position: absolute;
383
+ cursor: pointer;
384
+ top: 0;
385
+ left: 0;
386
+ right: 0;
387
+ bottom: 0;
388
+ background: var(--bg-hover);
389
+ border-radius: 30px;
390
+ transition: all 0.3s ease;
391
+ }
392
+
393
+ .toggle-slider:before {
394
+ position: absolute;
395
+ content: "";
396
+ height: 22px;
397
+ width: 22px;
398
+ left: 4px;
399
+ bottom: 4px;
400
+ background: white;
401
+ border-radius: 50%;
402
+ transition: all 0.3s ease;
403
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
404
+ }
405
+
406
+ .toggle-switch input:checked + .toggle-slider {
407
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
408
+ }
409
+
410
+ .toggle-switch input:checked + .toggle-slider:before {
411
+ transform: translateX(30px);
412
+ }
413
+
414
+ /* 操作按钮区域 */
415
+ .settings-actions {
416
+ display: flex;
417
+ gap: 12px;
418
+ flex-wrap: wrap;
419
+ justify-content: center;
420
+ margin-top: 30px;
421
+ }
422
+
423
+ .btn-primary-large,
424
+ .btn-secondary-large {
425
+ padding: 16px 32px;
426
+ border: none;
427
+ border-radius: 12px;
428
+ font-size: 16px;
429
+ font-weight: 700;
430
+ cursor: pointer;
431
+ transition: all 0.3s ease;
432
+ display: flex;
433
+ align-items: center;
434
+ gap: 10px;
435
+ }
436
+
437
+ .btn-primary-large {
438
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
439
+ color: white;
440
+ box-shadow: 0 4px 12px rgba(99,102,241,0.3);
441
+ }
442
+
443
+ .btn-primary-large:hover {
444
+ transform: translateY(-3px);
445
+ box-shadow: 0 8px 24px rgba(99,102,241,0.5);
446
+ }
447
+
448
+ .btn-secondary-large {
449
+ background: var(--bg-card);
450
+ color: var(--text-primary);
451
+ border: 2px solid var(--border);
452
+ }
453
+
454
+ .btn-secondary-large:hover {
455
+ border-color: var(--primary);
456
+ transform: translateY(-3px);
457
+ box-shadow: 0 8px 24px rgba(99,102,241,0.2);
458
+ }
459
+
460
+ .btn-primary-large span,
461
+ .btn-secondary-large span {
462
+ font-size: 20px;
463
+ }
464
+
465
+ /* AI 功能展示 */
466
+ .ai-features-showcase {
467
+ background: linear-gradient(135deg, var(--bg-card) 0%, rgba(99,102,241,0.03) 100%);
468
+ border: 2px solid var(--border);
469
+ border-radius: 16px;
470
+ padding: 30px;
471
+ margin-bottom: 30px;
472
+ }
473
+
474
+ .ai-features-showcase h3 {
475
+ margin: 0 0 24px;
476
+ font-size: 20px;
477
+ font-weight: 700;
478
+ color: var(--text-primary);
479
+ text-align: center;
480
+ }
481
+
482
+ .features-grid {
483
+ display: grid;
484
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
485
+ gap: 20px;
486
+ }
487
+
488
+ .feature-item {
489
+ background: var(--bg-dark);
490
+ border: 1px solid var(--border);
491
+ border-radius: 12px;
492
+ padding: 20px;
493
+ text-align: center;
494
+ transition: all 0.3s ease;
495
+ }
496
+
497
+ .feature-item:hover {
498
+ border-color: var(--primary);
499
+ transform: translateY(-5px);
500
+ box-shadow: 0 8px 24px rgba(99,102,241,0.2);
501
+ }
502
+
503
+ .feature-icon {
504
+ font-size: 36px;
505
+ margin-bottom: 12px;
506
+ }
507
+
508
+ .feature-item h4 {
509
+ margin: 0 0 8px;
510
+ font-size: 16px;
511
+ font-weight: 600;
512
+ color: var(--text-primary);
513
+ }
514
+
515
+ .feature-item p {
516
+ margin: 0;
517
+ font-size: 13px;
518
+ color: var(--text-secondary);
519
+ }
520
+
521
+ /* 数据统计卡片 */
522
+ .data-stats-cards {
523
+ display: grid;
524
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
525
+ gap: 20px;
526
+ margin-bottom: 30px;
527
+ }
528
+
529
+ .data-stat-card {
530
+ background: linear-gradient(135deg, var(--bg-card) 0%, rgba(99,102,241,0.05) 100%);
531
+ border: 2px solid var(--border);
532
+ border-radius: 16px;
533
+ padding: 24px;
534
+ display: flex;
535
+ align-items: center;
536
+ gap: 16px;
537
+ transition: all 0.3s ease;
538
+ }
539
+
540
+ .data-stat-card:hover {
541
+ transform: translateY(-5px);
542
+ box-shadow: 0 8px 24px rgba(99,102,241,0.2);
543
+ border-color: var(--primary);
544
+ }
545
+
546
+ .stat-icon-large {
547
+ font-size: 48px;
548
+ }
549
+
550
+ .stat-info {
551
+ flex: 1;
552
+ }
553
+
554
+ .stat-value {
555
+ font-size: 32px;
556
+ font-weight: 800;
557
+ color: var(--text-primary);
558
+ margin-bottom: 4px;
559
+ }
560
+
561
+ .stat-label {
562
+ font-size: 14px;
563
+ color: var(--text-secondary);
564
+ font-weight: 600;
565
+ }
566
+
567
+ /* 导出选项 */
568
+ .export-options {
569
+ display: flex;
570
+ gap: 10px;
571
+ margin-top: 16px;
572
+ flex-wrap: wrap;
573
+ }
574
+
575
+ .btn-export {
576
+ padding: 10px 20px;
577
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
578
+ color: white;
579
+ border: none;
580
+ border-radius: 8px;
581
+ font-size: 14px;
582
+ font-weight: 600;
583
+ cursor: pointer;
584
+ transition: all 0.3s ease;
585
+ display: flex;
586
+ align-items: center;
587
+ gap: 8px;
588
+ }
589
+
590
+ .btn-export:hover {
591
+ transform: translateY(-2px);
592
+ box-shadow: 0 4px 12px rgba(99,102,241,0.4);
593
+ }
594
+
595
+ .btn-danger-outline {
596
+ padding: 10px 20px;
597
+ background: transparent;
598
+ color: var(--danger);
599
+ border: 2px solid var(--danger);
600
+ border-radius: 8px;
601
+ font-size: 14px;
602
+ font-weight: 600;
603
+ cursor: pointer;
604
+ transition: all 0.3s ease;
605
+ display: flex;
606
+ align-items: center;
607
+ gap: 8px;
608
+ margin-top: 16px;
609
+ }
610
+
611
+ .btn-danger-outline:hover {
612
+ background: var(--danger);
613
+ color: white;
614
+ transform: translateY(-2px);
615
+ box-shadow: 0 4px 12px rgba(239,68,68,0.4);
616
+ }
617
+
618
+ /* 语言选择器 */
619
+ .language-selector-modern {
620
+ display: grid;
621
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
622
+ gap: 16px;
623
+ margin-bottom: 30px;
624
+ }
625
+
626
+ .language-card {
627
+ background: var(--bg-card);
628
+ border: 2px solid var(--border);
629
+ border-radius: 16px;
630
+ padding: 20px;
631
+ display: flex;
632
+ align-items: center;
633
+ gap: 16px;
634
+ cursor: pointer;
635
+ transition: all 0.3s ease;
636
+ }
637
+
638
+ .language-card:hover {
639
+ border-color: var(--primary);
640
+ transform: translateY(-5px);
641
+ box-shadow: 0 8px 24px rgba(99,102,241,0.2);
642
+ }
643
+
644
+ .language-card.selected {
645
+ border-color: var(--success);
646
+ background: linear-gradient(90deg, rgba(16,185,129,0.1) 0%, transparent 100%);
647
+ }
648
+
649
+ .language-flag {
650
+ font-size: 48px;
651
+ }
652
+
653
+ .language-info {
654
+ flex: 1;
655
+ }
656
+
657
+ .language-info h4 {
658
+ margin: 0 0 4px;
659
+ font-size: 18px;
660
+ font-weight: 700;
661
+ color: var(--text-primary);
662
+ }
663
+
664
+ .language-info p {
665
+ margin: 0;
666
+ font-size: 13px;
667
+ color: var(--text-secondary);
668
+ }
669
+
670
+ .language-check {
671
+ width: 30px;
672
+ height: 30px;
673
+ display: flex;
674
+ align-items: center;
675
+ justify-content: center;
676
+ }
677
+
678
+ .check-icon {
679
+ width: 30px;
680
+ height: 30px;
681
+ border-radius: 50%;
682
+ background: linear-gradient(135deg, var(--success) 0%, #059669 100%);
683
+ color: white;
684
+ display: flex;
685
+ align-items: center;
686
+ justify-content: center;
687
+ font-size: 18px;
688
+ font-weight: 700;
689
+ animation: scaleIn 0.3s ease;
690
+ }
691
+
692
+ /* 信息提示框 */
693
+ .language-info-box {
694
+ background: linear-gradient(135deg, rgba(99,102,241,0.1) 0%, rgba(99,102,241,0.05) 100%);
695
+ border: 2px solid rgba(99,102,241,0.3);
696
+ border-radius: 12px;
697
+ padding: 20px;
698
+ display: flex;
699
+ gap: 16px;
700
+ margin-bottom: 30px;
701
+ }
702
+
703
+ .info-icon {
704
+ font-size: 32px;
705
+ flex-shrink: 0;
706
+ }
707
+
708
+ .info-content h4 {
709
+ margin: 0 0 8px;
710
+ font-size: 16px;
711
+ font-weight: 700;
712
+ color: var(--text-primary);
713
+ }
714
+
715
+ .info-content p {
716
+ margin: 0;
717
+ font-size: 14px;
718
+ color: var(--text-secondary);
719
+ line-height: 1.6;
720
+ }
721
+
722
+ /* 动画 */
723
+ @keyframes scaleIn {
724
+ from {
725
+ transform: scale(0);
726
+ opacity: 0;
727
+ }
728
+ to {
729
+ transform: scale(1);
730
+ opacity: 1;
731
+ }
732
+ }
733
+
734
+ @keyframes bounce {
735
+ 0%, 100% {
736
+ transform: translateY(0);
737
+ }
738
+ 50% {
739
+ transform: translateY(-10px);
740
+ }
741
+ }
742
+
743
+ /* 响应式 */
744
+ @media (max-width: 768px) {
745
+ .settings-header-modern {
746
+ padding: 30px 20px;
747
+ }
748
+
749
+ .settings-icon-large {
750
+ font-size: 48px;
751
+ }
752
+
753
+ .settings-header-modern h2 {
754
+ font-size: 24px;
755
+ }
756
+
757
+ .setting-card-detail {
758
+ flex-direction: column;
759
+ text-align: center;
760
+ }
761
+
762
+ .setting-card-header {
763
+ flex-direction: column;
764
+ gap: 12px;
765
+ }
766
+
767
+ .settings-actions {
768
+ flex-direction: column;
769
+ }
770
+
771
+ .btn-primary-large,
772
+ .btn-secondary-large {
773
+ width: 100%;
774
+ justify-content: center;
775
+ }
776
+
777
+ .language-selector-modern {
778
+ grid-template-columns: 1fr;
779
+ }
780
+
781
+ .features-grid {
782
+ grid-template-columns: 1fr;
783
+ }
784
+
785
+ .data-stats-cards {
786
+ grid-template-columns: 1fr;
787
+ }
788
+ }
789
+ `;
790
+ document.head.appendChild(style);
791
+ }
792
+
793
+ /**
794
+ * 显示设置详情
795
+ */
796
+ showSettingDetail(setting, container) {
797
+ const grid = container.querySelector('.settings-cards-grid');
798
+ const panel = container.querySelector('.setting-detail-panel');
799
+ const content = container.querySelector('#settingDetailContent');
800
+
801
+ grid.style.display = 'none';
802
+ panel.classList.remove('hidden');
803
+
804
+ // 加载对应的设置内容
805
+ this.loadSettingsTab(setting, content);
806
+
807
+ // 返回按钮
808
+ container.querySelector('#backToSettings').addEventListener('click', () => {
809
+ panel.classList.add('hidden');
810
+ grid.style.display = 'grid';
811
+ });
812
+ }
813
+
814
+ /**
815
+ * 加载设置标签内容
816
+ */
817
+ loadSettingsTab(tab, container) {
818
+ switch(tab) {
819
+ case 'theme':
820
+ themeManager.renderThemeSelector(container);
821
+ break;
822
+ case 'notifications':
823
+ this.renderNotificationSettings(container);
824
+ break;
825
+ case 'ai':
826
+ this.renderAISettings(container);
827
+ break;
828
+ case 'permissions':
829
+ if (this.user.role === 'admin') {
830
+ permissionManager.renderPermissionManager(container, this.user);
831
+ }
832
+ break;
833
+ case 'data':
834
+ this.renderDataSettings(container);
835
+ break;
836
+ case 'language':
837
+ this.renderLanguageSettings(container);
838
+ break;
839
+ }
840
+ }
841
+
842
+ /**
843
+ * 渲染数据管理设置(优化后)
844
+ */
845
+ renderDataSettings(container) {
846
+ container.innerHTML = `
847
+ <div class="settings-detail-modern">
848
+ <div class="settings-header-modern">
849
+ <div class="settings-icon-large">📊</div>
850
+ <h2>数据管理</h2>
851
+ <p>管理您的数据、导出和备份</p>
852
+ </div>
853
+
854
+ <div class="data-stats-cards">
855
+ <div class="data-stat-card">
856
+ <div class="stat-icon-large">💬</div>
857
+ <div class="stat-info">
858
+ <div class="stat-value">--</div>
859
+ <div class="stat-label">消息数量</div>
860
+ </div>
861
+ </div>
862
+
863
+ <div class="data-stat-card">
864
+ <div class="stat-icon-large">📄</div>
865
+ <div class="stat-info">
866
+ <div class="stat-value">--</div>
867
+ <div class="stat-label">文档数量</div>
868
+ </div>
869
+ </div>
870
+
871
+ <div class="data-stat-card">
872
+ <div class="stat-icon-large">💾</div>
873
+ <div class="stat-info">
874
+ <div class="stat-value">--</div>
875
+ <div class="stat-label">存储空间</div>
876
+ </div>
877
+ </div>
878
+ </div>
879
+
880
+ <div class="settings-cards-container">
881
+ <div class="setting-card-detail">
882
+ <div class="setting-card-icon">📤</div>
883
+ <div class="setting-card-content">
884
+ <h4>导出数据</h4>
885
+ <p>导出您的聊天记录、文档和其他数据为 JSON 或 CSV 格式</p>
886
+ <div class="export-options">
887
+ <button class="btn-export" data-type="messages">
888
+ <span>💬</span> 导出消息
889
+ </button>
890
+ <button class="btn-export" data-type="documents">
891
+ <span>📄</span> 导出文档
892
+ </button>
893
+ <button class="btn-export" data-type="all">
894
+ <span>📦</span> 导出全部
895
+ </button>
896
+ </div>
897
+ </div>
898
+ </div>
899
+
900
+ <div class="setting-card-detail">
901
+ <div class="setting-card-icon">🗑️</div>
902
+ <div class="setting-card-content">
903
+ <h4>清除缓存</h4>
904
+ <p>清除本地缓存数据以释放空间,不会删除服务器数据</p>
905
+ <button class="btn-danger-outline" id="clearCache">
906
+ <span>🗑️</span> 清除缓存
907
+ </button>
908
+ </div>
909
+ </div>
910
+
911
+ <div class="setting-card-detail">
912
+ <div class="setting-card-icon">🔄</div>
913
+ <div class="setting-card-content">
914
+ <h4>自动备份</h4>
915
+ <p>定期自动备份您的重要数据,确保数据安全</p>
916
+ <label class="toggle-switch">
917
+ <input type="checkbox" id="autoBackup" checked>
918
+ <span class="toggle-slider"></span>
919
+ </label>
920
+ </div>
921
+ </div>
922
+ </div>
923
+ </div>
924
+ `;
925
+
926
+ // 添加详细设置样式
927
+ this.addDetailSettingsStyles();
928
+
929
+ // 导出按钮
930
+ container.querySelectorAll('.btn-export').forEach(btn => {
931
+ btn.addEventListener('click', () => {
932
+ const type = btn.dataset.type;
933
+ const originalText = btn.innerHTML;
934
+ btn.innerHTML = '<span>⏳</span> 导出中...';
935
+ btn.disabled = true;
936
+
937
+ setTimeout(() => {
938
+ btn.innerHTML = '<span>✅</span> 导出成功!';
939
+ setTimeout(() => {
940
+ btn.innerHTML = originalText;
941
+ btn.disabled = false;
942
+ }, 2000);
943
+
944
+ alert(`${type === 'all' ? '全部数据' : type === 'messages' ? '消息' : '文档'}导出功能开发中...`);
945
+ }, 1000);
946
+ });
947
+ });
948
+
949
+ // 清除缓存
950
+ container.querySelector('#clearCache')?.addEventListener('click', () => {
951
+ if (confirm('确定要清除缓存吗?这不会删除服务器上的数据。')) {
952
+ const btn = container.querySelector('#clearCache');
953
+ btn.innerHTML = '<span>⏳</span> 清除中...';
954
+ btn.disabled = true;
955
+
956
+ setTimeout(() => {
957
+ localStorage.clear();
958
+ alert('缓存已清除!页面将刷新...');
959
+ window.location.reload();
960
+ }, 1000);
961
+ }
962
+ });
963
+ }
964
+
965
+ /**
966
+ * 渲染语言设置(优化后)
967
+ */
968
+ renderLanguageSettings(container) {
969
+ const currentLang = localStorage.getItem('language') || 'zh-CN';
970
+
971
+ container.innerHTML = `
972
+ <div class="settings-detail-modern">
973
+ <div class="settings-header-modern">
974
+ <div class="settings-icon-large">🌐</div>
975
+ <h2>语言设置</h2>
976
+ <p>选择您偏好的界面显示语言</p>
977
+ </div>
978
+
979
+ <div class="language-selector-modern">
980
+ <div class="language-card ${currentLang === 'zh-CN' ? 'selected' : ''}" data-lang="zh-CN">
981
+ <div class="language-flag">🇨🇳</div>
982
+ <div class="language-info">
983
+ <h4>简体中文</h4>
984
+ <p>Simplified Chinese</p>
985
+ </div>
986
+ <div class="language-check">
987
+ ${currentLang === 'zh-CN' ? '<span class="check-icon">✓</span>' : ''}
988
+ </div>
989
+ </div>
990
+
991
+ <div class="language-card ${currentLang === 'zh-TW' ? 'selected' : ''}" data-lang="zh-TW">
992
+ <div class="language-flag">🇹🇼</div>
993
+ <div class="language-info">
994
+ <h4>繁體中文</h4>
995
+ <p>Traditional Chinese</p>
996
+ </div>
997
+ <div class="language-check">
998
+ ${currentLang === 'zh-TW' ? '<span class="check-icon">✓</span>' : ''}
999
+ </div>
1000
+ </div>
1001
+
1002
+ <div class="language-card ${currentLang === 'en-US' ? 'selected' : ''}" data-lang="en-US">
1003
+ <div class="language-flag">🇺🇸</div>
1004
+ <div class="language-info">
1005
+ <h4>English</h4>
1006
+ <p>United States</p>
1007
+ </div>
1008
+ <div class="language-check">
1009
+ ${currentLang === 'en-US' ? '<span class="check-icon">✓</span>' : ''}
1010
+ </div>
1011
+ </div>
1012
+
1013
+ <div class="language-card ${currentLang === 'ja-JP' ? 'selected' : ''}" data-lang="ja-JP">
1014
+ <div class="language-flag">🇯🇵</div>
1015
+ <div class="language-info">
1016
+ <h4>日本語</h4>
1017
+ <p>Japanese</p>
1018
+ </div>
1019
+ <div class="language-check">
1020
+ ${currentLang === 'ja-JP' ? '<span class="check-icon">✓</span>' : ''}
1021
+ </div>
1022
+ </div>
1023
+
1024
+ <div class="language-card ${currentLang === 'ko-KR' ? 'selected' : ''}" data-lang="ko-KR">
1025
+ <div class="language-flag">🇰🇷</div>
1026
+ <div class="language-info">
1027
+ <h4>한국어</h4>
1028
+ <p>Korean</p>
1029
+ </div>
1030
+ <div class="language-check">
1031
+ ${currentLang === 'ko-KR' ? '<span class="check-icon">✓</span>' : ''}
1032
+ </div>
1033
+ </div>
1034
+
1035
+ <div class="language-card ${currentLang === 'fr-FR' ? 'selected' : ''}" data-lang="fr-FR">
1036
+ <div class="language-flag">🇫🇷</div>
1037
+ <div class="language-info">
1038
+ <h4>Français</h4>
1039
+ <p>French</p>
1040
+ </div>
1041
+ <div class="language-check">
1042
+ ${currentLang === 'fr-FR' ? '<span class="check-icon">✓</span>' : ''}
1043
+ </div>
1044
+ </div>
1045
+ </div>
1046
+
1047
+ <div class="language-info-box">
1048
+ <div class="info-icon">ℹ️</div>
1049
+ <div class="info-content">
1050
+ <h4>语言切换说明</h4>
1051
+ <p>更改语言后,页面将自动刷新以应用新的语言设置。部分内容可能需要重新加载。</p>
1052
+ </div>
1053
+ </div>
1054
+
1055
+ <div class="settings-actions">
1056
+ <button class="btn-primary-large" id="saveLanguage">
1057
+ <span>💾</span> 保存并应用
1058
+ </button>
1059
+ </div>
1060
+ </div>
1061
+ `;
1062
+
1063
+ // 添加详细设置样式
1064
+ this.addDetailSettingsStyles();
1065
+
1066
+ // 语言卡片点击效果
1067
+ container.querySelectorAll('.language-card').forEach(card => {
1068
+ card.addEventListener('click', () => {
1069
+ // 移除所有选中状态
1070
+ container.querySelectorAll('.language-card').forEach(c => {
1071
+ c.classList.remove('selected');
1072
+ c.querySelector('.language-check').innerHTML = '';
1073
+ });
1074
+
1075
+ // 添加选中状态
1076
+ card.classList.add('selected');
1077
+ card.querySelector('.language-check').innerHTML = '<span class="check-icon">✓</span>';
1078
+ });
1079
+ });
1080
+
1081
+ // 保存语言设置
1082
+ container.querySelector('#saveLanguage')?.addEventListener('click', () => {
1083
+ const selectedCard = container.querySelector('.language-card.selected');
1084
+ const selectedLang = selectedCard.dataset.lang;
1085
+
1086
+ const btn = container.querySelector('#saveLanguage');
1087
+ const originalText = btn.innerHTML;
1088
+ btn.innerHTML = '<span>⏳</span> 应用中...';
1089
+ btn.disabled = true;
1090
+
1091
+ setTimeout(() => {
1092
+ localStorage.setItem('language', selectedLang);
1093
+ btn.innerHTML = '<span>✅</span> 应用成功!';
1094
+
1095
+ setTimeout(() => {
1096
+ window.location.reload();
1097
+ }, 1000);
1098
+ }, 500);
1099
+ });
1100
+ }
1101
+
1102
+ /**
1103
+ * 渲染通知设置(优化后)
1104
+ */
1105
+ renderNotificationSettings(container) {
1106
+ const settings = {
1107
+ desktop: localStorage.getItem('notif_desktop') !== 'false',
1108
+ sound: localStorage.getItem('notif_sound') !== 'false',
1109
+ mentions: localStorage.getItem('notif_mentions') !== 'false',
1110
+ messages: localStorage.getItem('notif_messages') !== 'false'
1111
+ };
1112
+
1113
+ container.innerHTML = `
1114
+ <div class="settings-detail-modern">
1115
+ <div class="settings-header-modern">
1116
+ <div class="settings-icon-large">🔔</div>
1117
+ <h2>通知设置</h2>
1118
+ <p>管理您的通知偏好和提醒方式</p>
1119
+ </div>
1120
+
1121
+ <div class="settings-cards-container">
1122
+ <div class="setting-card-detail ${settings.desktop ? 'active' : ''}">
1123
+ <div class="setting-card-icon">🖥️</div>
1124
+ <div class="setting-card-content">
1125
+ <div class="setting-card-header">
1126
+ <h4>桌面通知</h4>
1127
+ <label class="toggle-switch">
1128
+ <input type="checkbox" id="desktopNotif" ${settings.desktop ? 'checked' : ''}>
1129
+ <span class="toggle-slider"></span>
1130
+ </label>
1131
+ </div>
1132
+ <p>在桌面显示新消息通知,即使浏览器在后台运行</p>
1133
+ </div>
1134
+ </div>
1135
+
1136
+ <div class="setting-card-detail ${settings.sound ? 'active' : ''}">
1137
+ <div class="setting-card-icon">🔊</div>
1138
+ <div class="setting-card-content">
1139
+ <div class="setting-card-header">
1140
+ <h4>声音提示</h4>
1141
+ <label class="toggle-switch">
1142
+ <input type="checkbox" id="soundNotif" ${settings.sound ? 'checked' : ''}>
1143
+ <span class="toggle-slider"></span>
1144
+ </label>
1145
+ </div>
1146
+ <p>收到新消息时播放提示音,让您不会错过重要信息</p>
1147
+ </div>
1148
+ </div>
1149
+
1150
+ <div class="setting-card-detail ${settings.mentions ? 'active' : ''}">
1151
+ <div class="setting-card-icon">@</div>
1152
+ <div class="setting-card-content">
1153
+ <div class="setting-card-header">
1154
+ <h4>@提及通知</h4>
1155
+ <label class="toggle-switch">
1156
+ <input type="checkbox" id="mentionNotif" ${settings.mentions ? 'checked' : ''}>
1157
+ <span class="toggle-slider"></span>
1158
+ </label>
1159
+ </div>
1160
+ <p>有人@提及您时发送特别通知,确保及时回复</p>
1161
+ </div>
1162
+ </div>
1163
+
1164
+ <div class="setting-card-detail ${settings.messages ? 'active' : ''}">
1165
+ <div class="setting-card-icon">💬</div>
1166
+ <div class="setting-card-content">
1167
+ <div class="setting-card-header">
1168
+ <h4>新消息通知</h4>
1169
+ <label class="toggle-switch">
1170
+ <input type="checkbox" id="messageNotif" ${settings.messages ? 'checked' : ''}>
1171
+ <span class="toggle-slider"></span>
1172
+ </label>
1173
+ </div>
1174
+ <p>收到新消息时发送通知,保持与团队的实时沟通</p>
1175
+ </div>
1176
+ </div>
1177
+ </div>
1178
+
1179
+ <div class="settings-actions">
1180
+ <button class="btn-primary-large" id="saveNotifSettings">
1181
+ <span>💾</span> 保存设置
1182
+ </button>
1183
+ <button class="btn-secondary-large" id="testNotif">
1184
+ <span>🔔</span> 测试通知
1185
+ </button>
1186
+ </div>
1187
+ </div>
1188
+ `;
1189
+
1190
+ // 添加详细设置样式
1191
+ this.addDetailSettingsStyles();
1192
+
1193
+ // 切换开关效果
1194
+ container.querySelectorAll('.toggle-switch input').forEach(input => {
1195
+ input.addEventListener('change', (e) => {
1196
+ const card = e.target.closest('.setting-card-detail');
1197
+ if (e.target.checked) {
1198
+ card.classList.add('active');
1199
+ } else {
1200
+ card.classList.remove('active');
1201
+ }
1202
+ });
1203
+ });
1204
+
1205
+ // 保存设置
1206
+ container.querySelector('#saveNotifSettings').addEventListener('click', () => {
1207
+ localStorage.setItem('notif_desktop', container.querySelector('#desktopNotif').checked);
1208
+ localStorage.setItem('notif_sound', container.querySelector('#soundNotif').checked);
1209
+ localStorage.setItem('notif_mentions', container.querySelector('#mentionNotif').checked);
1210
+ localStorage.setItem('notif_messages', container.querySelector('#messageNotif').checked);
1211
+
1212
+ // 显示成功提示
1213
+ const btn = container.querySelector('#saveNotifSettings');
1214
+ const originalText = btn.innerHTML;
1215
+ btn.innerHTML = '<span>✅</span> 保存成功!';
1216
+ btn.style.background = 'linear-gradient(135deg, #10b981 0%, #059669 100%)';
1217
+
1218
+ setTimeout(() => {
1219
+ btn.innerHTML = originalText;
1220
+ btn.style.background = '';
1221
+ }, 2000);
1222
+ });
1223
+
1224
+ // 测试通知
1225
+ container.querySelector('#testNotif')?.addEventListener('click', () => {
1226
+ if ('Notification' in window) {
1227
+ Notification.requestPermission().then(permission => {
1228
+ if (permission === 'granted') {
1229
+ new Notification('CollabDocChat', {
1230
+ body: '这是一条测试通知!',
1231
+ icon: '/favicon.ico'
1232
+ });
1233
+ } else {
1234
+ alert('请允许浏览器通知权限');
1235
+ }
1236
+ });
1237
+ } else {
1238
+ alert('您的浏览器不支持桌面通知');
1239
+ }
1240
+ });
1241
+ }
1242
+
1243
+ /**
1244
+ * 渲染AI设置(优化后)
1245
+ */
1246
+ renderAISettings(container) {
1247
+ const aiEnabled = localStorage.getItem('ai_enabled') !== 'false';
1248
+ const smartReplies = localStorage.getItem('ai_smart_replies') !== 'false';
1249
+ const autoComplete = localStorage.getItem('ai_auto_complete') !== 'false';
1250
+
1251
+ container.innerHTML = `
1252
+ <div class="settings-detail-modern">
1253
+ <div class="settings-header-modern">
1254
+ <div class="settings-icon-large">🤖</div>
1255
+ <h2>AI 助手设置</h2>
1256
+ <p>配置 AI 功能,提升您的工作效率</p>
1257
+ </div>
1258
+
1259
+ <div class="settings-cards-container">
1260
+ <div class="setting-card-detail ${aiEnabled ? 'active' : ''}">
1261
+ <div class="setting-card-icon">⚡</div>
1262
+ <div class="setting-card-content">
1263
+ <div class="setting-card-header">
1264
+ <h4>启用 AI 助手</h4>
1265
+ <label class="toggle-switch">
1266
+ <input type="checkbox" id="aiEnabled" ${aiEnabled ? 'checked' : ''}>
1267
+ <span class="toggle-slider"></span>
1268
+ </label>
1269
+ </div>
1270
+ <p>使用 AI 提供智能回复建议和内容分析,让沟通更高效</p>
1271
+ </div>
1272
+ </div>
1273
+
1274
+ <div class="setting-card-detail ${smartReplies ? 'active' : ''}">
1275
+ <div class="setting-card-icon">💡</div>
1276
+ <div class="setting-card-content">
1277
+ <div class="setting-card-header">
1278
+ <h4>智能回复建议</h4>
1279
+ <label class="toggle-switch">
1280
+ <input type="checkbox" id="smartReplies" ${smartReplies ? 'checked' : ''}>
1281
+ <span class="toggle-slider"></span>
1282
+ </label>
1283
+ </div>
1284
+ <p>根据消息内容自动生成回复建议,快速响应对话</p>
1285
+ </div>
1286
+ </div>
1287
+
1288
+ <div class="setting-card-detail ${autoComplete ? 'active' : ''}">
1289
+ <div class="setting-card-icon">✨</div>
1290
+ <div class="setting-card-content">
1291
+ <div class="setting-card-header">
1292
+ <h4>自动完成</h4>
1293
+ <label class="toggle-switch">
1294
+ <input type="checkbox" id="autoComplete" ${autoComplete ? 'checked' : ''}>
1295
+ <span class="toggle-slider"></span>
1296
+ </label>
1297
+ </div>
1298
+ <p>输入时提供智能自动完成建议,提高输入效率</p>
1299
+ </div>
1300
+ </div>
1301
+ </div>
1302
+
1303
+ <div class="ai-features-showcase">
1304
+ <h3>✨ AI 功能展示</h3>
1305
+ <div class="features-grid">
1306
+ <div class="feature-item">
1307
+ <div class="feature-icon">📝</div>
1308
+ <h4>智能摘要</h4>
1309
+ <p>自动生成会议和文档摘要</p>
1310
+ </div>
1311
+ <div class="feature-item">
1312
+ <div class="feature-icon">🔍</div>
1313
+ <h4>智能搜索</h4>
1314
+ <p>理解语义的智能搜索</p>
1315
+ </div>
1316
+ <div class="feature-item">
1317
+ <div class="feature-icon">🎯</div>
1318
+ <h4>任务建议</h4>
1319
+ <p>智能推荐任务优先级</p>
1320
+ </div>
1321
+ <div class="feature-item">
1322
+ <div class="feature-icon">📊</div>
1323
+ <h4>数据分析</h4>
1324
+ <p>自动分析团队协作数据</p>
1325
+ </div>
1326
+ </div>
1327
+ </div>
1328
+
1329
+ <div class="settings-actions">
1330
+ <button class="btn-primary-large" id="saveAISettings">
1331
+ <span>💾</span> 保存设置
1332
+ </button>
1333
+ <button class="btn-secondary-large" id="testAI">
1334
+ <span>🧪</span> 测试 AI
1335
+ </button>
1336
+ <button class="btn-secondary-large" id="openAIPanel">
1337
+ <span>🤖</span> AI 面板
1338
+ </button>
1339
+ </div>
1340
+ </div>
1341
+ `;
1342
+
1343
+ // 添加详细设置样式
1344
+ this.addDetailSettingsStyles();
1345
+
1346
+ // 切换开关效果
1347
+ container.querySelectorAll('.toggle-switch input').forEach(input => {
1348
+ input.addEventListener('change', (e) => {
1349
+ const card = e.target.closest('.setting-card-detail');
1350
+ if (e.target.checked) {
1351
+ card.classList.add('active');
1352
+ } else {
1353
+ card.classList.remove('active');
1354
+ }
1355
+ });
1356
+ });
1357
+
1358
+ // 保存设置
1359
+ container.querySelector('#saveAISettings').addEventListener('click', () => {
1360
+ localStorage.setItem('ai_enabled', container.querySelector('#aiEnabled').checked);
1361
+ localStorage.setItem('ai_smart_replies', container.querySelector('#smartReplies').checked);
1362
+ localStorage.setItem('ai_auto_complete', container.querySelector('#autoComplete').checked);
1363
+
1364
+ const btn = container.querySelector('#saveAISettings');
1365
+ const originalText = btn.innerHTML;
1366
+ btn.innerHTML = '<span>✅</span> 保存成功!';
1367
+ btn.style.background = 'linear-gradient(135deg, #10b981 0%, #059669 100%)';
1368
+
1369
+ setTimeout(() => {
1370
+ btn.innerHTML = originalText;
1371
+ btn.style.background = '';
1372
+ }, 2000);
1373
+ });
1374
+
1375
+ // 测试 AI
1376
+ container.querySelector('#testAI').addEventListener('click', () => {
1377
+ const btn = container.querySelector('#testAI');
1378
+ const originalText = btn.innerHTML;
1379
+ btn.innerHTML = '<span>⏳</span> 测试中...';
1380
+ btn.disabled = true;
1381
+
1382
+ setTimeout(() => {
1383
+ btn.innerHTML = '<span>✅</span> AI 正常运行!';
1384
+ setTimeout(() => {
1385
+ btn.innerHTML = originalText;
1386
+ btn.disabled = false;
1387
+ }, 2000);
1388
+ }, 1000);
1389
+ });
1390
+
1391
+ // 打开 AI 面板
1392
+ container.querySelector('#openAIPanel').addEventListener('click', () => {
1393
+ const panel = document.createElement('div');
1394
+ panel.className = 'modal';
1395
+ panel.innerHTML = '<div class="modal-content" style="max-width: 800px;"></div>';
1396
+ document.body.appendChild(panel);
1397
+
1398
+ this.aiAssistant.renderAssistantPanel(panel.querySelector('.modal-content'));
1399
+
1400
+ panel.addEventListener('click', (e) => {
1401
+ if (e.target === panel) {
1402
+ panel.remove();
1403
+ }
1404
+ });
1405
+ });
1406
+ }
1407
+
1408
+ /**
1409
+ * 渲染帮助页面
1410
+ */
1411
+ renderHelpView(container) {
1412
+ onboardingGuide.showHelpCenter(container);
1413
+ }
1414
+
1415
+ /**
1416
+ * 增强聊天视图
1417
+ */
1418
+ enhanceChatView(container, currentGroup, groupMembers) {
1419
+ // 添加增强功能按钮
1420
+ const header = container.querySelector('.view-header');
1421
+ if (header) {
1422
+ const enhancementsHTML = `
1423
+ <div class="chat-enhancements">
1424
+ <button class="btn-secondary" id="showAIAssistant" title="AI 助手">
1425
+ 🤖 AI
1426
+ </button>
1427
+ <button class="btn-secondary" id="showCollabTools" title="协作工具">
1428
+ 🛠️ 工具
1429
+ </button>
1430
+ <button class="btn-secondary" id="markAllRead" title="全部标记为已读">
1431
+ ✓ 已读
1432
+ </button>
1433
+ </div>
1434
+ `;
1435
+ header.insertAdjacentHTML('beforeend', enhancementsHTML);
1436
+
1437
+ // AI 助手按钮
1438
+ container.querySelector('#showAIAssistant').addEventListener('click', () => {
1439
+ const panel = document.createElement('div');
1440
+ panel.className = 'modal';
1441
+ panel.innerHTML = '<div class="modal-content" style="max-width: 800px;"></div>';
1442
+ document.body.appendChild(panel);
1443
+
1444
+ this.aiAssistant.renderAssistantPanel(panel.querySelector('.modal-content'));
1445
+
1446
+ panel.addEventListener('click', (e) => {
1447
+ if (e.target === panel) panel.remove();
1448
+ });
1449
+ });
1450
+
1451
+ // 协作工具按钮
1452
+ container.querySelector('#showCollabTools').addEventListener('click', () => {
1453
+ this.showCollaborationTools(currentGroup._id);
1454
+ });
1455
+
1456
+ // 标记全部已读
1457
+ container.querySelector('#markAllRead').addEventListener('click', async () => {
1458
+ const messages = Array.from(container.querySelectorAll('.message[data-message-id]'))
1459
+ .map(el => el.dataset.messageId);
1460
+
1461
+ if (messages.length > 0) {
1462
+ await this.chatEnhancements.markAllAsRead(messages);
1463
+ alert('已标记所有消息为已读');
1464
+ }
1465
+ });
1466
+ }
1467
+
1468
+ // 设置@提及功能
1469
+ const messageInput = container.querySelector('#messageInput');
1470
+ if (messageInput && groupMembers) {
1471
+ this.chatEnhancements.setupMentionInput(messageInput, groupMembers);
1472
+ }
1473
+
1474
+ // 监听智能回复选择
1475
+ window.addEventListener('smartReplySelected', (e) => {
1476
+ if (messageInput) {
1477
+ messageInput.value = e.detail.reply;
1478
+ messageInput.focus();
1479
+ }
1480
+ });
1481
+ }
1482
+
1483
+ /**
1484
+ * 显示协作工具
1485
+ */
1486
+ showCollaborationTools(groupId) {
1487
+ const modal = document.createElement('div');
1488
+ modal.className = 'modal';
1489
+
1490
+ // 根据用户角色决定是否显示投票功能
1491
+ const pollTab = this.user.role === 'admin' ? '<button class="collab-tab-btn" data-tool="poll"><span class="tab-icon">📊</span><span class="tab-text">投票</span></button>' : '';
1492
+
1493
+ modal.innerHTML = `
1494
+ <div class="modal-content" style="max-width: 1000px;">
1495
+ <div class="modal-header">
1496
+ <h3>🛠️ 协作工具</h3>
1497
+ <button class="modal-close" id="closeCollabTools">×</button>
1498
+ </div>
1499
+ <div class="collab-tools-tabs-modern">
1500
+ <button class="collab-tab-btn active" data-tool="whiteboard">
1501
+ <span class="tab-icon">🎨</span>
1502
+ <span class="tab-text">白板</span>
1503
+ </button>
1504
+ ${pollTab}
1505
+ <button class="collab-tab-btn" data-tool="code">
1506
+ <span class="tab-icon">💻</span>
1507
+ <span class="tab-text">代码编辑</span>
1508
+ </button>
1509
+ <button class="collab-tab-btn" data-tool="mindmap">
1510
+ <span class="tab-icon">🧠</span>
1511
+ <span class="tab-text">思维导图</span>
1512
+ </button>
1513
+ </div>
1514
+ <div class="collab-tools-content" id="collabToolsContent"></div>
1515
+ </div>
1516
+ `;
1517
+
1518
+ document.body.appendChild(modal);
1519
+
1520
+ // 添加标签按钮样式
1521
+ this.addCollabTabStyles();
1522
+
1523
+ // 关闭按钮
1524
+ modal.querySelector('#closeCollabTools').addEventListener('click', () => {
1525
+ modal.remove();
1526
+ });
1527
+
1528
+ // 标签切换
1529
+ modal.querySelectorAll('.collab-tab-btn').forEach(btn => {
1530
+ btn.addEventListener('click', () => {
1531
+ const tool = btn.dataset.tool;
1532
+
1533
+ modal.querySelectorAll('.collab-tab-btn').forEach(b => b.classList.remove('active'));
1534
+ btn.classList.add('active');
1535
+
1536
+ const content = modal.querySelector('#collabToolsContent');
1537
+ this.loadCollaborationTool(tool, content, groupId);
1538
+ });
1539
+ });
1540
+
1541
+ // 默认加载白板
1542
+ this.loadCollaborationTool('whiteboard', modal.querySelector('#collabToolsContent'), groupId);
1543
+ }
1544
+
1545
+ /**
1546
+ * 添加协作标签按钮样式
1547
+ */
1548
+ addCollabTabStyles() {
1549
+ if (document.getElementById('collab-tab-modern-styles')) return;
1550
+
1551
+ const style = document.createElement('style');
1552
+ style.id = 'collab-tab-modern-styles';
1553
+ style.textContent = `
1554
+ .collab-tools-tabs-modern {
1555
+ display: flex;
1556
+ gap: 12px;
1557
+ padding: 20px;
1558
+ background: var(--bg-dark);
1559
+ border-radius: 12px;
1560
+ margin-bottom: 20px;
1561
+ flex-wrap: wrap;
1562
+ }
1563
+
1564
+ .collab-tab-btn {
1565
+ flex: 1;
1566
+ min-width: 120px;
1567
+ padding: 14px 20px;
1568
+ background: var(--bg-card);
1569
+ border: 2px solid var(--border);
1570
+ border-radius: 12px;
1571
+ color: var(--text-primary);
1572
+ font-size: 15px;
1573
+ font-weight: 600;
1574
+ cursor: pointer;
1575
+ transition: all 0.3s ease;
1576
+ display: flex;
1577
+ flex-direction: column;
1578
+ align-items: center;
1579
+ gap: 8px;
1580
+ position: relative;
1581
+ overflow: hidden;
1582
+ }
1583
+
1584
+ .collab-tab-btn::before {
1585
+ content: '';
1586
+ position: absolute;
1587
+ top: 0;
1588
+ left: -100%;
1589
+ width: 100%;
1590
+ height: 100%;
1591
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
1592
+ transition: left 0.5s ease;
1593
+ }
1594
+
1595
+ .collab-tab-btn:hover::before {
1596
+ left: 100%;
1597
+ }
1598
+
1599
+ .collab-tab-btn:hover {
1600
+ border-color: var(--primary);
1601
+ transform: translateY(-3px);
1602
+ box-shadow: 0 8px 24px rgba(99,102,241,0.3);
1603
+ }
1604
+
1605
+ .collab-tab-btn.active {
1606
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
1607
+ border-color: var(--primary);
1608
+ color: white;
1609
+ box-shadow: 0 4px 12px rgba(99,102,241,0.4);
1610
+ }
1611
+
1612
+ .collab-tab-btn.active::after {
1613
+ content: '';
1614
+ position: absolute;
1615
+ bottom: 0;
1616
+ left: 0;
1617
+ right: 0;
1618
+ height: 3px;
1619
+ background: white;
1620
+ box-shadow: 0 0 10px rgba(255,255,255,0.5);
1621
+ }
1622
+
1623
+ .tab-icon {
1624
+ font-size: 24px;
1625
+ transition: all 0.3s ease;
1626
+ }
1627
+
1628
+ .collab-tab-btn:hover .tab-icon {
1629
+ transform: scale(1.2);
1630
+ }
1631
+
1632
+ .collab-tab-btn.active .tab-icon {
1633
+ animation: bounce 0.6s ease;
1634
+ }
1635
+
1636
+ .tab-text {
1637
+ font-size: 14px;
1638
+ font-weight: 600;
1639
+ letter-spacing: 0.5px;
1640
+ }
1641
+
1642
+ @keyframes bounce {
1643
+ 0%, 100% {
1644
+ transform: translateY(0);
1645
+ }
1646
+ 50% {
1647
+ transform: translateY(-5px);
1648
+ }
1649
+ }
1650
+
1651
+ @media (max-width: 768px) {
1652
+ .collab-tools-tabs-modern {
1653
+ flex-direction: column;
1654
+ }
1655
+
1656
+ .collab-tab-btn {
1657
+ width: 100%;
1658
+ flex-direction: row;
1659
+ justify-content: center;
1660
+ }
1661
+ }
1662
+ `;
1663
+ document.head.appendChild(style);
1664
+ }
1665
+
1666
+ /**
1667
+ * 加载协作工具
1668
+ */
1669
+ loadCollaborationTool(tool, container, groupId) {
1670
+ const isAdmin = this.user.role === 'admin';
1671
+
1672
+ switch(tool) {
1673
+ case 'whiteboard':
1674
+ this.collaboration.createWhiteboard(container, groupId, this.user.username, isAdmin);
1675
+ break;
1676
+ case 'poll':
1677
+ this.collaboration.createPoll(container, groupId);
1678
+ break;
1679
+ case 'code':
1680
+ this.collaboration.createCodeEditor(container);
1681
+ break;
1682
+ case 'mindmap':
1683
+ this.collaboration.createMindMap(container);
1684
+ break;
1685
+ }
1686
+ }
1687
+
1688
+ /**
1689
+ * 显示新手引导
1690
+ */
1691
+ showOnboarding() {
1692
+ if (!onboardingGuide.hasCompleted) {
1693
+ setTimeout(() => {
1694
+ const showGuide = confirm('欢迎使用 CollabDocChat!是否需要新手引导?');
1695
+ if (showGuide) {
1696
+ onboardingGuide.start();
1697
+ } else {
1698
+ onboardingGuide.markCompleted();
1699
+ }
1700
+ }, 1000);
1701
+ }
1702
+ }
1703
+
1704
+ /**
1705
+ * 添加在线状态指示器
1706
+ */
1707
+ addOnlineStatusIndicators(container, members) {
1708
+ members.forEach(member => {
1709
+ const memberEl = container.querySelector(`[data-user-id="${member._id}"]`);
1710
+ if (memberEl) {
1711
+ const indicator = this.onlineStatus.renderStatusIndicator(member._id);
1712
+ memberEl.insertAdjacentHTML('beforeend', indicator);
1713
+ }
1714
+ });
1715
+ }
1716
+
1717
+ /**
1718
+ * 清理资源
1719
+ */
1720
+ cleanup() {
1721
+ this.chatEnhancements.cleanup();
1722
+ }
1723
+ }
1724
+