collabdocchat 2.4.4 → 2.4.6

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 (82) hide show
  1. package/bin/cli.js +1 -1
  2. package/package.json +4 -2
  3. package/scripts/cleanup-scripts.js +140 -0
  4. package/scripts/fix-startup-issues.js +136 -0
  5. package/scripts/start-app.js +11 -5
  6. package/scripts/start-simple.js +96 -0
  7. package/server/index.js +4 -0
  8. package/server/index.js.bak +97 -0
  9. package/server/models/Document.js +5 -0
  10. package/server/models/KnowledgeBase.js +259 -254
  11. package/server/models/Poll.js +97 -0
  12. package/server/routes/ai.js +391 -327
  13. package/server/routes/audit.js +61 -0
  14. package/server/routes/documents.js +74 -5
  15. package/server/routes/export.js +171 -10
  16. package/server/routes/files.js +27 -4
  17. package/server/routes/knowledge.js +31 -22
  18. package/server/routes/messages.js +142 -0
  19. package/server/routes/polls.js +241 -0
  20. package/server/routes/tasks.js +1 -0
  21. package/server/routes/workflows.js +27 -0
  22. package/server/utils/auditLogger.js +268 -238
  23. package/src/pages/admin-dashboard.js +1431 -335
  24. package/src/pages/admin-dashboard.js.audit-optimize.bak +4134 -0
  25. package/src/pages/admin-dashboard.js.bak +4041 -0
  26. package/src/pages/admin-dashboard.js.broken.bak +4099 -0
  27. package/src/pages/admin-dashboard.js.comprehensive.bak +4099 -0
  28. package/src/pages/admin-dashboard.js.escape.bak +4099 -0
  29. package/src/pages/admin-dashboard.js.final-final-fix.bak +4099 -0
  30. package/src/pages/admin-dashboard.js.final-fix.bak +4099 -0
  31. package/src/pages/admin-dashboard.js.final.bak +4099 -0
  32. package/src/pages/admin-dashboard.js.indent-fix.bak +4099 -0
  33. package/src/pages/admin-dashboard.js.last-fix.bak +4099 -0
  34. package/src/pages/admin-dashboard.js.line595-fix.bak +4099 -0
  35. package/src/pages/admin-dashboard.js.pre-manual-fix.bak +4099 -0
  36. package/src/pages/admin-dashboard.js.syntax.bak +4099 -0
  37. package/src/pages/admin-dashboard.js.test.bak +4099 -0
  38. package/src/pages/optimized-task-detail-original.js +838 -0
  39. package/src/pages/optimized-task-detail.js +324 -22
  40. package/src/pages/optimized-task-detail.js.bak +1162 -0
  41. package/src/pages/poll-detail-enhanced.js +394 -0
  42. package/src/pages/update-poll-display.js +380 -0
  43. package/src/pages/user-dashboard.js +1860 -1006
  44. package/src/services/api.js +326 -265
  45. package/src/services/auth.js +54 -54
  46. package/src/services/websocket.js +88 -80
  47. package/scripts/add-button-hover.js +0 -56
  48. package/scripts/add-missing-functions.js +0 -66
  49. package/scripts/add-more-features.js +0 -427
  50. package/scripts/add-user-functions.js +0 -201
  51. package/scripts/auto-publish.js +0 -63
  52. package/scripts/beautify-buttons.js +0 -45
  53. package/scripts/beautify-ui.js +0 -267
  54. package/scripts/check-encoding.js +0 -41
  55. package/scripts/check-syntax.js +0 -54
  56. package/scripts/find-buttons.js +0 -20
  57. package/scripts/find-duplicate.js +0 -35
  58. package/scripts/find-sidebar-buttons.js +0 -21
  59. package/scripts/fix-help.js +0 -274
  60. package/scripts/fix-issues-step1.js +0 -73
  61. package/scripts/fix-issues-step2.js +0 -93
  62. package/scripts/fix-issues-step3.js +0 -155
  63. package/scripts/fix-issues-step4.js +0 -150
  64. package/scripts/fix-optimized-views.js +0 -37
  65. package/scripts/fix-ports.js +0 -77
  66. package/scripts/fix-settings.js +0 -258
  67. package/scripts/fix-user-dashboard.js +0 -62
  68. package/scripts/fix-workflow.js +0 -110
  69. package/scripts/refactor-step1.js +0 -32
  70. package/scripts/refactor-step2.js +0 -255
  71. package/scripts/refactor-step3.js +0 -137
  72. package/scripts/refactor-step4.js +0 -183
  73. package/scripts/refactor-step5.js +0 -181
  74. package/scripts/refactor-step6.js +0 -254
  75. package/scripts/refactor-step7.js +0 -291
  76. package/scripts/remove-bom.js +0 -69
  77. package/scripts/remove-quill-from-user-dashboard.js +0 -49
  78. package/scripts/remove-quill-imports-only.js +0 -32
  79. package/scripts/update-port-user.js +0 -21
  80. package/scripts/update-port.js +0 -22
  81. package/src/pages/simplified-workflows.js +0 -652
  82. package/src/utils/ai-assistant.js +0 -1384
@@ -1,110 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
-
8
- const filePath = path.join(__dirname, '../src/pages/admin-dashboard.js');
9
-
10
- console.log('读取文件...');
11
- let content = fs.readFileSync(filePath, 'utf8');
12
-
13
- // 1. 替换工作流模态框,添加更多选项
14
- console.log('丰富工作流功能...');
15
- const oldWorkflowModal = ` <div id="workflowModal" class="modal hidden">
16
- <div class="modal-content">
17
- <h3>创建工作流</h3>
18
- <form id="workflowForm">
19
- <div class="form-group">
20
- <label>⚙️ 工作流名称</label>
21
- <input type="text" name="name" required style="width: 100%; padding: 10px; border: 1px solid var(--border); border-radius: 8px;">
22
- </div>
23
- <div class="form-group">
24
- <label>📝 描述</label>
25
- <textarea name="description" rows="3" style="width: 100%; padding: 10px; border: 1px solid var(--border); border-radius: 8px;"></textarea>
26
- </div>
27
- <div class="form-group">
28
- <label>🔔 触发条件</label>
29
- <select name="trigger" style="width: 100%; padding: 10px; border: 1px solid var(--border); border-radius: 8px;">
30
- <option value="document_create">文档创建时</option>
31
- <option value="document_update">文档更新时</option>
32
- <option value="task_complete">任务完成时</option>
33
- <option value="manual">手动触发</option>
34
- </select>
35
- </div>
36
- <div style="display: flex; gap: 10px; margin-top: 20px;">
37
- <button type="submit" class="btn-primary" style="flex: 1;">创建</button>
38
- <button type="button" class="btn-secondary" id="closeWorkflowModal" style="flex: 1;">取消</button>
39
- </div>
40
- </form>
41
- </div>
42
- </div>`;
43
-
44
- const newWorkflowModal = ` <div id="workflowModal" class="modal hidden">
45
- <div class="modal-content" style="max-width: 700px;">
46
- <div class="modal-header" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 20px; border-radius: 12px 12px 0 0; margin: -20px -20px 20px -20px;">
47
- <h3 style="margin: 0; display: flex; align-items: center; gap: 10px;">
48
- <span style="font-size: 24px;">⚙️</span>
49
- <span>创建工作流</span>
50
- </h3>
51
- </div>
52
- <form id="workflowForm">
53
- <div class="form-group" style="margin-bottom: 20px;">
54
- <label style="display: block; margin-bottom: 8px; font-weight: 600; color: var(--text-secondary);">⚙️ 工作流名称</label>
55
- <input type="text" name="name" required placeholder="例如:文档审批流程" style="width: 100%; padding: 12px; border: 2px solid var(--border); border-radius: 8px; font-size: 14px; transition: border-color 0.2s;">
56
- </div>
57
- <div class="form-group" style="margin-bottom: 20px;">
58
- <label style="display: block; margin-bottom: 8px; font-weight: 600; color: var(--text-secondary);">📝 描述</label>
59
- <textarea name="description" rows="3" placeholder="描述这个工作流的用途..." style="width: 100%; padding: 12px; border: 2px solid var(--border); border-radius: 8px; font-size: 14px; resize: vertical; transition: border-color 0.2s;"></textarea>
60
- </div>
61
- <div class="form-group" style="margin-bottom: 20px;">
62
- <label style="display: block; margin-bottom: 8px; font-weight: 600; color: var(--text-secondary);">⚡ 触发条件</label>
63
- <select name="trigger" style="width: 100%; padding: 12px; border: 2px solid var(--border); border-radius: 8px; font-size: 14px; cursor: pointer; transition: border-color 0.2s;">
64
- <option value="document_create">📄 文档创建时</option>
65
- <option value="document_update">✏️ 文档更新时</option>
66
- <option value="document_delete">🗑️ 文档删除时</option>
67
- <option value="task_create">📋 任务创建时</option>
68
- <option value="task_complete">✅ 任务完成时</option>
69
- <option value="task_overdue">⏰ 任务逾期时</option>
70
- <option value="member_join">👥 成员加入时</option>
71
- <option value="group_create">🏢 群组创建时</option>
72
- <option value="scheduled">⏱️ 定时触发</option>
73
- <option value="manual">🖱️ 手动触发</option>
74
- </select>
75
- </div>
76
- <div class="form-group" style="margin-bottom: 20px;">
77
- <label style="display: block; margin-bottom: 8px; font-weight: 600; color: var(--text-secondary);">🎯 执行操作</label>
78
- <select name="action" style="width: 100%; padding: 12px; border: 2px solid var(--border); border-radius: 8px; font-size: 14px; cursor: pointer; transition: border-color 0.2s;">
79
- <option value="send_notification">📧 发送通知</option>
80
- <option value="send_email">✉️ 发送邮件</option>
81
- <option value="create_task">📋 创建任务</option>
82
- <option value="update_status">🔄 更新状态</option>
83
- <option value="assign_permission">🔐 分配权限</option>
84
- <option value="backup_data">💾 备份数据</option>
85
- <option value="generate_report">📊 生成报告</option>
86
- <option value="call_api">🔗 调用外部API</option>
87
- </select>
88
- </div>
89
- <div class="form-group" style="margin-bottom: 20px;">
90
- <label style="display: block; margin-bottom: 8px; font-weight: 600; color: var(--text-secondary);">⚙️ 操作参数 (JSON格式)</label>
91
- <textarea name="actionParams" rows="4" placeholder='{"message": "任务已完成", "recipients": ["user1"]}' style="width: 100%; padding: 12px; border: 2px solid var(--border); border-radius: 8px; font-size: 13px; font-family: monospace; resize: vertical; transition: border-color 0.2s;"></textarea>
92
- <div style="margin-top: 8px; font-size: 12px; color: var(--text-tertiary);">
93
- 💡 提示:使用 JSON 格式配置操作参数
94
- </div>
95
- </div>
96
- <div style="display: flex; gap: 12px; margin-top: 25px;">
97
- <button type="submit" class="btn-primary" style="flex: 1; padding: 12px; border-radius: 8px; font-weight: 600; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border: none; cursor: pointer; transition: transform 0.2s;">创建</button>
98
- <button type="button" class="btn-secondary" id="closeWorkflowModal" style="flex: 1; padding: 12px; border-radius: 8px; font-weight: 600;">取消</button>
99
- </div>
100
- </form>
101
- </div>
102
- </div>`;
103
-
104
- content = content.replace(oldWorkflowModal, newWorkflowModal);
105
-
106
- console.log('写入文件...');
107
- fs.writeFileSync(filePath, content, 'utf8');
108
-
109
- console.log('✅ 工作流功能已丰富!');
110
-
@@ -1,32 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
-
8
- const filePath = path.join(__dirname, '../src/pages/admin-dashboard.js');
9
-
10
- console.log('读取文件...');
11
- let content = fs.readFileSync(filePath, 'utf8');
12
-
13
- // 1. 从导航菜单中删除 AI助手、数据导出、协作白板、集成管理
14
- console.log('删除菜单项...');
15
- content = content.replace(/<button class="nav-item" data-view="ai">[\s\S]*?AI助手[\s\S]*?<\/button>\s*/g, '');
16
- content = content.replace(/<button class="nav-item" data-view="export">[\s\S]*?数据导出[\s\S]*?<\/button>\s*/g, '');
17
- content = content.replace(/<button class="nav-item" data-view="whiteboard">[\s\S]*?协作白板[\s\S]*?<\/button>\s*/g, '');
18
- content = content.replace(/<button class="nav-item" data-view="integrations">[\s\S]*?集成管理[\s\S]*?<\/button>\s*/g, '');
19
-
20
- // 2. 从 switch 语句中删除对应的 case
21
- console.log('删除 switch case...');
22
- content = content.replace(/case 'integrations':[\s\S]*?await renderIntegrationsView\(contentArea\);[\s\S]*?break;\s*/g, '');
23
-
24
- // 3. 删除 renderIntegrationsView 函数
25
- console.log('删除集成管理函数...');
26
- content = content.replace(/\/\/ 集成管理[\s\S]*?async function renderIntegrationsView\(container\)[\s\S]*?}\s*}\s*;[\s\S]*?}\s*}\s*;/g, '');
27
-
28
- console.log('写入文件...');
29
- fs.writeFileSync(filePath, content, 'utf8');
30
-
31
- console.log('✅ 第一步完成!已删除不需要的菜单项');
32
-
@@ -1,255 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
-
8
- const filePath = path.join(__dirname, '../src/pages/admin-dashboard.js');
9
-
10
- console.log('读取文件...');
11
- let content = fs.readFileSync(filePath, 'utf8');
12
-
13
- // 在群聊视图的按钮组中添加 AI助手 和 协作白板
14
- console.log('在群聊中添加 AI助手 和 协作白板按钮...');
15
- const chatHeaderPattern = /(<h2>群聊 - \$\{currentGroup\.name\}<\/h2>\s*<div style="display: flex; gap: 10px;">[\s\S]*?<button class="btn-secondary" id="manageMuteBtn">个人禁言<\/button>)/;
16
- const chatHeaderReplacement = `$1
17
- <button class="btn-secondary" id="openAIBtn">🤖 AI助手</button>
18
- <button class="btn-secondary" id="openWhiteboardBtn">🎨 协作白板</button>`;
19
-
20
- content = content.replace(chatHeaderPattern, chatHeaderReplacement);
21
-
22
- // 在群聊视图中添加 AI助手和白板的模态框
23
- console.log('添加 AI助手和白板模态框...');
24
- const chatContainerPattern = /(<div id="manageMuteModal" class="modal hidden">[\s\S]*?<\/div>\s*<\/div>)/;
25
- const chatContainerReplacement = `$1
26
-
27
- <!-- AI助手模态框 -->
28
- <div id="aiModal" class="modal hidden">
29
- <div class="modal-content" style="max-width: 800px; height: 80vh;">
30
- <div class="modal-header">
31
- <h3>🤖 AI助手</h3>
32
- <button class="modal-close" id="closeAIModal">&times;</button>
33
- </div>
34
- <div class="ai-chat-container" style="display: flex; flex-direction: column; height: calc(100% - 60px);">
35
- <div class="ai-chat" id="aiChatMessages" style="flex: 1; overflow-y: auto; padding: 20px; background: var(--bg-secondary);">
36
- <div class="ai-message ai">
37
- <p>你好!我是AI助手,有什么可以帮助你的吗?</p>
38
- <p>你可以问我关于文档、任务、群组的问题。</p>
39
- </div>
40
- </div>
41
- <div class="ai-input-container" style="padding: 15px; border-top: 1px solid var(--border);">
42
- <textarea id="aiInputText" placeholder="向AI助手提问..." rows="3" style="width: 100%; padding: 10px; border: 1px solid var(--border); border-radius: 8px; resize: none;"></textarea>
43
- <button class="btn-primary" id="aiSendBtnModal" style="margin-top: 10px; width: 100%;">发送</button>
44
- </div>
45
- </div>
46
- </div>
47
- </div>
48
-
49
- <!-- 协作白板模态框 -->
50
- <div id="whiteboardModal" class="modal hidden">
51
- <div class="modal-content" style="max-width: 95vw; max-height: 90vh; width: 1400px;">
52
- <div class="modal-header">
53
- <h3>🎨 协作白板</h3>
54
- <div style="display: flex; gap: 10px;">
55
- <button class="btn-secondary" id="clearCanvasBtn">清空画布</button>
56
- <button class="btn-primary" id="saveCanvasBtn">保存白板</button>
57
- <button class="modal-close" id="closeWhiteboardModal">&times;</button>
58
- </div>
59
- </div>
60
- <div class="whiteboard-container" style="padding: 15px;">
61
- <div class="whiteboard-toolbar" style="display: flex; gap: 10px; margin-bottom: 15px; padding: 10px; background: var(--bg-secondary); border-radius: 8px;">
62
- <button class="tool-btn active" data-tool="pen" style="padding: 8px 15px; border: 2px solid var(--primary); border-radius: 6px; background: var(--primary); color: white;">✏️ 画笔</button>
63
- <button class="tool-btn" data-tool="eraser" style="padding: 8px 15px; border: 2px solid var(--border); border-radius: 6px; background: transparent;">🧹 橡皮擦</button>
64
- <input type="color" id="colorPickerCanvas" value="#000000" title="颜色" style="width: 50px; height: 40px; border: none; border-radius: 6px; cursor: pointer;">
65
- <input type="range" id="brushSizeCanvas" min="1" max="20" value="3" title="画笔大小" style="width: 150px;">
66
- <span id="brushSizeLabel" style="padding: 8px 15px;">大小: 3</span>
67
- </div>
68
- <canvas id="whiteboardCanvas" width="1300" height="600" style="border: 2px solid var(--border); background: white; cursor: crosshair; border-radius: 8px; display: block;"></canvas>
69
- </div>
70
- </div>
71
- </div>`;
72
-
73
- content = content.replace(chatContainerPattern, chatContainerReplacement);
74
-
75
- // 在群聊视图函数末尾添加按钮事件处理
76
- console.log('添加按钮事件处理...');
77
- const chatEndPattern = /(sendBtn\.addEventListener\('click', sendMessage\);[\s\S]*?messageInput\.addEventListener\('keypress', \(e\) => \{[\s\S]*?if \(e\.key === 'Enter'\) sendMessage\(\);[\s\S]*?\}\);)/;
78
- const chatEndReplacement = `$1
79
-
80
- // AI助手按钮
81
- document.getElementById('openAIBtn').addEventListener('click', () => {
82
- document.getElementById('aiModal').classList.remove('hidden');
83
- });
84
-
85
- document.getElementById('closeAIModal').addEventListener('click', () => {
86
- document.getElementById('aiModal').classList.add('hidden');
87
- });
88
-
89
- document.getElementById('aiSendBtnModal').addEventListener('click', async () => {
90
- const input = document.getElementById('aiInputText');
91
- const question = input.value.trim();
92
- if (!question) return;
93
-
94
- const chatMessages = document.getElementById('aiChatMessages');
95
-
96
- // 显示用户消息
97
- const userMsg = document.createElement('div');
98
- userMsg.className = 'ai-message user';
99
- userMsg.style.cssText = 'background: var(--primary); color: white; padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%; margin-left: auto; text-align: right;';
100
- userMsg.textContent = question;
101
- chatMessages.appendChild(userMsg);
102
- input.value = '';
103
-
104
- // 显示加载中
105
- const loadingMsg = document.createElement('div');
106
- loadingMsg.className = 'ai-message ai loading';
107
- loadingMsg.style.cssText = 'background: var(--bg-tertiary); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;';
108
- loadingMsg.textContent = '思考中...';
109
- chatMessages.appendChild(loadingMsg);
110
- chatMessages.scrollTop = chatMessages.scrollHeight;
111
-
112
- try {
113
- const token = localStorage.getItem('token');
114
- const response = await fetch('http://localhost:3000/api/ai/ask', {
115
- method: 'POST',
116
- headers: {
117
- 'Content-Type': 'application/json',
118
- 'Authorization': \`Bearer \${token}\`
119
- },
120
- body: JSON.stringify({ question, groupId: currentGroup?._id })
121
- });
122
- const result = await response.json();
123
-
124
- loadingMsg.remove();
125
- const aiMsg = document.createElement('div');
126
- aiMsg.className = 'ai-message ai';
127
- aiMsg.style.cssText = 'background: var(--bg-tertiary); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;';
128
- aiMsg.textContent = result.answer || '抱歉,我无法回答这个问题。';
129
- chatMessages.appendChild(aiMsg);
130
- chatMessages.scrollTop = chatMessages.scrollHeight;
131
- } catch (error) {
132
- loadingMsg.remove();
133
- const errorMsg = document.createElement('div');
134
- errorMsg.className = 'ai-message ai error';
135
- errorMsg.style.cssText = 'background: var(--danger); color: white; padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;';
136
- errorMsg.textContent = '抱歉,发生了错误: ' + error.message;
137
- chatMessages.appendChild(errorMsg);
138
- }
139
- });
140
-
141
- // 协作白板按钮
142
- document.getElementById('openWhiteboardBtn').addEventListener('click', () => {
143
- document.getElementById('whiteboardModal').classList.remove('hidden');
144
- initWhiteboard();
145
- });
146
-
147
- document.getElementById('closeWhiteboardModal').addEventListener('click', () => {
148
- document.getElementById('whiteboardModal').classList.add('hidden');
149
- });
150
-
151
- function initWhiteboard() {
152
- const canvas = document.getElementById('whiteboardCanvas');
153
- if (!canvas) return;
154
-
155
- const ctx = canvas.getContext('2d');
156
- let isDrawing = false;
157
- let currentTool = 'pen';
158
- let currentColor = '#000000';
159
- let brushSize = 3;
160
- let lastX = 0;
161
- let lastY = 0;
162
-
163
- // 工具切换
164
- document.querySelectorAll('.tool-btn').forEach(btn => {
165
- btn.onclick = () => {
166
- document.querySelectorAll('.tool-btn').forEach(b => {
167
- b.style.background = 'transparent';
168
- b.style.borderColor = 'var(--border)';
169
- b.style.color = 'inherit';
170
- b.classList.remove('active');
171
- });
172
- btn.style.background = 'var(--primary)';
173
- btn.style.borderColor = 'var(--primary)';
174
- btn.style.color = 'white';
175
- btn.classList.add('active');
176
- currentTool = btn.dataset.tool;
177
- };
178
- });
179
-
180
- const colorPicker = document.getElementById('colorPickerCanvas');
181
- if (colorPicker) {
182
- colorPicker.onchange = (e) => {
183
- currentColor = e.target.value;
184
- };
185
- }
186
-
187
- const brushSizeInput = document.getElementById('brushSizeCanvas');
188
- const brushSizeLabel = document.getElementById('brushSizeLabel');
189
- if (brushSizeInput && brushSizeLabel) {
190
- brushSizeInput.oninput = (e) => {
191
- brushSize = e.target.value;
192
- brushSizeLabel.textContent = \`大小: \${brushSize}\`;
193
- };
194
- }
195
-
196
- // 绘画功能
197
- canvas.onmousedown = (e) => {
198
- isDrawing = true;
199
- const rect = canvas.getBoundingClientRect();
200
- lastX = e.clientX - rect.left;
201
- lastY = e.clientY - rect.top;
202
- };
203
-
204
- canvas.onmousemove = (e) => {
205
- if (!isDrawing) return;
206
-
207
- const rect = canvas.getBoundingClientRect();
208
- const x = e.clientX - rect.left;
209
- const y = e.clientY - rect.top;
210
-
211
- ctx.beginPath();
212
- ctx.moveTo(lastX, lastY);
213
- ctx.lineTo(x, y);
214
- ctx.strokeStyle = currentTool === 'eraser' ? '#ffffff' : currentColor;
215
- ctx.lineWidth = brushSize;
216
- ctx.lineCap = 'round';
217
- ctx.stroke();
218
-
219
- lastX = x;
220
- lastY = y;
221
- };
222
-
223
- canvas.onmouseup = () => {
224
- isDrawing = false;
225
- };
226
-
227
- canvas.onmouseleave = () => {
228
- isDrawing = false;
229
- };
230
-
231
- // 清空画布
232
- document.getElementById('clearCanvasBtn').onclick = () => {
233
- if (confirm('确定要清空画布吗?')) {
234
- ctx.clearRect(0, 0, canvas.width, canvas.height);
235
- }
236
- };
237
-
238
- // 保存白板
239
- document.getElementById('saveCanvasBtn').onclick = () => {
240
- const dataURL = canvas.toDataURL('image/png');
241
- const link = document.createElement('a');
242
- link.download = \`whiteboard-\${Date.now()}.png\`;
243
- link.href = dataURL;
244
- link.click();
245
- alert('白板已保存!');
246
- };
247
- }`;
248
-
249
- content = content.replace(chatEndPattern, chatEndReplacement);
250
-
251
- console.log('写入文件...');
252
- fs.writeFileSync(filePath, content, 'utf8');
253
-
254
- console.log('✅ 第二步完成!已在群聊中添加 AI助手 和 协作白板');
255
-
@@ -1,137 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __filename = fileURLToPath(import.meta.url);
6
- const __dirname = path.dirname(__filename);
7
-
8
- const filePath = path.join(__dirname, '../src/pages/admin-dashboard.js');
9
-
10
- console.log('读取文件...');
11
- let content = fs.readFileSync(filePath, 'utf8');
12
-
13
- // 在任务卡片中添加"查看详细"按钮
14
- console.log('添加查看详细按钮...');
15
- const taskCardPattern = /(taskCard\.innerHTML = `[\s\S]*?<button class="btn-danger btn-sm" data-id="\$\{task\._id\}" data-action="delete-task")/;
16
- const taskCardReplacement = `taskCard.innerHTML = \`
17
- <div style="display: flex; justify-content: space-between; align-items: start;">
18
- <div style="flex: 1;">
19
- <h3>\${task.title}</h3>
20
- <p>\${task.description || '无描述'}</p>
21
- <div class="task-meta">
22
- <span class="status-badge">\${getStatusText(task.status)}</span>
23
- <span>截止: \${task.deadline ? new Date(task.deadline).toLocaleDateString() : '无'}</span>
24
- </div>
25
- </div>
26
- <div style="display: flex; gap: 10px;">
27
- <button class="btn-primary btn-sm" data-id="\${task._id}" data-action="view-task" title="查看详细">📋 查看详细</button>
28
- <button class="btn-danger btn-sm" data-id="\${task._id}" data-action="delete-task"`;
29
-
30
- content = content.replace(taskCardPattern, taskCardReplacement);
31
-
32
- // 在任务列表后添加任务详情模态框
33
- console.log('添加任务详情模态框...');
34
- const taskModalPattern = /(<div id="createTaskModal" class="modal hidden">[\s\S]*?<\/div>\s*<\/div>)/;
35
- const taskModalReplacement = `$1
36
-
37
- <!-- 任务详情模态框 -->
38
- <div id="taskDetailModal" class="modal hidden">
39
- <div class="modal-content" style="max-width: 800px;">
40
- <div class="modal-header">
41
- <h3>📋 任务详情</h3>
42
- <button class="modal-close" id="closeTaskDetailModal">&times;</button>
43
- </div>
44
- <div class="modal-body" id="taskDetailContent" style="padding: 20px;">
45
- <!-- 任务详情内容 -->
46
- </div>
47
- </div>
48
- </div>`;
49
-
50
- content = content.replace(taskModalPattern, taskModalReplacement);
51
-
52
- // 在删除任务事件后添加查看详细事件
53
- console.log('添加查看详细事件...');
54
- const deleteTaskPattern = /(\/\/ 添加删除任务事件[\s\S]*?document\.querySelectorAll\('\[data-action="delete-task"\]'\)\.forEach\(btn => \{[\s\S]*?\}\);[\s\S]*?\}\);)/;
55
- const deleteTaskReplacement = `$1
56
-
57
- // 添加查看详细事件
58
- document.querySelectorAll('[data-action="view-task"]').forEach(btn => {
59
- btn.addEventListener('click', async (e) => {
60
- e.stopPropagation();
61
- const taskId = btn.dataset.id;
62
- const task = result.tasks.find(t => t._id === taskId);
63
-
64
- if (task) {
65
- const detailContent = document.getElementById('taskDetailContent');
66
- detailContent.innerHTML = \`
67
- <div class="task-detail">
68
- <div class="detail-section">
69
- <h4>📌 任务标题</h4>
70
- <p style="font-size: 18px; font-weight: 600; margin: 10px 0;">\${task.title}</p>
71
- </div>
72
-
73
- <div class="detail-section" style="margin-top: 20px;">
74
- <h4>📝 任务描述</h4>
75
- <p style="margin: 10px 0; line-height: 1.6;">\${task.description || '无描述'}</p>
76
- </div>
77
-
78
- <div class="detail-section" style="margin-top: 20px;">
79
- <h4>📊 任务状态</h4>
80
- <span class="status-badge" style="display: inline-block; margin: 10px 0; padding: 6px 12px; border-radius: 6px; background: var(--primary); color: white;">\${getStatusText(task.status)}</span>
81
- </div>
82
-
83
- <div class="detail-section" style="margin-top: 20px;">
84
- <h4>📅 截止日期</h4>
85
- <p style="margin: 10px 0;">\${task.deadline ? new Date(task.deadline).toLocaleString() : '无截止日期'}</p>
86
- </div>
87
-
88
- <div class="detail-section" style="margin-top: 20px;">
89
- <h4>👥 分配给</h4>
90
- <div style="display: flex; flex-wrap: wrap; gap: 10px; margin: 10px 0;">
91
- \${task.assignedTo && task.assignedTo.length > 0 ?
92
- task.assignedTo.map(user => \`
93
- <div style="display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--bg-secondary); border-radius: 8px;">
94
- <div class="avatar" style="width: 30px; height: 30px; font-size: 14px;">\${user.username?.[0]?.toUpperCase() || '?'}</div>
95
- <span>\${user.username || '未知用户'}</span>
96
- </div>
97
- \`).join('') :
98
- '<p>未分配</p>'
99
- }
100
- </div>
101
- </div>
102
-
103
- <div class="detail-section" style="margin-top: 20px;">
104
- <h4>🕐 创建时间</h4>
105
- <p style="margin: 10px 0;">\${new Date(task.createdAt).toLocaleString()}</p>
106
- </div>
107
-
108
- <div class="detail-section" style="margin-top: 20px;">
109
- <h4>🔄 更新时间</h4>
110
- <p style="margin: 10px 0;">\${new Date(task.updatedAt).toLocaleString()}</p>
111
- </div>
112
- </div>
113
- \`;
114
-
115
- document.getElementById('taskDetailModal').classList.remove('hidden');
116
- }
117
- });
118
- });`;
119
-
120
- content = content.replace(deleteTaskPattern, deleteTaskReplacement);
121
-
122
- // 添加关闭任务详情模态框的事件
123
- console.log('添加关闭模态框事件...');
124
- const closeTaskModalPattern = /(document\.getElementById\('closeTaskModal'\)\.addEventListener\('click', \(\) => \{[\s\S]*?document\.getElementById\('createTaskModal'\)\.classList\.add\('hidden'\);[\s\S]*?\}\);)/;
125
- const closeTaskModalReplacement = `$1
126
-
127
- document.getElementById('closeTaskDetailModal').addEventListener('click', () => {
128
- document.getElementById('taskDetailModal').classList.add('hidden');
129
- });`;
130
-
131
- content = content.replace(closeTaskModalPattern, closeTaskModalReplacement);
132
-
133
- console.log('写入文件...');
134
- fs.writeFileSync(filePath, content, 'utf8');
135
-
136
- console.log('✅ 第三步完成!已为任务管理添加查看详细功能');
137
-