collabdocchat 2.4.3 → 2.4.5
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 +2 -2
- package/scripts/add-button-hover.js +58 -0
- package/scripts/add-missing-braces.js +27 -0
- package/scripts/add-missing-functions.js +2 -0
- package/scripts/add-more-features.js +2 -0
- package/scripts/add-user-functions.js +2 -0
- package/scripts/auto-publish.js +2 -0
- package/scripts/beautify-buttons.js +47 -0
- package/scripts/beautify-ui.js +269 -0
- package/scripts/check-brackets.js +50 -0
- package/scripts/check-encoding.js +2 -0
- package/scripts/check-syntax.js +2 -0
- package/scripts/delete-orphan-block.js +27 -0
- package/scripts/find-buttons.js +22 -0
- package/scripts/find-duplicate.js +2 -0
- package/scripts/find-extra-brace.js +63 -0
- package/scripts/find-sidebar-buttons.js +23 -0
- package/scripts/fix-file-end.js +46 -0
- package/scripts/fix-help.js +2 -0
- package/scripts/fix-issues-step1.js +2 -0
- package/scripts/fix-issues-step2.js +2 -0
- package/scripts/fix-issues-step3.js +2 -0
- package/scripts/fix-issues-step4.js +2 -0
- package/scripts/fix-optimized-views.js +2 -0
- package/scripts/fix-settings.js +2 -0
- package/scripts/fix-syntax-error.js +38 -0
- package/scripts/fix-workflow.js +2 -0
- package/scripts/refactor-step1.js +2 -0
- package/scripts/refactor-step2.js +2 -0
- package/scripts/refactor-step3.js +2 -0
- package/scripts/refactor-step4.js +2 -0
- package/scripts/refactor-step5.js +2 -0
- package/scripts/refactor-step6.js +2 -0
- package/scripts/refactor-step7.js +2 -0
- package/scripts/remove-orphan-code.js +57 -0
- package/scripts/update-port-user.js +2 -0
- package/scripts/update-port.js +2 -0
- package/server/index.js +4 -0
- package/server/index.js.bak +97 -0
- package/server/models/Document.js +5 -0
- package/server/models/KnowledgeBase.js +259 -254
- package/server/models/Poll.js +97 -0
- package/server/routes/ai.js +391 -327
- package/server/routes/audit.js +61 -0
- package/server/routes/documents.js +74 -5
- package/server/routes/export.js +171 -10
- package/server/routes/files.js +27 -4
- package/server/routes/knowledge.js +31 -22
- package/server/routes/messages.js +142 -0
- package/server/routes/polls.js +241 -0
- package/server/routes/tasks.js +1 -0
- package/server/routes/workflows.js +27 -0
- package/server/utils/auditLogger.js +268 -238
- package/src/pages/admin-dashboard.js +1395 -261
- package/src/pages/admin-dashboard.js.audit-optimize.bak +4134 -0
- package/src/pages/admin-dashboard.js.bak +4041 -0
- package/src/pages/admin-dashboard.js.broken.bak +4099 -0
- package/src/pages/admin-dashboard.js.comprehensive.bak +4099 -0
- package/src/pages/admin-dashboard.js.escape.bak +4099 -0
- package/src/pages/admin-dashboard.js.final-final-fix.bak +4099 -0
- package/src/pages/admin-dashboard.js.final-fix.bak +4099 -0
- package/src/pages/admin-dashboard.js.final.bak +4099 -0
- package/src/pages/admin-dashboard.js.indent-fix.bak +4099 -0
- package/src/pages/admin-dashboard.js.last-fix.bak +4099 -0
- package/src/pages/admin-dashboard.js.line595-fix.bak +4099 -0
- package/src/pages/admin-dashboard.js.pre-manual-fix.bak +4099 -0
- package/src/pages/admin-dashboard.js.syntax.bak +4099 -0
- package/src/pages/admin-dashboard.js.test.bak +4099 -0
- package/src/pages/optimized-task-detail-original.js +838 -0
- package/src/pages/optimized-task-detail.js +324 -22
- package/src/pages/optimized-task-detail.js.bak +1162 -0
- package/src/pages/poll-detail-enhanced.js +394 -0
- package/src/pages/update-poll-display.js +380 -0
- package/src/pages/user-dashboard.js +1860 -1006
- package/src/services/api.js +326 -265
- package/src/services/auth.js +54 -54
- package/src/services/websocket.js +88 -80
- package/src/pages/simplified-workflows.js +0 -652
- package/src/utils/ai-assistant.js +0 -1384
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "collabdocchat",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.5",
|
|
4
4
|
"description": "开源的实时协作文档聊天平台 - 集成任务管理、多人文档编辑、智能点名功能",
|
|
5
5
|
"main": "./server/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -91,4 +91,4 @@
|
|
|
91
91
|
"open": "^11.0.0",
|
|
92
92
|
"vite": "^5.0.8"
|
|
93
93
|
}
|
|
94
|
-
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
const settingsBtnPattern = /document\.getElementById\('settingsBtn'\)\.addEventListener\('click', \(\) => \{/;
|
|
15
|
+
|
|
16
|
+
if (settingsBtnPattern.test(content)) {
|
|
17
|
+
// 在设置按钮点击事件之前添加悬停效果
|
|
18
|
+
const hoverEffects = `
|
|
19
|
+
// 设置和帮助按钮悬停效果
|
|
20
|
+
const settingsBtn = document.getElementById('settingsBtn');
|
|
21
|
+
const helpBtn = document.getElementById('helpBtn');
|
|
22
|
+
|
|
23
|
+
settingsBtn.addEventListener('mouseenter', () => {
|
|
24
|
+
settingsBtn.style.transform = 'translateY(-2px)';
|
|
25
|
+
settingsBtn.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.5)';
|
|
26
|
+
});
|
|
27
|
+
settingsBtn.addEventListener('mouseleave', () => {
|
|
28
|
+
settingsBtn.style.transform = 'translateY(0)';
|
|
29
|
+
settingsBtn.style.boxShadow = '0 2px 8px rgba(102, 126, 234, 0.3)';
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
helpBtn.addEventListener('mouseenter', () => {
|
|
33
|
+
helpBtn.style.transform = 'translateY(-2px)';
|
|
34
|
+
helpBtn.style.boxShadow = '0 4px 12px rgba(240, 147, 251, 0.5)';
|
|
35
|
+
});
|
|
36
|
+
helpBtn.addEventListener('mouseleave', () => {
|
|
37
|
+
helpBtn.style.transform = 'translateY(0)';
|
|
38
|
+
helpBtn.style.boxShadow = '0 2px 8px rgba(240, 147, 251, 0.3)';
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
content = content.replace(
|
|
44
|
+
settingsBtnPattern,
|
|
45
|
+
hoverEffects + "document.getElementById('settingsBtn').addEventListener('click', () => {"
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
console.log('✅ 悬停效果已添加');
|
|
49
|
+
} else {
|
|
50
|
+
console.log('⚠️ 未找到设置按钮点击事件');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
54
|
+
|
|
55
|
+
console.log('\n✅ 完成!按钮现在有悬停动画效果');
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
content = content.trimEnd();
|
|
15
|
+
if (!content.endsWith('}')) {
|
|
16
|
+
content += '\n}\n';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 再添加一个
|
|
20
|
+
content += '\n';
|
|
21
|
+
|
|
22
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
23
|
+
|
|
24
|
+
console.log('✅ 已添加缺失的闭合括号');
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
package/scripts/auto-publish.js
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
const oldButtonsSection = ` <div class="sidebar-footer">
|
|
15
|
+
<button class="sidebar-footer-btn" id="settingsBtn">
|
|
16
|
+
<span class="icon">⚙️</span> 设置
|
|
17
|
+
</button>
|
|
18
|
+
<button class="sidebar-footer-btn" id="helpBtn">
|
|
19
|
+
<span class="icon">❓</span> 帮助
|
|
20
|
+
</button>
|
|
21
|
+
</div>`;
|
|
22
|
+
|
|
23
|
+
const newButtonsSection = ` <div class="sidebar-footer" style="display: flex; gap: 8px; padding: 0 10px;">
|
|
24
|
+
<button class="sidebar-footer-btn" id="settingsBtn" style="flex: 1; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 12px; border-radius: 10px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); display: flex; align-items: center; justify-content: center; gap: 6px;">
|
|
25
|
+
<span class="icon" style="font-size: 18px;">⚙️</span>
|
|
26
|
+
<span>设置</span>
|
|
27
|
+
</button>
|
|
28
|
+
<button class="sidebar-footer-btn" id="helpBtn" style="flex: 1; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border: none; padding: 12px; border-radius: 10px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(240, 147, 251, 0.3); display: flex; align-items: center; justify-content: center; gap: 6px;">
|
|
29
|
+
<span class="icon" style="font-size: 18px;">❓</span>
|
|
30
|
+
<span>帮助</span>
|
|
31
|
+
</button>
|
|
32
|
+
</div>`;
|
|
33
|
+
|
|
34
|
+
content = content.replace(oldButtonsSection, newButtonsSection);
|
|
35
|
+
console.log('✅ 设置和帮助按钮已美化');
|
|
36
|
+
|
|
37
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
38
|
+
|
|
39
|
+
console.log('\n✅ 美化完成!');
|
|
40
|
+
console.log('\n变更内容:');
|
|
41
|
+
console.log('1. 设置按钮:紫色渐变背景 + 白色文字 + 阴影');
|
|
42
|
+
console.log('2. 帮助按钮:粉色渐变背景 + 白色文字 + 阴影');
|
|
43
|
+
console.log('3. 按钮并排显示,各占50%宽度');
|
|
44
|
+
console.log('4. 图标和文字居中对齐');
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
@@ -0,0 +1,269 @@
|
|
|
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('美化设置和帮助按钮,优化AI助手界面...');
|
|
11
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
12
|
+
|
|
13
|
+
// 1. 查找并替换设置和帮助按钮的样式
|
|
14
|
+
const oldButtons = ` <button class="nav-btn" id="settingsBtn">⚙️ 设置</button>
|
|
15
|
+
<button class="nav-btn" id="helpBtn">❓ 帮助</button>`;
|
|
16
|
+
|
|
17
|
+
const newButtons = ` <button class="nav-btn" id="settingsBtn" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);">⚙️ 设置</button>
|
|
18
|
+
<button class="nav-btn" id="helpBtn" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(240, 147, 251, 0.3); margin-left: 10px;">❓ 帮助</button>`;
|
|
19
|
+
|
|
20
|
+
if (content.includes(oldButtons)) {
|
|
21
|
+
content = content.replace(oldButtons, newButtons);
|
|
22
|
+
console.log('✅ 设置和帮助按钮样式已更新');
|
|
23
|
+
} else {
|
|
24
|
+
console.log('⚠️ 未找到设置和帮助按钮,尝试其他匹配方式...');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 2. 删除AI助手模态框底部的输入框和提示
|
|
28
|
+
const oldAIInput = ` <!-- 输入区域 -->
|
|
29
|
+
<div class="ai-input-container" style="padding: 20px; border-top: 1px solid var(--border); background: var(--bg-secondary);">
|
|
30
|
+
<div style="display: flex; gap: 12px; align-items: end;">
|
|
31
|
+
<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>
|
|
32
|
+
<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;">
|
|
33
|
+
<span style="display: flex; align-items: center; gap: 6px;">
|
|
34
|
+
<span>发送</span>
|
|
35
|
+
<span>🚀</span>
|
|
36
|
+
</span>
|
|
37
|
+
</button>
|
|
38
|
+
</div>
|
|
39
|
+
<div style="margin-top: 10px; font-size: 11px; color: var(--text-tertiary); text-align: center;">
|
|
40
|
+
💡 提示:按 Enter 发送,Shift + Enter 换行
|
|
41
|
+
</div>
|
|
42
|
+
</div>`;
|
|
43
|
+
|
|
44
|
+
const newAIInput = ` <!-- 输入区域已移除,使用快捷问题按钮 -->`;
|
|
45
|
+
|
|
46
|
+
content = content.replace(oldAIInput, newAIInput);
|
|
47
|
+
console.log('✅ AI助手输入框已删除');
|
|
48
|
+
|
|
49
|
+
// 3. 优化AI助手的快捷问题按钮样式
|
|
50
|
+
const oldQuickButtons = ` <div style="display: flex; gap: 8px; flex-wrap: wrap;">
|
|
51
|
+
<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>
|
|
52
|
+
<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>
|
|
53
|
+
<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>
|
|
54
|
+
<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>
|
|
55
|
+
</div>`;
|
|
56
|
+
|
|
57
|
+
const newQuickButtons = ` <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;">
|
|
58
|
+
<button class="quick-question-btn" data-question="如何创建一个新文档?" style="padding: 12px 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); display: flex; align-items: center; gap: 8px;">
|
|
59
|
+
<span style="font-size: 20px;">📄</span>
|
|
60
|
+
<span>如何创建文档?</span>
|
|
61
|
+
</button>
|
|
62
|
+
<button class="quick-question-btn" data-question="如何邀请成员加入群组?" style="padding: 12px 16px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(240, 147, 251, 0.3); display: flex; align-items: center; gap: 8px;">
|
|
63
|
+
<span style="font-size: 20px;">👥</span>
|
|
64
|
+
<span>如何邀请成员?</span>
|
|
65
|
+
</button>
|
|
66
|
+
<button class="quick-question-btn" data-question="如何使用工作流功能?" style="padding: 12px 16px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: white; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(79, 172, 254, 0.3); display: flex; align-items: center; gap: 8px;">
|
|
67
|
+
<span style="font-size: 20px;">⚙️</span>
|
|
68
|
+
<span>工作流使用?</span>
|
|
69
|
+
</button>
|
|
70
|
+
<button class="quick-question-btn" data-question="如何备份数据?" style="padding: 12px 16px; background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: white; border: none; border-radius: 12px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.3s; box-shadow: 0 2px 8px rgba(250, 112, 154, 0.3); display: flex; align-items: center; gap: 8px;">
|
|
71
|
+
<span style="font-size: 20px;">💾</span>
|
|
72
|
+
<span>如何备份?</span>
|
|
73
|
+
</button>
|
|
74
|
+
</div>`;
|
|
75
|
+
|
|
76
|
+
content = content.replace(oldQuickButtons, newQuickButtons);
|
|
77
|
+
console.log('✅ 快捷问题按钮已美化');
|
|
78
|
+
|
|
79
|
+
// 4. 更新快捷问题按钮的事件处理,移除输入框相关代码
|
|
80
|
+
const oldQuickBtnHandler = ` // 快捷问题按钮
|
|
81
|
+
document.querySelectorAll('.quick-question-btn').forEach(btn => {
|
|
82
|
+
btn.addEventListener('click', () => {
|
|
83
|
+
document.getElementById('aiInputText').value = btn.dataset.question;
|
|
84
|
+
document.getElementById('aiSendBtnModal').click();
|
|
85
|
+
});
|
|
86
|
+
btn.addEventListener('mouseenter', (e) => {
|
|
87
|
+
e.target.style.background = 'var(--primary)';
|
|
88
|
+
e.target.style.color = 'white';
|
|
89
|
+
e.target.style.transform = 'translateY(-2px)';
|
|
90
|
+
});
|
|
91
|
+
btn.addEventListener('mouseleave', (e) => {
|
|
92
|
+
e.target.style.background = 'var(--bg)';
|
|
93
|
+
e.target.style.color = 'inherit';
|
|
94
|
+
e.target.style.transform = 'translateY(0)';
|
|
95
|
+
});
|
|
96
|
+
});`;
|
|
97
|
+
|
|
98
|
+
const newQuickBtnHandler = ` // 快捷问题按钮 - 直接发送问题
|
|
99
|
+
document.querySelectorAll('.quick-question-btn').forEach(btn => {
|
|
100
|
+
btn.addEventListener('click', async () => {
|
|
101
|
+
const question = btn.dataset.question;
|
|
102
|
+
const chatMessages = document.getElementById('aiChatMessages');
|
|
103
|
+
|
|
104
|
+
// 显示用户问题
|
|
105
|
+
const userMsg = document.createElement('div');
|
|
106
|
+
userMsg.className = 'ai-message user';
|
|
107
|
+
userMsg.textContent = question;
|
|
108
|
+
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;';
|
|
109
|
+
chatMessages.appendChild(userMsg);
|
|
110
|
+
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
111
|
+
|
|
112
|
+
// 发送到AI
|
|
113
|
+
try {
|
|
114
|
+
const token = localStorage.getItem('token');
|
|
115
|
+
const response = await fetch('http://localhost:8765/api/ai/ask', {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/json',
|
|
119
|
+
'Authorization': \`Bearer \${token}\`
|
|
120
|
+
},
|
|
121
|
+
body: JSON.stringify({ question })
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const data = await response.json();
|
|
125
|
+
|
|
126
|
+
// 显示AI回复
|
|
127
|
+
const aiMsg = document.createElement('div');
|
|
128
|
+
aiMsg.className = 'ai-message ai';
|
|
129
|
+
aiMsg.textContent = data.answer || '抱歉,我现在无法回答这个问题。';
|
|
130
|
+
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;';
|
|
131
|
+
chatMessages.appendChild(aiMsg);
|
|
132
|
+
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
const errorMsg = document.createElement('div');
|
|
135
|
+
errorMsg.className = 'ai-message ai';
|
|
136
|
+
errorMsg.textContent = '抱歉,发生了错误:' + error.message;
|
|
137
|
+
errorMsg.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;';
|
|
138
|
+
chatMessages.appendChild(errorMsg);
|
|
139
|
+
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// 悬停效果
|
|
144
|
+
btn.addEventListener('mouseenter', (e) => {
|
|
145
|
+
e.target.style.transform = 'translateY(-3px) scale(1.02)';
|
|
146
|
+
e.target.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
|
|
147
|
+
});
|
|
148
|
+
btn.addEventListener('mouseleave', (e) => {
|
|
149
|
+
e.target.style.transform = 'translateY(0) scale(1)';
|
|
150
|
+
const gradient = e.target.style.background;
|
|
151
|
+
if (gradient.includes('667eea')) {
|
|
152
|
+
e.target.style.boxShadow = '0 2px 8px rgba(102, 126, 234, 0.3)';
|
|
153
|
+
} else if (gradient.includes('f093fb')) {
|
|
154
|
+
e.target.style.boxShadow = '0 2px 8px rgba(240, 147, 251, 0.3)';
|
|
155
|
+
} else if (gradient.includes('4facfe')) {
|
|
156
|
+
e.target.style.boxShadow = '0 2px 8px rgba(79, 172, 254, 0.3)';
|
|
157
|
+
} else {
|
|
158
|
+
e.target.style.boxShadow = '0 2px 8px rgba(250, 112, 154, 0.3)';
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});`;
|
|
162
|
+
|
|
163
|
+
content = content.replace(oldQuickBtnHandler, newQuickBtnHandler);
|
|
164
|
+
console.log('✅ 快捷问题按钮事件已更新');
|
|
165
|
+
|
|
166
|
+
// 5. 删除不再需要的输入框相关代码
|
|
167
|
+
const inputRelatedCode = [
|
|
168
|
+
` // AI输入框自动调整高度
|
|
169
|
+
const aiInput = document.getElementById('aiInputText');
|
|
170
|
+
aiInput.addEventListener('input', () => {
|
|
171
|
+
aiInput.style.height = 'auto';
|
|
172
|
+
aiInput.style.height = aiInput.scrollHeight + 'px';
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// 支持 Enter 发送,Shift+Enter 换行
|
|
176
|
+
aiInput.addEventListener('keydown', (e) => {
|
|
177
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
document.getElementById('aiSendBtnModal').click();
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// 输入框聚焦效果
|
|
184
|
+
aiInput.addEventListener('focus', () => {
|
|
185
|
+
aiInput.style.borderColor = 'var(--primary)';
|
|
186
|
+
});
|
|
187
|
+
aiInput.addEventListener('blur', () => {
|
|
188
|
+
aiInput.style.borderColor = 'var(--border)';
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// 发送按钮悬停效果
|
|
192
|
+
const aiSendBtn = document.getElementById('aiSendBtnModal');
|
|
193
|
+
aiSendBtn.addEventListener('mouseenter', () => {
|
|
194
|
+
aiSendBtn.style.transform = 'scale(1.05)';
|
|
195
|
+
});
|
|
196
|
+
aiSendBtn.addEventListener('mouseleave', () => {
|
|
197
|
+
aiSendBtn.style.transform = 'scale(1)';
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
document.getElementById('aiSendBtnModal').addEventListener('click', async () => {`,
|
|
201
|
+
` document.getElementById('aiSendBtnModal').addEventListener('click', async () => {
|
|
202
|
+
const question = document.getElementById('aiInputText').value.trim();
|
|
203
|
+
if (!question) return;
|
|
204
|
+
|
|
205
|
+
const chatMessages = document.getElementById('aiChatMessages');
|
|
206
|
+
|
|
207
|
+
// 显示用户消息
|
|
208
|
+
const userMsg = document.createElement('div');
|
|
209
|
+
userMsg.className = 'ai-message user';
|
|
210
|
+
userMsg.textContent = question;
|
|
211
|
+
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;';
|
|
212
|
+
chatMessages.appendChild(userMsg);
|
|
213
|
+
|
|
214
|
+
// 清空输入框
|
|
215
|
+
document.getElementById('aiInputText').value = '';
|
|
216
|
+
document.getElementById('aiInputText').style.height = 'auto';
|
|
217
|
+
|
|
218
|
+
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const token = localStorage.getItem('token');
|
|
222
|
+
const response = await fetch('http://localhost:8765/api/ai/ask', {
|
|
223
|
+
method: 'POST',
|
|
224
|
+
headers: {
|
|
225
|
+
'Content-Type': 'application/json',
|
|
226
|
+
'Authorization': \`Bearer \${token}\`
|
|
227
|
+
},
|
|
228
|
+
body: JSON.stringify({ question })
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const data = await response.json();
|
|
232
|
+
|
|
233
|
+
// 显示AI回复
|
|
234
|
+
const aiMsg = document.createElement('div');
|
|
235
|
+
aiMsg.className = 'ai-message ai';
|
|
236
|
+
aiMsg.textContent = data.answer || '抱歉,我现在无法回答这个问题。';
|
|
237
|
+
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;';
|
|
238
|
+
chatMessages.appendChild(aiMsg);
|
|
239
|
+
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const errorMsg = document.createElement('div');
|
|
242
|
+
errorMsg.className = 'ai-message ai';
|
|
243
|
+
errorMsg.textContent = '抱歉,发生了错误:' + error.message;
|
|
244
|
+
errorMsg.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;';
|
|
245
|
+
chatMessages.appendChild(errorMsg);
|
|
246
|
+
chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
247
|
+
}
|
|
248
|
+
});`
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
inputRelatedCode.forEach(code => {
|
|
252
|
+
if (content.includes(code)) {
|
|
253
|
+
content = content.replace(code, '');
|
|
254
|
+
console.log('✅ 已删除输入框相关代码');
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
259
|
+
|
|
260
|
+
console.log('\n✅ 所有美化完成!');
|
|
261
|
+
console.log('\n变更内容:');
|
|
262
|
+
console.log('1. 设置按钮:紫色渐变 + 阴影');
|
|
263
|
+
console.log('2. 帮助按钮:粉色渐变 + 阴影');
|
|
264
|
+
console.log('3. AI助手:删除底部输入框');
|
|
265
|
+
console.log('4. 快捷问题:2x2网格布局,渐变色按钮');
|
|
266
|
+
console.log('5. 点击快捷问题直接发送到AI');
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
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('检查 JavaScript 语法...');
|
|
11
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
12
|
+
|
|
13
|
+
// 检查括号匹配
|
|
14
|
+
let braceCount = 0;
|
|
15
|
+
let parenCount = 0;
|
|
16
|
+
let bracketCount = 0;
|
|
17
|
+
const lines = content.split('\n');
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < lines.length; i++) {
|
|
20
|
+
const line = lines[i];
|
|
21
|
+
|
|
22
|
+
// 跳过注释和字符串
|
|
23
|
+
const cleanLine = line.replace(/\/\/.*$/, '').replace(/'[^']*'/g, '').replace(/"[^"]*"/g, '').replace(/`[^`]*`/g, '');
|
|
24
|
+
|
|
25
|
+
for (const char of cleanLine) {
|
|
26
|
+
if (char === '{') braceCount++;
|
|
27
|
+
if (char === '}') braceCount--;
|
|
28
|
+
if (char === '(') parenCount++;
|
|
29
|
+
if (char === ')') parenCount--;
|
|
30
|
+
if (char === '[') bracketCount++;
|
|
31
|
+
if (char === ']') bracketCount--;
|
|
32
|
+
|
|
33
|
+
if (braceCount < 0 || parenCount < 0 || bracketCount < 0) {
|
|
34
|
+
console.log(`\n❌ 第 ${i + 1} 行发现不匹配的括号:`);
|
|
35
|
+
console.log(` ${line.trim()}`);
|
|
36
|
+
console.log(` 大括号: ${braceCount}, 圆括号: ${parenCount}, 方括号: ${bracketCount}`);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (braceCount < 0 || parenCount < 0 || bracketCount < 0) break;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log(`\n最终统计:`);
|
|
45
|
+
console.log(`大括号 {}: ${braceCount > 0 ? '缺少 ' + braceCount + ' 个 }' : braceCount < 0 ? '多了 ' + Math.abs(braceCount) + ' 个 }' : '匹配'}`);
|
|
46
|
+
console.log(`圆括号 (): ${parenCount > 0 ? '缺少 ' + parenCount + ' 个 )' : parenCount < 0 ? '多了 ' + Math.abs(parenCount) + ' 个 )' : '匹配'}`);
|
|
47
|
+
console.log(`方括号 []: ${bracketCount > 0 ? '缺少 ' + bracketCount + ' 个 ]' : bracketCount < 0 ? '多了 ' + Math.abs(bracketCount) + ' 个 ]' : '匹配'}`);
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
package/scripts/check-syntax.js
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
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('删除第 1339-1531 行的孤立代码...');
|
|
11
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
12
|
+
const lines = content.split('\n');
|
|
13
|
+
|
|
14
|
+
// 删除第 1339 行(索引 1338)到第 1531 行(索引 1530)之前的内容
|
|
15
|
+
const newLines = [
|
|
16
|
+
...lines.slice(0, 1338), // 保留前 1338 行
|
|
17
|
+
'', // 保留空行
|
|
18
|
+
...lines.slice(1531) // 从第 1532 行开始保留
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
content = newLines.join('\n');
|
|
22
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
23
|
+
|
|
24
|
+
console.log('✅ 已删除 ' + (1531 - 1338) + ' 行孤立代码');
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
10
|
+
const lines = content.split('\n');
|
|
11
|
+
|
|
12
|
+
console.log('搜索设置和帮助按钮...\n');
|
|
13
|
+
|
|
14
|
+
lines.forEach((line, i) => {
|
|
15
|
+
if ((line.includes('设置') || line.includes('帮助')) &&
|
|
16
|
+
(line.includes('btn') || line.includes('button') || line.includes('nav-btn'))) {
|
|
17
|
+
console.log(`第 ${i + 1} 行: ${line.trim()}`);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
let braceCount = 0;
|
|
15
|
+
let functionStack = [];
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < lines.length; i++) {
|
|
18
|
+
const line = lines[i];
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
|
|
21
|
+
// 检测函数定义
|
|
22
|
+
if (trimmed.match(/(?:async\s+)?function\s+\w+|(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?\(/)) {
|
|
23
|
+
const match = trimmed.match(/function\s+(\w+)|(?:const|let|var)\s+(\w+)/);
|
|
24
|
+
if (match) {
|
|
25
|
+
functionStack.push({ name: match[1] || match[2], line: i + 1, braceCount });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 计算括号
|
|
30
|
+
for (const char of line) {
|
|
31
|
+
if (char === '{') braceCount++;
|
|
32
|
+
if (char === '}') {
|
|
33
|
+
braceCount--;
|
|
34
|
+
if (braceCount < 0) {
|
|
35
|
+
console.log(`\n❌ 第 ${i + 1} 行有多余的 }:`);
|
|
36
|
+
console.log(` ${line.trim()}`);
|
|
37
|
+
console.log(`\n当前函数栈:`);
|
|
38
|
+
functionStack.forEach(f => console.log(` - ${f.name} (第 ${f.line} 行)`));
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 检测函数结束
|
|
45
|
+
if (trimmed === '}' && functionStack.length > 0) {
|
|
46
|
+
const lastFunc = functionStack[functionStack.length - 1];
|
|
47
|
+
if (braceCount <= lastFunc.braceCount) {
|
|
48
|
+
functionStack.pop();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log(`\n最终大括号计数: ${braceCount}`);
|
|
54
|
+
if (braceCount > 0) {
|
|
55
|
+
console.log(`\n❌ 缺少 ${braceCount} 个 }`);
|
|
56
|
+
console.log(`\n未闭合的函数:`);
|
|
57
|
+
functionStack.forEach(f => console.log(` - ${f.name} (第 ${f.line} 行)`));
|
|
58
|
+
} else if (braceCount < 0) {
|
|
59
|
+
console.log(`\n❌ 多了 ${Math.abs(braceCount)} 个 }`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
10
|
+
const lines = content.split('\n');
|
|
11
|
+
|
|
12
|
+
console.log('搜索侧边栏底部按钮...\n');
|
|
13
|
+
|
|
14
|
+
lines.forEach((line, i) => {
|
|
15
|
+
if (line.includes('退出登录') ||
|
|
16
|
+
(line.includes('⚙️') && line.includes('设置')) ||
|
|
17
|
+
(line.includes('❓') && line.includes('帮助'))) {
|
|
18
|
+
console.log(`第 ${i + 1} 行: ${line.trim()}`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|