collabdocchat 2.0.0 → 2.0.2

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,485 +1,485 @@
1
- /**
2
- * 知识库创建和编辑功能
3
- */
4
-
5
- // 显示创建知识库模态框
6
- export function showCreateKnowledgeModal(currentGroup, apiService, container, currentUserId) {
7
- const modal = document.createElement('div');
8
- modal.className = 'modal';
9
- modal.id = 'createKnowledgeModal';
10
-
11
- modal.innerHTML = `
12
- <div class="modal-content knowledge-modal-content">
13
- <div class="modal-header">
14
- <h3>✨ 创建知识库文档</h3>
15
- <button class="modal-close" id="closeKnowledgeModal">×</button>
16
- </div>
17
-
18
- <form id="createKnowledgeForm">
19
- <div class="form-group">
20
- <label>标题 *</label>
21
- <input type="text" id="kbTitle" placeholder="请输入文档标题" required>
22
- </div>
23
-
24
- <div class="form-group">
25
- <label>分类</label>
26
- <input type="text" id="kbCategory" placeholder="例如:技术文档、使用指南">
27
- </div>
28
-
29
- <div class="form-group">
30
- <label>标签(用逗号分隔)</label>
31
- <input type="text" id="kbTags" placeholder="例如:API, 教程, 入门">
32
- </div>
33
-
34
- <div class="form-group">
35
- <label>内容 *</label>
36
- <div id="kbContentEditor" style="height: 300px;"></div>
37
- </div>
38
-
39
- <div class="form-group">
40
- <label>权限设置</label>
41
- <div class="permission-options">
42
- <label class="permission-option">
43
- <input type="radio" name="permission" value="private" checked>
44
- <div class="option-content">
45
- <span class="option-icon">🔒</span>
46
- <div>
47
- <strong>私有</strong>
48
- <p>仅自己可见</p>
49
- </div>
50
- </div>
51
- </label>
52
- <label class="permission-option">
53
- <input type="radio" name="permission" value="group">
54
- <div class="option-content">
55
- <span class="option-icon">👥</span>
56
- <div>
57
- <strong>群组可见</strong>
58
- <p>群组成员可见</p>
59
- </div>
60
- </div>
61
- </label>
62
- <label class="permission-option">
63
- <input type="radio" name="permission" value="public">
64
- <div class="option-content">
65
- <span class="option-icon">🌐</span>
66
- <div>
67
- <strong>公开</strong>
68
- <p>所有人可见</p>
69
- </div>
70
- </div>
71
- </label>
72
- </div>
73
- </div>
74
-
75
- <div class="form-actions">
76
- <button type="button" class="btn-secondary" id="saveDraft">保存草稿</button>
77
- <button type="submit" class="btn-primary">发布</button>
78
- </div>
79
- </form>
80
- </div>
81
- `;
82
-
83
- document.body.appendChild(modal);
84
- addKnowledgeModalStyles();
85
-
86
- // 初始化 Quill 编辑器
87
- const Quill = window.Quill;
88
- const quill = new Quill('#kbContentEditor', {
89
- theme: 'snow',
90
- modules: {
91
- toolbar: [
92
- [{ 'header': [1, 2, 3, false] }],
93
- ['bold', 'italic', 'underline', 'strike'],
94
- [{ 'list': 'ordered'}, { 'list': 'bullet' }],
95
- [{ 'color': [] }, { 'background': [] }],
96
- ['link', 'code-block'],
97
- ['clean']
98
- ]
99
- }
100
- });
101
-
102
- // 关闭模态框
103
- const closeModal = () => {
104
- modal.remove();
105
- };
106
-
107
- document.getElementById('closeKnowledgeModal').addEventListener('click', closeModal);
108
- modal.addEventListener('click', (e) => {
109
- if (e.target === modal) closeModal();
110
- });
111
-
112
- // 保存草稿
113
- document.getElementById('saveDraft').addEventListener('click', async () => {
114
- await saveKnowledge(false);
115
- });
116
-
117
- // 发布
118
- document.getElementById('createKnowledgeForm').addEventListener('submit', async (e) => {
119
- e.preventDefault();
120
- await saveKnowledge(true);
121
- });
122
-
123
- async function saveKnowledge(publish) {
124
- const title = document.getElementById('kbTitle').value.trim();
125
- const category = document.getElementById('kbCategory').value.trim();
126
- const tags = document.getElementById('kbTags').value.split(',').map(t => t.trim()).filter(t => t);
127
- const content = quill.root.innerHTML;
128
- const permission = document.querySelector('input[name="permission"]:checked').value;
129
-
130
- if (!title || !content) {
131
- alert('请填写标题和内容');
132
- return;
133
- }
134
-
135
- try {
136
- const token = localStorage.getItem('token');
137
- const response = await fetch('http://localhost:8765/api/knowledge', {
138
- method: 'POST',
139
- headers: {
140
- 'Content-Type': 'application/json',
141
- 'Authorization': `Bearer ${token}`
142
- },
143
- body: JSON.stringify({
144
- title,
145
- content,
146
- category,
147
- tags,
148
- groupId: currentGroup._id,
149
- status: publish ? 'published' : 'draft',
150
- permission: permission,
151
- author: currentUserId
152
- })
153
- });
154
-
155
- const result = await response.json();
156
- if (result.success) {
157
- alert(publish ? '发布成功!' : '保存成功!');
158
- closeModal();
159
- // 触发自定义事件通知刷新
160
- window.dispatchEvent(new CustomEvent('knowledgeUpdated', {
161
- detail: { groupId: currentGroup._id }
162
- }));
163
- } else {
164
- alert('保存失败: ' + (result.error?.message || '未知错误'));
165
- }
166
- } catch (error) {
167
- alert('保存失败: ' + error.message);
168
- }
169
- }
170
- }
171
-
172
- // 显示编辑知识库模态框
173
- export async function showEditKnowledgeModal(kbId, currentGroup, apiService, container, currentUserId) {
174
- try {
175
- const token = localStorage.getItem('token');
176
- const response = await fetch(`http://localhost:8765/api/knowledge/${kbId}`, {
177
- headers: { 'Authorization': `Bearer ${token}` }
178
- });
179
- const result = await response.json();
180
- const kb = result.data.knowledge;
181
-
182
- const modal = document.createElement('div');
183
- modal.className = 'modal';
184
- modal.id = 'editKnowledgeModal';
185
-
186
- modal.innerHTML = `
187
- <div class="modal-content knowledge-modal-content">
188
- <div class="modal-header">
189
- <h3>✏️ 编辑知识库文档</h3>
190
- <button class="modal-close" id="closeKnowledgeModal">×</button>
191
- </div>
192
-
193
- <form id="editKnowledgeForm">
194
- <div class="form-group">
195
- <label>标题 *</label>
196
- <input type="text" id="kbTitle" value="${kb.title}" required>
197
- </div>
198
-
199
- <div class="form-group">
200
- <label>分类</label>
201
- <input type="text" id="kbCategory" value="${kb.category || ''}">
202
- </div>
203
-
204
- <div class="form-group">
205
- <label>标签(用逗号分隔)</label>
206
- <input type="text" id="kbTags" value="${kb.tags ? kb.tags.join(', ') : ''}">
207
- </div>
208
-
209
- <div class="form-group">
210
- <label>内容 *</label>
211
- <div id="kbContentEditor" style="height: 300px;"></div>
212
- </div>
213
-
214
- <div class="form-group">
215
- <label>权限设置</label>
216
- <div class="permission-options">
217
- <label class="permission-option">
218
- <input type="radio" name="permission" value="private" ${kb.permission === 'private' ? 'checked' : ''}>
219
- <div class="option-content">
220
- <span class="option-icon">🔒</span>
221
- <div>
222
- <strong>私有</strong>
223
- <p>仅自己可见</p>
224
- </div>
225
- </div>
226
- </label>
227
- <label class="permission-option">
228
- <input type="radio" name="permission" value="group" ${kb.permission === 'group' ? 'checked' : ''}>
229
- <div class="option-content">
230
- <span class="option-icon">👥</span>
231
- <div>
232
- <strong>群组可见</strong>
233
- <p>群组成员可见</p>
234
- </div>
235
- </div>
236
- </label>
237
- <label class="permission-option">
238
- <input type="radio" name="permission" value="public" ${kb.permission === 'public' ? 'checked' : ''}>
239
- <div class="option-content">
240
- <span class="option-icon">🌐</span>
241
- <div>
242
- <strong>公开</strong>
243
- <p>所有人可见</p>
244
- </div>
245
- </div>
246
- </label>
247
- </div>
248
- </div>
249
-
250
- <div class="form-actions">
251
- <button type="button" class="btn-secondary" id="saveDraft">保存草稿</button>
252
- <button type="submit" class="btn-primary">更新</button>
253
- </div>
254
- </form>
255
- </div>
256
- `;
257
-
258
- document.body.appendChild(modal);
259
- addKnowledgeModalStyles();
260
-
261
- // 初始化编辑器并设置内容
262
- const Quill = window.Quill;
263
- const quill = new Quill('#kbContentEditor', {
264
- theme: 'snow',
265
- modules: {
266
- toolbar: [
267
- [{ 'header': [1, 2, 3, false] }],
268
- ['bold', 'italic', 'underline', 'strike'],
269
- [{ 'list': 'ordered'}, { 'list': 'bullet' }],
270
- [{ 'color': [] }, { 'background': [] }],
271
- ['link', 'code-block'],
272
- ['clean']
273
- ]
274
- }
275
- });
276
-
277
- quill.root.innerHTML = kb.content;
278
-
279
- // 关闭模态框
280
- const closeModal = () => {
281
- modal.remove();
282
- };
283
-
284
- document.getElementById('closeKnowledgeModal').addEventListener('click', closeModal);
285
- modal.addEventListener('click', (e) => {
286
- if (e.target === modal) closeModal();
287
- });
288
-
289
- // 保存草稿
290
- document.getElementById('saveDraft').addEventListener('click', async () => {
291
- await updateKnowledge(false);
292
- });
293
-
294
- // 更新
295
- document.getElementById('editKnowledgeForm').addEventListener('submit', async (e) => {
296
- e.preventDefault();
297
- await updateKnowledge(true);
298
- });
299
-
300
- async function updateKnowledge(publish) {
301
- const title = document.getElementById('kbTitle').value.trim();
302
- const category = document.getElementById('kbCategory').value.trim();
303
- const tags = document.getElementById('kbTags').value.split(',').map(t => t.trim()).filter(t => t);
304
- const content = quill.root.innerHTML;
305
- const permission = document.querySelector('input[name="permission"]:checked').value;
306
-
307
- if (!title || !content) {
308
- alert('请填写标题和内容');
309
- return;
310
- }
311
-
312
- try {
313
- const token = localStorage.getItem('token');
314
- const response = await fetch(`http://localhost:8765/api/knowledge/${kbId}`, {
315
- method: 'PUT',
316
- headers: {
317
- 'Content-Type': 'application/json',
318
- 'Authorization': `Bearer ${token}`
319
- },
320
- body: JSON.stringify({
321
- title,
322
- content,
323
- category,
324
- tags,
325
- status: publish ? 'published' : 'draft',
326
- permission: permission
327
- })
328
- });
329
-
330
- const result = await response.json();
331
- if (result.success) {
332
- alert('更新成功!');
333
- closeModal();
334
- // 触发自定义事件通知刷新
335
- window.dispatchEvent(new CustomEvent('knowledgeUpdated', {
336
- detail: { groupId: currentGroup._id }
337
- }));
338
- } else {
339
- alert('更新失败: ' + (result.error?.message || '未知错误'));
340
- }
341
- } catch (error) {
342
- alert('更新失败: ' + error.message);
343
- }
344
- }
345
-
346
- } catch (error) {
347
- alert('加载文档失败: ' + error.message);
348
- }
349
- }
350
-
351
- // 添加模态框样式
352
- function addKnowledgeModalStyles() {
353
- if (document.getElementById('knowledge-modal-styles')) return;
354
-
355
- const style = document.createElement('style');
356
- style.id = 'knowledge-modal-styles';
357
- style.textContent = `
358
- .knowledge-modal-content {
359
- max-width: 900px;
360
- max-height: 90vh;
361
- overflow-y: auto;
362
- }
363
-
364
- .permission-options {
365
- display: grid;
366
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
367
- gap: 12px;
368
- margin-top: 12px;
369
- }
370
-
371
- .permission-option {
372
- cursor: pointer;
373
- }
374
-
375
- .permission-option input[type="radio"] {
376
- display: none;
377
- }
378
-
379
- .option-content {
380
- display: flex;
381
- align-items: center;
382
- gap: 12px;
383
- padding: 16px;
384
- background: var(--bg-dark);
385
- border: 2px solid var(--border);
386
- border-radius: 12px;
387
- transition: all 0.3s ease;
388
- }
389
-
390
- .permission-option:hover .option-content {
391
- border-color: var(--primary);
392
- background: rgba(99,102,241,0.05);
393
- }
394
-
395
- .permission-option input[type="radio"]:checked + .option-content {
396
- border-color: var(--primary);
397
- background: linear-gradient(135deg, rgba(99,102,241,0.1) 0%, rgba(99,102,241,0.05) 100%);
398
- box-shadow: 0 4px 12px rgba(99,102,241,0.2);
399
- }
400
-
401
- .option-icon {
402
- font-size: 24px;
403
- }
404
-
405
- .option-content strong {
406
- display: block;
407
- font-size: 15px;
408
- color: var(--text-primary);
409
- margin-bottom: 4px;
410
- }
411
-
412
- .option-content p {
413
- margin: 0;
414
- font-size: 13px;
415
- color: var(--text-secondary);
416
- }
417
-
418
- #kbContentEditor {
419
- background: white;
420
- border-radius: 8px;
421
- }
422
-
423
- .ql-toolbar {
424
- border-radius: 8px 8px 0 0 !important;
425
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
426
- border: none !important;
427
- padding: 12px !important;
428
- }
429
-
430
- .ql-toolbar .ql-stroke {
431
- stroke: white !important;
432
- }
433
-
434
- .ql-toolbar .ql-fill {
435
- fill: white !important;
436
- }
437
-
438
- .ql-toolbar .ql-picker-label {
439
- color: white !important;
440
- }
441
-
442
- .ql-toolbar button:hover,
443
- .ql-toolbar button:focus,
444
- .ql-toolbar button.ql-active {
445
- background: rgba(255, 255, 255, 0.2) !important;
446
- border-radius: 4px;
447
- }
448
-
449
- .ql-toolbar .ql-picker-label:hover,
450
- .ql-toolbar .ql-picker-label.ql-active {
451
- background: rgba(255, 255, 255, 0.2) !important;
452
- border-radius: 4px;
453
- }
454
-
455
- .ql-container {
456
- border-radius: 0 0 8px 8px !important;
457
- background: white;
458
- border: 1px solid #e5e7eb !important;
459
- border-top: none !important;
460
- }
461
-
462
- .ql-editor {
463
- color: #000000 !important;
464
- min-height: 300px;
465
- }
466
-
467
- .ql-editor p,
468
- .ql-editor h1,
469
- .ql-editor h2,
470
- .ql-editor h3,
471
- .ql-editor h4,
472
- .ql-editor h5,
473
- .ql-editor h6,
474
- .ql-editor li,
475
- .ql-editor span {
476
- color: #000000 !important;
477
- }
478
-
479
- .ql-editor.ql-blank::before {
480
- color: #9ca3af !important;
481
- }
482
- `;
483
- document.head.appendChild(style);
484
- }
485
-
1
+ /**
2
+ * 知识库创建和编辑功能
3
+ */
4
+
5
+ // 显示创建知识库模态框
6
+ export function showCreateKnowledgeModal(currentGroup, apiService, container, currentUserId) {
7
+ const modal = document.createElement('div');
8
+ modal.className = 'modal';
9
+ modal.id = 'createKnowledgeModal';
10
+
11
+ modal.innerHTML = `
12
+ <div class="modal-content knowledge-modal-content">
13
+ <div class="modal-header">
14
+ <h3>✨ 创建知识库文档</h3>
15
+ <button class="modal-close" id="closeKnowledgeModal">×</button>
16
+ </div>
17
+
18
+ <form id="createKnowledgeForm">
19
+ <div class="form-group">
20
+ <label>标题 *</label>
21
+ <input type="text" id="kbTitle" placeholder="请输入文档标题" required>
22
+ </div>
23
+
24
+ <div class="form-group">
25
+ <label>分类</label>
26
+ <input type="text" id="kbCategory" placeholder="例如:技术文档、使用指南">
27
+ </div>
28
+
29
+ <div class="form-group">
30
+ <label>标签(用逗号分隔)</label>
31
+ <input type="text" id="kbTags" placeholder="例如:API, 教程, 入门">
32
+ </div>
33
+
34
+ <div class="form-group">
35
+ <label>内容 *</label>
36
+ <div id="kbContentEditor" style="height: 300px;"></div>
37
+ </div>
38
+
39
+ <div class="form-group">
40
+ <label>权限设置</label>
41
+ <div class="permission-options">
42
+ <label class="permission-option">
43
+ <input type="radio" name="permission" value="private" checked>
44
+ <div class="option-content">
45
+ <span class="option-icon">🔒</span>
46
+ <div>
47
+ <strong>私有</strong>
48
+ <p>仅自己可见</p>
49
+ </div>
50
+ </div>
51
+ </label>
52
+ <label class="permission-option">
53
+ <input type="radio" name="permission" value="group">
54
+ <div class="option-content">
55
+ <span class="option-icon">👥</span>
56
+ <div>
57
+ <strong>群组可见</strong>
58
+ <p>群组成员可见</p>
59
+ </div>
60
+ </div>
61
+ </label>
62
+ <label class="permission-option">
63
+ <input type="radio" name="permission" value="public">
64
+ <div class="option-content">
65
+ <span class="option-icon">🌐</span>
66
+ <div>
67
+ <strong>公开</strong>
68
+ <p>所有人可见</p>
69
+ </div>
70
+ </div>
71
+ </label>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="form-actions">
76
+ <button type="button" class="btn-secondary" id="saveDraft">保存草稿</button>
77
+ <button type="submit" class="btn-primary">发布</button>
78
+ </div>
79
+ </form>
80
+ </div>
81
+ `;
82
+
83
+ document.body.appendChild(modal);
84
+ addKnowledgeModalStyles();
85
+
86
+ // 初始化 Quill 编辑器
87
+ const Quill = window.Quill;
88
+ const quill = new Quill('#kbContentEditor', {
89
+ theme: 'snow',
90
+ modules: {
91
+ toolbar: [
92
+ [{ 'header': [1, 2, 3, false] }],
93
+ ['bold', 'italic', 'underline', 'strike'],
94
+ [{ 'list': 'ordered'}, { 'list': 'bullet' }],
95
+ [{ 'color': [] }, { 'background': [] }],
96
+ ['link', 'code-block'],
97
+ ['clean']
98
+ ]
99
+ }
100
+ });
101
+
102
+ // 关闭模态框
103
+ const closeModal = () => {
104
+ modal.remove();
105
+ };
106
+
107
+ document.getElementById('closeKnowledgeModal').addEventListener('click', closeModal);
108
+ modal.addEventListener('click', (e) => {
109
+ if (e.target === modal) closeModal();
110
+ });
111
+
112
+ // 保存草稿
113
+ document.getElementById('saveDraft').addEventListener('click', async () => {
114
+ await saveKnowledge(false);
115
+ });
116
+
117
+ // 发布
118
+ document.getElementById('createKnowledgeForm').addEventListener('submit', async (e) => {
119
+ e.preventDefault();
120
+ await saveKnowledge(true);
121
+ });
122
+
123
+ async function saveKnowledge(publish) {
124
+ const title = document.getElementById('kbTitle').value.trim();
125
+ const category = document.getElementById('kbCategory').value.trim();
126
+ const tags = document.getElementById('kbTags').value.split(',').map(t => t.trim()).filter(t => t);
127
+ const content = quill.root.innerHTML;
128
+ const permission = document.querySelector('input[name="permission"]:checked').value;
129
+
130
+ if (!title || !content) {
131
+ alert('请填写标题和内容');
132
+ return;
133
+ }
134
+
135
+ try {
136
+ const token = localStorage.getItem('token');
137
+ const response = await fetch('http://localhost:8765/api/knowledge', {
138
+ method: 'POST',
139
+ headers: {
140
+ 'Content-Type': 'application/json',
141
+ 'Authorization': `Bearer ${token}`
142
+ },
143
+ body: JSON.stringify({
144
+ title,
145
+ content,
146
+ category,
147
+ tags,
148
+ groupId: currentGroup._id,
149
+ status: publish ? 'published' : 'draft',
150
+ permission: permission,
151
+ author: currentUserId
152
+ })
153
+ });
154
+
155
+ const result = await response.json();
156
+ if (result.success) {
157
+ alert(publish ? '发布成功!' : '保存成功!');
158
+ closeModal();
159
+ // 触发自定义事件通知刷新
160
+ window.dispatchEvent(new CustomEvent('knowledgeUpdated', {
161
+ detail: { groupId: currentGroup._id }
162
+ }));
163
+ } else {
164
+ alert('保存失败: ' + (result.error?.message || '未知错误'));
165
+ }
166
+ } catch (error) {
167
+ alert('保存失败: ' + error.message);
168
+ }
169
+ }
170
+ }
171
+
172
+ // 显示编辑知识库模态框
173
+ export async function showEditKnowledgeModal(kbId, currentGroup, apiService, container, currentUserId) {
174
+ try {
175
+ const token = localStorage.getItem('token');
176
+ const response = await fetch(`http://localhost:8765/api/knowledge/${kbId}`, {
177
+ headers: { 'Authorization': `Bearer ${token}` }
178
+ });
179
+ const result = await response.json();
180
+ const kb = result.data.knowledge;
181
+
182
+ const modal = document.createElement('div');
183
+ modal.className = 'modal';
184
+ modal.id = 'editKnowledgeModal';
185
+
186
+ modal.innerHTML = `
187
+ <div class="modal-content knowledge-modal-content">
188
+ <div class="modal-header">
189
+ <h3>✏️ 编辑知识库文档</h3>
190
+ <button class="modal-close" id="closeKnowledgeModal">×</button>
191
+ </div>
192
+
193
+ <form id="editKnowledgeForm">
194
+ <div class="form-group">
195
+ <label>标题 *</label>
196
+ <input type="text" id="kbTitle" value="${kb.title}" required>
197
+ </div>
198
+
199
+ <div class="form-group">
200
+ <label>分类</label>
201
+ <input type="text" id="kbCategory" value="${kb.category || ''}">
202
+ </div>
203
+
204
+ <div class="form-group">
205
+ <label>标签(用逗号分隔)</label>
206
+ <input type="text" id="kbTags" value="${kb.tags ? kb.tags.join(', ') : ''}">
207
+ </div>
208
+
209
+ <div class="form-group">
210
+ <label>内容 *</label>
211
+ <div id="kbContentEditor" style="height: 300px;"></div>
212
+ </div>
213
+
214
+ <div class="form-group">
215
+ <label>权限设置</label>
216
+ <div class="permission-options">
217
+ <label class="permission-option">
218
+ <input type="radio" name="permission" value="private" ${kb.permission === 'private' ? 'checked' : ''}>
219
+ <div class="option-content">
220
+ <span class="option-icon">🔒</span>
221
+ <div>
222
+ <strong>私有</strong>
223
+ <p>仅自己可见</p>
224
+ </div>
225
+ </div>
226
+ </label>
227
+ <label class="permission-option">
228
+ <input type="radio" name="permission" value="group" ${kb.permission === 'group' ? 'checked' : ''}>
229
+ <div class="option-content">
230
+ <span class="option-icon">👥</span>
231
+ <div>
232
+ <strong>群组可见</strong>
233
+ <p>群组成员可见</p>
234
+ </div>
235
+ </div>
236
+ </label>
237
+ <label class="permission-option">
238
+ <input type="radio" name="permission" value="public" ${kb.permission === 'public' ? 'checked' : ''}>
239
+ <div class="option-content">
240
+ <span class="option-icon">🌐</span>
241
+ <div>
242
+ <strong>公开</strong>
243
+ <p>所有人可见</p>
244
+ </div>
245
+ </div>
246
+ </label>
247
+ </div>
248
+ </div>
249
+
250
+ <div class="form-actions">
251
+ <button type="button" class="btn-secondary" id="saveDraft">保存草稿</button>
252
+ <button type="submit" class="btn-primary">更新</button>
253
+ </div>
254
+ </form>
255
+ </div>
256
+ `;
257
+
258
+ document.body.appendChild(modal);
259
+ addKnowledgeModalStyles();
260
+
261
+ // 初始化编辑器并设置内容
262
+ const Quill = window.Quill;
263
+ const quill = new Quill('#kbContentEditor', {
264
+ theme: 'snow',
265
+ modules: {
266
+ toolbar: [
267
+ [{ 'header': [1, 2, 3, false] }],
268
+ ['bold', 'italic', 'underline', 'strike'],
269
+ [{ 'list': 'ordered'}, { 'list': 'bullet' }],
270
+ [{ 'color': [] }, { 'background': [] }],
271
+ ['link', 'code-block'],
272
+ ['clean']
273
+ ]
274
+ }
275
+ });
276
+
277
+ quill.root.innerHTML = kb.content;
278
+
279
+ // 关闭模态框
280
+ const closeModal = () => {
281
+ modal.remove();
282
+ };
283
+
284
+ document.getElementById('closeKnowledgeModal').addEventListener('click', closeModal);
285
+ modal.addEventListener('click', (e) => {
286
+ if (e.target === modal) closeModal();
287
+ });
288
+
289
+ // 保存草稿
290
+ document.getElementById('saveDraft').addEventListener('click', async () => {
291
+ await updateKnowledge(false);
292
+ });
293
+
294
+ // 更新
295
+ document.getElementById('editKnowledgeForm').addEventListener('submit', async (e) => {
296
+ e.preventDefault();
297
+ await updateKnowledge(true);
298
+ });
299
+
300
+ async function updateKnowledge(publish) {
301
+ const title = document.getElementById('kbTitle').value.trim();
302
+ const category = document.getElementById('kbCategory').value.trim();
303
+ const tags = document.getElementById('kbTags').value.split(',').map(t => t.trim()).filter(t => t);
304
+ const content = quill.root.innerHTML;
305
+ const permission = document.querySelector('input[name="permission"]:checked').value;
306
+
307
+ if (!title || !content) {
308
+ alert('请填写标题和内容');
309
+ return;
310
+ }
311
+
312
+ try {
313
+ const token = localStorage.getItem('token');
314
+ const response = await fetch(`http://localhost:8765/api/knowledge/${kbId}`, {
315
+ method: 'PUT',
316
+ headers: {
317
+ 'Content-Type': 'application/json',
318
+ 'Authorization': `Bearer ${token}`
319
+ },
320
+ body: JSON.stringify({
321
+ title,
322
+ content,
323
+ category,
324
+ tags,
325
+ status: publish ? 'published' : 'draft',
326
+ permission: permission
327
+ })
328
+ });
329
+
330
+ const result = await response.json();
331
+ if (result.success) {
332
+ alert('更新成功!');
333
+ closeModal();
334
+ // 触发自定义事件通知刷新
335
+ window.dispatchEvent(new CustomEvent('knowledgeUpdated', {
336
+ detail: { groupId: currentGroup._id }
337
+ }));
338
+ } else {
339
+ alert('更新失败: ' + (result.error?.message || '未知错误'));
340
+ }
341
+ } catch (error) {
342
+ alert('更新失败: ' + error.message);
343
+ }
344
+ }
345
+
346
+ } catch (error) {
347
+ alert('加载文档失败: ' + error.message);
348
+ }
349
+ }
350
+
351
+ // 添加模态框样式
352
+ function addKnowledgeModalStyles() {
353
+ if (document.getElementById('knowledge-modal-styles')) return;
354
+
355
+ const style = document.createElement('style');
356
+ style.id = 'knowledge-modal-styles';
357
+ style.textContent = `
358
+ .knowledge-modal-content {
359
+ max-width: 900px;
360
+ max-height: 90vh;
361
+ overflow-y: auto;
362
+ }
363
+
364
+ .permission-options {
365
+ display: grid;
366
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
367
+ gap: 12px;
368
+ margin-top: 12px;
369
+ }
370
+
371
+ .permission-option {
372
+ cursor: pointer;
373
+ }
374
+
375
+ .permission-option input[type="radio"] {
376
+ display: none;
377
+ }
378
+
379
+ .option-content {
380
+ display: flex;
381
+ align-items: center;
382
+ gap: 12px;
383
+ padding: 16px;
384
+ background: var(--bg-dark);
385
+ border: 2px solid var(--border);
386
+ border-radius: 12px;
387
+ transition: all 0.3s ease;
388
+ }
389
+
390
+ .permission-option:hover .option-content {
391
+ border-color: var(--primary);
392
+ background: rgba(99,102,241,0.05);
393
+ }
394
+
395
+ .permission-option input[type="radio"]:checked + .option-content {
396
+ border-color: var(--primary);
397
+ background: linear-gradient(135deg, rgba(99,102,241,0.1) 0%, rgba(99,102,241,0.05) 100%);
398
+ box-shadow: 0 4px 12px rgba(99,102,241,0.2);
399
+ }
400
+
401
+ .option-icon {
402
+ font-size: 24px;
403
+ }
404
+
405
+ .option-content strong {
406
+ display: block;
407
+ font-size: 15px;
408
+ color: var(--text-primary);
409
+ margin-bottom: 4px;
410
+ }
411
+
412
+ .option-content p {
413
+ margin: 0;
414
+ font-size: 13px;
415
+ color: var(--text-secondary);
416
+ }
417
+
418
+ #kbContentEditor {
419
+ background: white;
420
+ border-radius: 8px;
421
+ }
422
+
423
+ .ql-toolbar {
424
+ border-radius: 8px 8px 0 0 !important;
425
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
426
+ border: none !important;
427
+ padding: 12px !important;
428
+ }
429
+
430
+ .ql-toolbar .ql-stroke {
431
+ stroke: white !important;
432
+ }
433
+
434
+ .ql-toolbar .ql-fill {
435
+ fill: white !important;
436
+ }
437
+
438
+ .ql-toolbar .ql-picker-label {
439
+ color: white !important;
440
+ }
441
+
442
+ .ql-toolbar button:hover,
443
+ .ql-toolbar button:focus,
444
+ .ql-toolbar button.ql-active {
445
+ background: rgba(255, 255, 255, 0.2) !important;
446
+ border-radius: 4px;
447
+ }
448
+
449
+ .ql-toolbar .ql-picker-label:hover,
450
+ .ql-toolbar .ql-picker-label.ql-active {
451
+ background: rgba(255, 255, 255, 0.2) !important;
452
+ border-radius: 4px;
453
+ }
454
+
455
+ .ql-container {
456
+ border-radius: 0 0 8px 8px !important;
457
+ background: white;
458
+ border: 1px solid #e5e7eb !important;
459
+ border-top: none !important;
460
+ }
461
+
462
+ .ql-editor {
463
+ color: #000000 !important;
464
+ min-height: 300px;
465
+ }
466
+
467
+ .ql-editor p,
468
+ .ql-editor h1,
469
+ .ql-editor h2,
470
+ .ql-editor h3,
471
+ .ql-editor h4,
472
+ .ql-editor h5,
473
+ .ql-editor h6,
474
+ .ql-editor li,
475
+ .ql-editor span {
476
+ color: #000000 !important;
477
+ }
478
+
479
+ .ql-editor.ql-blank::before {
480
+ color: #9ca3af !important;
481
+ }
482
+ `;
483
+ document.head.appendChild(style);
484
+ }
485
+