collabdocchat 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "collabdocchat",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "开源的实时协作文档聊天平台 - 集成任务管理、多人文档编辑、智能点名功能",
5
5
  "main": "./server/index.js",
6
6
  "type": "module",
@@ -0,0 +1,54 @@
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
+ const content = fs.readFileSync(filePath, 'utf8');
12
+
13
+ // 检查是否有明显的语法错误
14
+ const lines = content.split('\n');
15
+ let inFunction = false;
16
+ let functionName = '';
17
+ const scopeVars = {};
18
+
19
+ lines.forEach((line, i) => {
20
+ const lineNum = i + 1;
21
+
22
+ // 检测函数开始
23
+ if (line.match(/(?:async\s+)?function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/)) {
24
+ const match = line.match(/(?:async\s+)?function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(/);
25
+ functionName = match[1] || match[2] || 'anonymous';
26
+ inFunction = true;
27
+ scopeVars[functionName] = {};
28
+ }
29
+
30
+ // 检测变量声明
31
+ const varMatch = line.match(/(?:const|let|var)\s+(\w+)\s*=/);
32
+ if (varMatch && inFunction) {
33
+ const varName = varMatch[1];
34
+ if (!scopeVars[functionName][varName]) {
35
+ scopeVars[functionName][varName] = [];
36
+ }
37
+ scopeVars[functionName][varName].push(lineNum);
38
+ }
39
+
40
+ // 检测函数结束(简单检测)
41
+ if (line.match(/^\s*}\s*$/) && inFunction) {
42
+ // 检查当前函数作用域的重复声明
43
+ for (const [varName, lineNumbers] of Object.entries(scopeVars[functionName])) {
44
+ if (lineNumbers.length > 1) {
45
+ console.log(`\n⚠️ 在函数 ${functionName} 中发现重复声明: ${varName}`);
46
+ console.log(` 出现在第 ${lineNumbers.join(', ')} 行`);
47
+ }
48
+ }
49
+ inFunction = false;
50
+ }
51
+ });
52
+
53
+ console.log('\n✅ 语法检查完成');
54
+
@@ -0,0 +1,35 @@
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
+ const content = fs.readFileSync(filePath, 'utf8');
12
+ const lines = content.split('\n');
13
+
14
+ const declarations = {};
15
+ lines.forEach((line, i) => {
16
+ const match = line.match(/(?:const|let|var)\s+(\w+)\s*=/);
17
+ if (match) {
18
+ const varName = match[1];
19
+ if (!declarations[varName]) {
20
+ declarations[varName] = [];
21
+ }
22
+ declarations[varName].push(i + 1);
23
+ }
24
+ });
25
+
26
+ console.log('\n重复声明的变量:');
27
+ for (const [varName, lineNumbers] of Object.entries(declarations)) {
28
+ if (lineNumbers.length > 1) {
29
+ console.log(`\n${varName}: 出现在第 ${lineNumbers.join(', ')} 行`);
30
+ lineNumbers.forEach(lineNum => {
31
+ console.log(` ${lineNum}: ${lines[lineNum - 1].trim()}`);
32
+ });
33
+ }
34
+ }
35
+
@@ -0,0 +1,274 @@
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 oldHelp = ` // 帮助
16
+ async function renderHelpView(container) {
17
+ container.innerHTML = \`
18
+ <div class="view-header">
19
+ <h2>❓ 帮助中心</h2>
20
+ </div>
21
+ <div class="help-container">
22
+ <div class="help-section">
23
+ <h3>📖 快速开始</h3>
24
+ <ul>
25
+ <li><a href="#" class="help-link">如何创建群组?</a></li>
26
+ <li><a href="#" class="help-link">如何邀请成员?</a></li>
27
+ <li><a href="#" class="help-link">如何创建文档?</a></li>
28
+ <li><a href="#" class="help-link">如何使用协作白板?</a></li>
29
+ </ul>
30
+ </div>
31
+
32
+ <div class="help-section">
33
+ <h3>🔧 功能说明</h3>
34
+ <ul>
35
+ <li><a href="#" class="help-link">群组管理</a></li>
36
+ <li><a href="#" class="help-link">任务管理</a></li>
37
+ <li><a href="#" class="help-link">文档协作</a></li>
38
+ <li><a href="#" class="help-link">知识库</a></li>
39
+ <li><a href="#" class="help-link">工作流引擎</a></li>
40
+ <li><a href="#" class="help-link">AI 助手</a></li>
41
+ </ul>
42
+ </div>
43
+
44
+ <div class="help-section">
45
+ <h3>❓ 常见问题</h3>
46
+ <ul>
47
+ <li><a href="#" class="help-link">如何重置密码?</a></li>
48
+ <li><a href="#" class="help-link">如何导出数据?</a></li>
49
+ <li><a href="#" class="help-link">如何备份数据?</a></li>
50
+ <li><a href="#" class="help-link">如何联系技术支持?</a></li>
51
+ </ul>
52
+ </div>
53
+
54
+ <div class="help-section">
55
+ <h3>📞 联系我们</h3>
56
+ <p>如果您有任何问题或建议,请通过以下方式联系我们:</p>
57
+ <ul>
58
+ <li>📧 邮箱: support@collabdocchat.com</li>
59
+ <li>🌐 GitHub: <a href="https://github.com/shijinghao/collabdocchat" target="_blank">github.com/shijinghao/collabdocchat</a></li>
60
+ <li>📦 npm: <a href="https://www.npmjs.com/package/collabdocchat" target="_blank">npmjs.com/package/collabdocchat</a></li>
61
+ </ul>
62
+ </div>
63
+
64
+ <div class="help-section">
65
+ <h3>ℹ️ 关于</h3>
66
+ <p><strong>CollabDocChat</strong> v2.1.5</p>
67
+ <p>开源的实时协作文档聊天平台</p>
68
+ <p>© 2026 CollabDocChat. All rights reserved.</p>
69
+ </div>
70
+ </div>
71
+ \`;
72
+ }`;
73
+
74
+ const newHelp = ` // 帮助
75
+ async function renderHelpView(container) {
76
+ container.innerHTML = \`
77
+ <div class="view-header" style="margin-bottom: 30px;">
78
+ <h2 style="display: flex; align-items: center; gap: 12px; font-size: 28px;">
79
+ <span style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">❓ 帮助中心</span>
80
+ </h2>
81
+ <p style="color: var(--text-tertiary); margin-top: 8px;">快速找到您需要的帮助和支持</p>
82
+ </div>
83
+
84
+ <div class="help-container" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 24px; max-width: 1200px;">
85
+ <!-- 快速开始卡片 -->
86
+ <div class="help-card" style="background: var(--bg-secondary); padding: 28px; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: transform 0.2s, box-shadow 0.2s;">
87
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
88
+ <div style="width: 48px; height: 48px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px;">📖</div>
89
+ <h3 style="margin: 0; font-size: 20px; font-weight: 600;">快速开始</h3>
90
+ </div>
91
+ <ul style="list-style: none; padding: 0; margin: 0;">
92
+ <li style="margin-bottom: 12px;">
93
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
94
+ <span style="color: var(--primary);">▶</span>
95
+ <span>如何创建群组?</span>
96
+ </a>
97
+ </li>
98
+ <li style="margin-bottom: 12px;">
99
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
100
+ <span style="color: var(--primary);">▶</span>
101
+ <span>如何邀请成员?</span>
102
+ </a>
103
+ </li>
104
+ <li style="margin-bottom: 12px;">
105
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
106
+ <span style="color: var(--primary);">▶</span>
107
+ <span>如何创建文档?</span>
108
+ </a>
109
+ </li>
110
+ <li>
111
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
112
+ <span style="color: var(--primary);">▶</span>
113
+ <span>如何使用协作白板?</span>
114
+ </a>
115
+ </li>
116
+ </ul>
117
+ </div>
118
+
119
+ <!-- 功能说明卡片 -->
120
+ <div class="help-card" style="background: var(--bg-secondary); padding: 28px; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: transform 0.2s, box-shadow 0.2s;">
121
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
122
+ <div style="width: 48px; height: 48px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px;">🔧</div>
123
+ <h3 style="margin: 0; font-size: 20px; font-weight: 600;">功能说明</h3>
124
+ </div>
125
+ <ul style="list-style: none; padding: 0; margin: 0;">
126
+ <li style="margin-bottom: 12px;">
127
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
128
+ <span style="color: var(--primary);">▶</span>
129
+ <span>群组管理</span>
130
+ </a>
131
+ </li>
132
+ <li style="margin-bottom: 12px;">
133
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
134
+ <span style="color: var(--primary);">▶</span>
135
+ <span>任务管理</span>
136
+ </a>
137
+ </li>
138
+ <li style="margin-bottom: 12px;">
139
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
140
+ <span style="color: var(--primary);">▶</span>
141
+ <span>文档协作</span>
142
+ </a>
143
+ </li>
144
+ <li style="margin-bottom: 12px;">
145
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
146
+ <span style="color: var(--primary);">▶</span>
147
+ <span>知识库</span>
148
+ </a>
149
+ </li>
150
+ <li style="margin-bottom: 12px;">
151
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
152
+ <span style="color: var(--primary);">▶</span>
153
+ <span>工作流引擎</span>
154
+ </a>
155
+ </li>
156
+ <li>
157
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
158
+ <span style="color: var(--primary);">▶</span>
159
+ <span>AI 智能助手</span>
160
+ </a>
161
+ </li>
162
+ </ul>
163
+ </div>
164
+
165
+ <!-- 常见问题卡片 -->
166
+ <div class="help-card" style="background: var(--bg-secondary); padding: 28px; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: transform 0.2s, box-shadow 0.2s;">
167
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
168
+ <div style="width: 48px; height: 48px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px;">❓</div>
169
+ <h3 style="margin: 0; font-size: 20px; font-weight: 600;">常见问题</h3>
170
+ </div>
171
+ <ul style="list-style: none; padding: 0; margin: 0;">
172
+ <li style="margin-bottom: 12px;">
173
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
174
+ <span style="color: var(--primary);">▶</span>
175
+ <span>如何重置密码?</span>
176
+ </a>
177
+ </li>
178
+ <li style="margin-bottom: 12px;">
179
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
180
+ <span style="color: var(--primary);">▶</span>
181
+ <span>如何导出数据?</span>
182
+ </a>
183
+ </li>
184
+ <li style="margin-bottom: 12px;">
185
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
186
+ <span style="color: var(--primary);">▶</span>
187
+ <span>如何备份数据?</span>
188
+ </a>
189
+ </li>
190
+ <li>
191
+ <a href="#" class="help-link" style="display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 8px; text-decoration: none; color: var(--text-primary); transition: all 0.2s;" onmouseenter="this.style.background='var(--bg-tertiary)'; this.style.paddingLeft='16px';" onmouseleave="this.style.background='transparent'; this.style.paddingLeft='10px';">
192
+ <span style="color: var(--primary);">▶</span>
193
+ <span>如何联系技术支持?</span>
194
+ </a>
195
+ </li>
196
+ </ul>
197
+ </div>
198
+
199
+ <!-- 联系我们卡片 -->
200
+ <div class="help-card" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 28px; border-radius: 16px; box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); transition: transform 0.2s, box-shadow 0.2s; color: white;">
201
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
202
+ <div style="width: 48px; height: 48px; background: rgba(255,255,255,0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px;">📞</div>
203
+ <h3 style="margin: 0; font-size: 20px; font-weight: 600;">联系我们</h3>
204
+ </div>
205
+ <p style="margin: 0 0 16px 0; opacity: 0.95; line-height: 1.6;">如果您有任何问题或建议,请通过以下方式联系我们:</p>
206
+ <ul style="list-style: none; padding: 0; margin: 0;">
207
+ <li style="margin-bottom: 12px; display: flex; align-items: center; gap: 10px; opacity: 0.95;">
208
+ <span>📧</span>
209
+ <span>support@collabdocchat.com</span>
210
+ </li>
211
+ <li style="margin-bottom: 12px;">
212
+ <a href="https://github.com/shijinghao/collabdocchat" target="_blank" style="display: flex; align-items: center; gap: 10px; color: white; text-decoration: none; opacity: 0.95; transition: opacity 0.2s;" onmouseenter="this.style.opacity='1'" onmouseleave="this.style.opacity='0.95'">
213
+ <span>🌐</span>
214
+ <span>GitHub</span>
215
+ </a>
216
+ </li>
217
+ <li>
218
+ <a href="https://www.npmjs.com/package/collabdocchat" target="_blank" style="display: flex; align-items: center; gap: 10px; color: white; text-decoration: none; opacity: 0.95; transition: opacity 0.2s;" onmouseenter="this.style.opacity='1'" onmouseleave="this.style.opacity='0.95'">
219
+ <span>📦</span>
220
+ <span>npm Package</span>
221
+ </a>
222
+ </li>
223
+ </ul>
224
+ </div>
225
+
226
+ <!-- 关于卡片 -->
227
+ <div class="help-card" style="background: var(--bg-secondary); padding: 28px; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: transform 0.2s, box-shadow 0.2s; grid-column: span 2;">
228
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 20px;">
229
+ <div style="width: 48px; height: 48px; background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px;">ℹ️</div>
230
+ <h3 style="margin: 0; font-size: 20px; font-weight: 600;">关于 CollabDocChat</h3>
231
+ </div>
232
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
233
+ <div>
234
+ <p style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: var(--primary);">CollabDocChat v2.3.0</p>
235
+ <p style="margin: 0 0 12px 0; color: var(--text-secondary); line-height: 1.6;">开源的实时协作文档聊天平台,提供强大的团队协作功能。</p>
236
+ <p style="margin: 0; color: var(--text-tertiary); font-size: 14px;">© 2026 CollabDocChat. All rights reserved.</p>
237
+ </div>
238
+ <div style="background: var(--bg-tertiary); padding: 20px; border-radius: 12px;">
239
+ <h4 style="margin: 0 0 12px 0; font-size: 16px;">核心特性</h4>
240
+ <ul style="margin: 0; padding-left: 20px; color: var(--text-secondary); line-height: 1.8; font-size: 14px;">
241
+ <li>实时协作编辑</li>
242
+ <li>智能 AI 助手</li>
243
+ <li>工作流自动化</li>
244
+ <li>知识库管理</li>
245
+ <li>协作白板</li>
246
+ <li>数据备份导出</li>
247
+ </ul>
248
+ </div>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ \`;
253
+
254
+ // 添加卡片悬停效果
255
+ document.querySelectorAll('.help-card').forEach(card => {
256
+ card.addEventListener('mouseenter', () => {
257
+ card.style.transform = 'translateY(-4px)';
258
+ card.style.boxShadow = '0 8px 24px rgba(0,0,0,0.12)';
259
+ });
260
+ card.addEventListener('mouseleave', () => {
261
+ card.style.transform = 'translateY(0)';
262
+ const isGradient = card.style.background.includes('gradient');
263
+ card.style.boxShadow = isGradient ? '0 4px 12px rgba(102, 126, 234, 0.3)' : '0 2px 8px rgba(0,0,0,0.05)';
264
+ });
265
+ });
266
+ }`;
267
+
268
+ content = content.replace(oldHelp, newHelp);
269
+
270
+ console.log('写入文件...');
271
+ fs.writeFileSync(filePath, content, 'utf8');
272
+
273
+ console.log('✅ 帮助页面已美化!');
274
+
@@ -0,0 +1,73 @@
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. 修复知识库的 forEach 错误
14
+ console.log('修复知识库错误...');
15
+ const knowledgeFixPattern = /(const knowledgeItems = result\.data \|\| \[\];)/;
16
+ const knowledgeFixReplacement = `const knowledgeItems = Array.isArray(result.data) ? result.data : (result.data?.items || []);`;
17
+
18
+ content = content.replace(knowledgeFixPattern, knowledgeFixReplacement);
19
+
20
+ // 2. 在白板模态框中添加"发送到群聊"按钮
21
+ console.log('添加白板发送到群聊功能...');
22
+ const whiteboardHeaderPattern = /(<button class="btn-primary" id="saveCanvasBtn">保存白板<\/button>)/;
23
+ const whiteboardHeaderReplacement = `$1
24
+ <button class="btn-success" id="sendToGroupBtn" style="background: var(--success); color: white;">📤 发送到群聊</button>`;
25
+
26
+ content = content.replace(whiteboardHeaderPattern, whiteboardHeaderReplacement);
27
+
28
+ // 3. 在白板保存按钮事件后添加发送到群聊事件
29
+ console.log('添加白板发送事件...');
30
+ const whiteboardSavePattern = /(document\.getElementById\('saveCanvasBtn'\)\.onclick = \(\) => \{[\s\S]*?alert\('白板已保存!'\);[\s\S]*?\};)/;
31
+ const whiteboardSaveReplacement = `$1
32
+
33
+ // 发送到群聊
34
+ document.getElementById('sendToGroupBtn').onclick = async () => {
35
+ try {
36
+ const dataURL = canvas.toDataURL('image/png');
37
+ const blob = await fetch(dataURL).then(r => r.blob());
38
+
39
+ // 创建 FormData 上传图片
40
+ const formData = new FormData();
41
+ formData.append('file', blob, \`whiteboard-\${Date.now()}.png\`);
42
+ formData.append('groupId', currentGroup._id);
43
+ formData.append('description', '协作白板作品');
44
+
45
+ const token = localStorage.getItem('token');
46
+ const response = await fetch('http://localhost:3000/api/files/upload', {
47
+ method: 'POST',
48
+ headers: {
49
+ 'Authorization': \`Bearer \${token}\`
50
+ },
51
+ body: formData
52
+ });
53
+
54
+ if (response.ok) {
55
+ // 发送消息到群聊
56
+ wsService.sendChatMessage(currentGroup._id, user.username, '[白板作品] 分享了一个白板作品');
57
+ alert('白板作品已发送到群聊!');
58
+ document.getElementById('whiteboardModal').classList.add('hidden');
59
+ } else {
60
+ throw new Error('上传失败');
61
+ }
62
+ } catch (error) {
63
+ alert('发送失败: ' + error.message);
64
+ }
65
+ };`;
66
+
67
+ content = content.replace(whiteboardSavePattern, whiteboardSaveReplacement);
68
+
69
+ console.log('写入文件...');
70
+ fs.writeFileSync(filePath, content, 'utf8');
71
+
72
+ console.log('✅ 第一批修复完成!');
73
+
@@ -0,0 +1,93 @@
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 auditDetailPattern = /(window\.showAuditDetail = async \(logId\) => \{[\s\S]*?content\.innerHTML = `[\s\S]*?<p>详细信息加载中\.\.\.<\/p>[\s\S]*?`;[\s\S]*?modal\.classList\.remove\('hidden'\);[\s\S]*?\} catch \(error\) \{[\s\S]*?\}[\s\S]*?\};)/;
16
+ const auditDetailReplacement = `window.showAuditDetail = async (logId) => {
17
+ try {
18
+ const token = localStorage.getItem('token');
19
+ const response = await fetch(\`http://localhost:3000/api/audit/\${logId}\`, {
20
+ headers: { 'Authorization': \`Bearer \${token}\` }
21
+ });
22
+ const result = await response.json();
23
+ const log = result.log;
24
+
25
+ const modal = document.getElementById('auditDetailModal');
26
+ const content = document.getElementById('auditDetailContent');
27
+
28
+ content.innerHTML = \`
29
+ <div class="audit-detail" style="padding: 20px;">
30
+ <div class="detail-section" style="margin-bottom: 20px; padding: 15px; background: var(--bg); border-radius: 8px;">
31
+ <h4 style="margin: 0 0 10px 0; color: var(--text-secondary);">📋 操作信息</h4>
32
+ <div style="display: grid; grid-template-columns: 120px 1fr; gap: 10px; font-size: 14px;">
33
+ <span style="color: var(--text-tertiary);">操作类型:</span>
34
+ <span style="font-weight: 600;">\${getActionText(log.action)}</span>
35
+ <span style="color: var(--text-tertiary);">操作时间:</span>
36
+ <span>\${new Date(log.createdAt).toLocaleString()}</span>
37
+ <span style="color: var(--text-tertiary);">操作用户:</span>
38
+ <span>\${log.user?.username || '未知用户'}</span>
39
+ </div>
40
+ </div>
41
+
42
+ <div class="detail-section" style="margin-bottom: 20px; padding: 15px; background: var(--bg); border-radius: 8px;">
43
+ <h4 style="margin: 0 0 10px 0; color: var(--text-secondary);">📄 资源信息</h4>
44
+ <div style="display: grid; grid-template-columns: 120px 1fr; gap: 10px; font-size: 14px;">
45
+ <span style="color: var(--text-tertiary);">资源类型:</span>
46
+ <span>\${log.resourceType || '未知'}</span>
47
+ <span style="color: var(--text-tertiary);">资源ID:</span>
48
+ <span style="font-family: monospace; font-size: 12px;">\${log.resourceId}</span>
49
+ <span style="color: var(--text-tertiary);">资源标题:</span>
50
+ <span>\${log.resourceTitle || '无'}</span>
51
+ </div>
52
+ </div>
53
+
54
+ \${log.details ? \`
55
+ <div class="detail-section" style="margin-bottom: 20px; padding: 15px; background: var(--bg); border-radius: 8px;">
56
+ <h4 style="margin: 0 0 10px 0; color: var(--text-secondary);">📝 详细信息</h4>
57
+ <div style="font-size: 14px; line-height: 1.6;">
58
+ \${log.details.description || '无详细描述'}
59
+ </div>
60
+ \${log.details.changes ? \`
61
+ <div style="margin-top: 15px;">
62
+ <h5 style="margin: 0 0 10px 0; font-size: 13px; color: var(--text-tertiary);">变更内容:</h5>
63
+ <pre style="background: var(--bg-tertiary); padding: 10px; border-radius: 6px; overflow-x: auto; font-size: 12px;">\${JSON.stringify(log.details.changes, null, 2)}</pre>
64
+ </div>
65
+ \` : ''}
66
+ </div>
67
+ \` : ''}
68
+
69
+ <div class="detail-section" style="padding: 15px; background: var(--bg); border-radius: 8px;">
70
+ <h4 style="margin: 0 0 10px 0; color: var(--text-secondary);">🌐 请求信息</h4>
71
+ <div style="display: grid; grid-template-columns: 120px 1fr; gap: 10px; font-size: 14px;">
72
+ <span style="color: var(--text-tertiary);">IP地址:</span>
73
+ <span style="font-family: monospace;">\${log.ipAddress || '未记录'}</span>
74
+ <span style="color: var(--text-tertiary);">用户代理:</span>
75
+ <span style="font-size: 12px; word-break: break-all;">\${log.userAgent || '未记录'}</span>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ \`;
80
+
81
+ modal.classList.remove('hidden');
82
+ } catch (error) {
83
+ alert('加载详情失败: ' + error.message);
84
+ }
85
+ };`;
86
+
87
+ content = content.replace(auditDetailPattern, auditDetailReplacement);
88
+
89
+ console.log('写入文件...');
90
+ fs.writeFileSync(filePath, content, 'utf8');
91
+
92
+ console.log('✅ 第二批修复完成!');
93
+