collabdocchat 2.3.0 → 2.4.0

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.0",
4
4
  "description": "开源的实时协作文档聊天平台 - 集成任务管理、多人文档编辑、智能点名功能",
5
5
  "main": "./server/index.js",
6
6
  "type": "module",
@@ -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
+
@@ -0,0 +1,155 @@
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 aiModalPattern = /(<!-- AI助手模态框 -->[\s\S]*?<div id="aiModal" class="modal hidden">[\s\S]*?<\/div>[\s\S]*?<\/div>[\s\S]*?<\/div>)/;
16
+ const aiModalReplacement = `<!-- AI助手模态框 -->
17
+ <div id="aiModal" class="modal hidden">
18
+ <div class="modal-content" style="max-width: 900px; height: 85vh; display: flex; flex-direction: column;">
19
+ <div class="modal-header" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px 12px 0 0;">
20
+ <div style="display: flex; align-items: center; justify-content: space-between;">
21
+ <div style="display: flex; align-items: center; gap: 15px;">
22
+ <div style="width: 50px; height: 50px; background: rgba(255,255,255,0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 28px;">🤖</div>
23
+ <div>
24
+ <h3 style="margin: 0; font-size: 22px;">AI 智能助手</h3>
25
+ <p style="margin: 5px 0 0 0; font-size: 13px; opacity: 0.9;">为您提供智能问答和协助服务</p>
26
+ </div>
27
+ </div>
28
+ <button class="modal-close" id="closeAIModal" style="background: rgba(255,255,255,0.2); border: none; color: white; width: 36px; height: 36px; border-radius: 8px; cursor: pointer; font-size: 20px;">&times;</button>
29
+ </div>
30
+ </div>
31
+
32
+ <div style="flex: 1; display: flex; flex-direction: column; overflow: hidden;">
33
+ <!-- 快捷问题 -->
34
+ <div style="padding: 15px; background: var(--bg-secondary); border-bottom: 1px solid var(--border);">
35
+ <div style="font-size: 12px; color: var(--text-tertiary); margin-bottom: 10px;">💡 快捷问题</div>
36
+ <div style="display: flex; gap: 8px; flex-wrap: wrap;">
37
+ <button class="quick-question-btn" data-question="如何创建一个新文档?" style="padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 16px; font-size: 12px; cursor: pointer; transition: all 0.2s;">📄 如何创建文档?</button>
38
+ <button class="quick-question-btn" data-question="如何邀请成员加入群组?" style="padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 16px; font-size: 12px; cursor: pointer; transition: all 0.2s;">👥 如何邀请成员?</button>
39
+ <button class="quick-question-btn" data-question="如何使用工作流功能?" style="padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 16px; font-size: 12px; cursor: pointer; transition: all 0.2s;">⚙️ 工作流使用?</button>
40
+ <button class="quick-question-btn" data-question="如何备份数据?" style="padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 16px; font-size: 12px; cursor: pointer; transition: all 0.2s;">💾 如何备份?</button>
41
+ </div>
42
+ </div>
43
+
44
+ <!-- 聊天区域 -->
45
+ <div class="ai-chat" id="aiChatMessages" style="flex: 1; overflow-y: auto; padding: 20px; background: var(--bg);">
46
+ <div class="ai-message ai" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px 18px; border-radius: 18px 18px 18px 4px; margin: 10px 0; max-width: 80%; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);">
47
+ <div style="display: flex; align-items: start; gap: 12px;">
48
+ <div style="font-size: 24px;">🤖</div>
49
+ <div>
50
+ <p style="margin: 0 0 8px 0; font-weight: 600;">你好!我是AI智能助手</p>
51
+ <p style="margin: 0; opacity: 0.95; line-height: 1.6;">我可以帮助你:</p>
52
+ <ul style="margin: 8px 0 0 0; padding-left: 20px; opacity: 0.95; line-height: 1.8;">
53
+ <li>解答关于平台功能的问题</li>
54
+ <li>提供操作指导和建议</li>
55
+ <li>帮助你更好地使用各项功能</li>
56
+ </ul>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ <!-- 输入区域 -->
63
+ <div class="ai-input-container" style="padding: 20px; border-top: 1px solid var(--border); background: var(--bg-secondary);">
64
+ <div style="display: flex; gap: 12px; align-items: end;">
65
+ <textarea id="aiInputText" placeholder="输入你的问题..." rows="1" style="flex: 1; padding: 12px 16px; border: 2px solid var(--border); border-radius: 12px; resize: none; font-size: 14px; transition: border-color 0.2s; max-height: 120px;"></textarea>
66
+ <button class="btn-primary" id="aiSendBtnModal" style="padding: 12px 24px; border-radius: 12px; font-size: 15px; font-weight: 600; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; cursor: pointer; transition: transform 0.2s;">
67
+ <span style="display: flex; align-items: center; gap: 6px;">
68
+ <span>发送</span>
69
+ <span>🚀</span>
70
+ </span>
71
+ </button>
72
+ </div>
73
+ <div style="margin-top: 10px; font-size: 11px; color: var(--text-tertiary); text-align: center;">
74
+ 💡 提示:按 Enter 发送,Shift + Enter 换行
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>`;
80
+
81
+ content = content.replace(aiModalPattern, aiModalReplacement);
82
+
83
+ // 更新AI发送按钮事件,添加快捷问题功能
84
+ console.log('添加AI快捷问题功能...');
85
+ const aiSendPattern = /(document\.getElementById\('aiSendBtnModal'\)\.addEventListener\('click', async \(\) => \{)/;
86
+ const aiSendReplacement = `// 快捷问题按钮
87
+ document.querySelectorAll('.quick-question-btn').forEach(btn => {
88
+ btn.addEventListener('click', () => {
89
+ document.getElementById('aiInputText').value = btn.dataset.question;
90
+ document.getElementById('aiSendBtnModal').click();
91
+ });
92
+ btn.addEventListener('mouseenter', (e) => {
93
+ e.target.style.background = 'var(--primary)';
94
+ e.target.style.color = 'white';
95
+ e.target.style.transform = 'translateY(-2px)';
96
+ });
97
+ btn.addEventListener('mouseleave', (e) => {
98
+ e.target.style.background = 'var(--bg)';
99
+ e.target.style.color = 'inherit';
100
+ e.target.style.transform = 'translateY(0)';
101
+ });
102
+ });
103
+
104
+ // AI输入框自动调整高度
105
+ const aiInput = document.getElementById('aiInputText');
106
+ aiInput.addEventListener('input', () => {
107
+ aiInput.style.height = 'auto';
108
+ aiInput.style.height = aiInput.scrollHeight + 'px';
109
+ });
110
+
111
+ // 支持 Enter 发送,Shift+Enter 换行
112
+ aiInput.addEventListener('keydown', (e) => {
113
+ if (e.key === 'Enter' && !e.shiftKey) {
114
+ e.preventDefault();
115
+ document.getElementById('aiSendBtnModal').click();
116
+ }
117
+ });
118
+
119
+ // 输入框聚焦效果
120
+ aiInput.addEventListener('focus', () => {
121
+ aiInput.style.borderColor = 'var(--primary)';
122
+ });
123
+ aiInput.addEventListener('blur', () => {
124
+ aiInput.style.borderColor = 'var(--border)';
125
+ });
126
+
127
+ // 发送按钮悬停效果
128
+ const sendBtn = document.getElementById('aiSendBtnModal');
129
+ sendBtn.addEventListener('mouseenter', () => {
130
+ sendBtn.style.transform = 'scale(1.05)';
131
+ });
132
+ sendBtn.addEventListener('mouseleave', () => {
133
+ sendBtn.style.transform = 'scale(1)';
134
+ });
135
+
136
+ $1`;
137
+
138
+ content = content.replace(aiSendPattern, aiSendReplacement);
139
+
140
+ // 美化AI消息样式
141
+ const aiMessagePattern = /(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;';)/;
142
+ const aiMessageReplacement = `userMsg.style.cssText = 'background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 18px; border-radius: 18px 18px 4px 18px; margin: 10px 0; max-width: 75%; margin-left: auto; text-align: right; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); animation: slideInRight 0.3s ease;';`;
143
+
144
+ content = content.replace(aiMessagePattern, aiMessageReplacement);
145
+
146
+ const aiResponsePattern = /(aiMsg\.style\.cssText = 'background: var\(--bg-tertiary\); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;';)/;
147
+ const aiResponseReplacement = `aiMsg.style.cssText = 'background: var(--bg-secondary); padding: 15px 18px; border-radius: 18px 18px 18px 4px; margin: 10px 0; max-width: 75%; border: 1px solid var(--border); box-shadow: 0 2px 4px rgba(0,0,0,0.05); animation: slideInLeft 0.3s ease; line-height: 1.6;';`;
148
+
149
+ content = content.replace(aiResponsePattern, aiResponseReplacement);
150
+
151
+ console.log('写入文件...');
152
+ fs.writeFileSync(filePath, content, 'utf8');
153
+
154
+ console.log('✅ 第三批修复完成!AI界面已美化');
155
+