collabdocchat 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/check-syntax.js +54 -0
- package/scripts/find-duplicate.js +35 -0
- package/scripts/start-app.js +3 -3
- package/scripts/update-port-user.js +21 -0
- package/scripts/update-port.js +22 -0
- package/src/pages/admin-dashboard.js +23 -23
- package/src/pages/user-dashboard.js +2 -2
- package/src/services/api.js +1 -1
- package/src/services/websocket.js +1 -1
package/package.json
CHANGED
|
@@ -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
|
+
|
package/scripts/start-app.js
CHANGED
|
@@ -9,7 +9,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
9
9
|
const __dirname = dirname(__filename);
|
|
10
10
|
const rootDir = join(__dirname, '..');
|
|
11
11
|
|
|
12
|
-
const PORT = process.env.PORT ||
|
|
12
|
+
const PORT = process.env.PORT || 8765;
|
|
13
13
|
const CLIENT_PORT = 5173;
|
|
14
14
|
const CLIENT_URL = `http://localhost:${CLIENT_PORT}`;
|
|
15
15
|
const isWindows = platform() === 'win32';
|
|
@@ -176,7 +176,7 @@ async function main() {
|
|
|
176
176
|
console.error('\n💡 解决方案:');
|
|
177
177
|
console.error(' 1. 停止占用端口的进程: npm run stop');
|
|
178
178
|
console.error(' 2. 或修改 .env 文件中的 PORT 配置');
|
|
179
|
-
console.error(
|
|
179
|
+
console.error(` 3. Windows: netstat -ano | findstr :${PORT}`);
|
|
180
180
|
console.error(' 然后: taskkill /PID <进程ID> /F\n');
|
|
181
181
|
process.exit(1);
|
|
182
182
|
}
|
|
@@ -216,7 +216,7 @@ async function main() {
|
|
|
216
216
|
openBrowser(CLIENT_URL);
|
|
217
217
|
console.log('\n✅ 应用启动成功!');
|
|
218
218
|
console.log('\n💡 提示:');
|
|
219
|
-
console.log(
|
|
219
|
+
console.log(` • 服务器: http://localhost:${PORT}`);
|
|
220
220
|
console.log(' • 客户端: http://localhost:5173');
|
|
221
221
|
console.log(' • 默认账号: admin / admin123');
|
|
222
222
|
console.log('\n⚠️ 按 Ctrl+C 停止服务\n');
|
|
@@ -0,0 +1,21 @@
|
|
|
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/user-dashboard.js');
|
|
9
|
+
|
|
10
|
+
console.log('更新 user-dashboard.js 端口号...');
|
|
11
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
12
|
+
|
|
13
|
+
const count = (content.match(/localhost:3000/g) || []).length;
|
|
14
|
+
console.log(`找到 ${count} 处需要替换`);
|
|
15
|
+
|
|
16
|
+
content = content.replace(/localhost:3000/g, 'localhost:8765');
|
|
17
|
+
|
|
18
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
19
|
+
|
|
20
|
+
console.log('✅ user-dashboard.js 端口号更新完成!');
|
|
21
|
+
|
|
@@ -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
|
+
|
|
10
|
+
console.log('更新端口号从 3000 到 8765...');
|
|
11
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
12
|
+
|
|
13
|
+
// 替换所有 localhost:3000 为 localhost:8765
|
|
14
|
+
const count = (content.match(/localhost:3000/g) || []).length;
|
|
15
|
+
console.log(`找到 ${count} 处需要替换`);
|
|
16
|
+
|
|
17
|
+
content = content.replace(/localhost:3000/g, 'localhost:8765');
|
|
18
|
+
|
|
19
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
20
|
+
|
|
21
|
+
console.log('✅ 端口号更新完成!');
|
|
22
|
+
|
|
@@ -1290,12 +1290,12 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1290
1290
|
});
|
|
1291
1291
|
|
|
1292
1292
|
// 发送按钮悬停效果
|
|
1293
|
-
const
|
|
1294
|
-
|
|
1295
|
-
|
|
1293
|
+
const aiSendBtn = document.getElementById('aiSendBtnModal');
|
|
1294
|
+
aiSendBtn.addEventListener('mouseenter', () => {
|
|
1295
|
+
aiSendBtn.style.transform = 'scale(1.05)';
|
|
1296
1296
|
});
|
|
1297
|
-
|
|
1298
|
-
|
|
1297
|
+
aiSendBtn.addEventListener('mouseleave', () => {
|
|
1298
|
+
aiSendBtn.style.transform = 'scale(1)';
|
|
1299
1299
|
});
|
|
1300
1300
|
|
|
1301
1301
|
document.getElementById('aiSendBtnModal').addEventListener('click', async () => {
|
|
@@ -1323,7 +1323,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1323
1323
|
|
|
1324
1324
|
try {
|
|
1325
1325
|
const token = localStorage.getItem('token');
|
|
1326
|
-
const response = await fetch('http://localhost:
|
|
1326
|
+
const response = await fetch('http://localhost:8765/api/ai/ask', {
|
|
1327
1327
|
method: 'POST',
|
|
1328
1328
|
headers: {
|
|
1329
1329
|
'Content-Type': 'application/json',
|
|
@@ -1470,7 +1470,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1470
1470
|
formData.append('description', '协作白板作品');
|
|
1471
1471
|
|
|
1472
1472
|
const token = localStorage.getItem('token');
|
|
1473
|
-
const response = await fetch('http://localhost:
|
|
1473
|
+
const response = await fetch('http://localhost:8765/api/files/upload', {
|
|
1474
1474
|
method: 'POST',
|
|
1475
1475
|
headers: {
|
|
1476
1476
|
'Authorization': `Bearer ${token}`
|
|
@@ -1700,7 +1700,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1700
1700
|
window.showAuditDetail = async (logId) => {
|
|
1701
1701
|
try {
|
|
1702
1702
|
const token = localStorage.getItem('token');
|
|
1703
|
-
const response = await fetch(`http://localhost:
|
|
1703
|
+
const response = await fetch(`http://localhost:8765/api/audit/${logId}`, {
|
|
1704
1704
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
1705
1705
|
});
|
|
1706
1706
|
const result = await response.json();
|
|
@@ -2019,7 +2019,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2019
2019
|
|
|
2020
2020
|
try {
|
|
2021
2021
|
const token = localStorage.getItem('token');
|
|
2022
|
-
const response = await fetch(`http://localhost:
|
|
2022
|
+
const response = await fetch(`http://localhost:8765/api/knowledge/group/${currentGroup._id}`, {
|
|
2023
2023
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2024
2024
|
});
|
|
2025
2025
|
const result = await response.json();
|
|
@@ -2108,7 +2108,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2108
2108
|
btn.addEventListener('click', async () => {
|
|
2109
2109
|
if (confirm('确定要删除这个知识条目吗?')) {
|
|
2110
2110
|
try {
|
|
2111
|
-
await fetch(`http://localhost:
|
|
2111
|
+
await fetch(`http://localhost:8765/api/knowledge/${btn.dataset.id}`, {
|
|
2112
2112
|
method: 'DELETE',
|
|
2113
2113
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2114
2114
|
});
|
|
@@ -2146,8 +2146,8 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2146
2146
|
try {
|
|
2147
2147
|
const editId = e.target.dataset.editId;
|
|
2148
2148
|
const url = editId
|
|
2149
|
-
? `http://localhost:
|
|
2150
|
-
: 'http://localhost:
|
|
2149
|
+
? `http://localhost:8765/api/knowledge/${editId}`
|
|
2150
|
+
: 'http://localhost:8765/api/knowledge';
|
|
2151
2151
|
const method = editId ? 'PUT' : 'POST';
|
|
2152
2152
|
|
|
2153
2153
|
await fetch(url, {
|
|
@@ -2180,7 +2180,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2180
2180
|
|
|
2181
2181
|
try {
|
|
2182
2182
|
const token = localStorage.getItem('token');
|
|
2183
|
-
const response = await fetch(`http://localhost:
|
|
2183
|
+
const response = await fetch(`http://localhost:8765/api/workflows/group/${currentGroup._id}`, {
|
|
2184
2184
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2185
2185
|
});
|
|
2186
2186
|
const result = await response.json();
|
|
@@ -2292,7 +2292,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2292
2292
|
document.querySelectorAll('[data-action="toggle"]').forEach(btn => {
|
|
2293
2293
|
btn.addEventListener('click', async () => {
|
|
2294
2294
|
try {
|
|
2295
|
-
await fetch(`http://localhost:
|
|
2295
|
+
await fetch(`http://localhost:8765/api/workflows/${btn.dataset.id}/toggle`, {
|
|
2296
2296
|
method: 'POST',
|
|
2297
2297
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2298
2298
|
});
|
|
@@ -2307,7 +2307,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2307
2307
|
btn.addEventListener('click', async () => {
|
|
2308
2308
|
if (confirm('确定要删除这个工作流吗?')) {
|
|
2309
2309
|
try {
|
|
2310
|
-
await fetch(`http://localhost:
|
|
2310
|
+
await fetch(`http://localhost:8765/api/workflows/${btn.dataset.id}`, {
|
|
2311
2311
|
method: 'DELETE',
|
|
2312
2312
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2313
2313
|
});
|
|
@@ -2341,7 +2341,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2341
2341
|
};
|
|
2342
2342
|
|
|
2343
2343
|
try {
|
|
2344
|
-
await fetch('http://localhost:
|
|
2344
|
+
await fetch('http://localhost:8765/api/workflows', {
|
|
2345
2345
|
method: 'POST',
|
|
2346
2346
|
headers: {
|
|
2347
2347
|
'Content-Type': 'application/json',
|
|
@@ -2365,7 +2365,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2365
2365
|
async function renderBackupView(container) {
|
|
2366
2366
|
try {
|
|
2367
2367
|
const token = localStorage.getItem('token');
|
|
2368
|
-
const response = await fetch('http://localhost:
|
|
2368
|
+
const response = await fetch('http://localhost:8765/api/backup/list', {
|
|
2369
2369
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2370
2370
|
});
|
|
2371
2371
|
const result = await response.json();
|
|
@@ -2400,7 +2400,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2400
2400
|
<span>📅 ${new Date(backup.createdAt).toLocaleString()}</span>
|
|
2401
2401
|
</div>
|
|
2402
2402
|
<div style="display: flex; gap: 10px;">
|
|
2403
|
-
<a href="http://localhost:
|
|
2403
|
+
<a href="http://localhost:8765/api/backup/download/${backup.filename}" class="btn-primary btn-sm" download style="flex: 1; text-align: center; text-decoration: none; display: block; padding: 8px;">⬇️ 下载</a>
|
|
2404
2404
|
<button class="btn-danger btn-sm" data-filename="${backup.filename}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
|
|
2405
2405
|
</div>
|
|
2406
2406
|
`;
|
|
@@ -2419,7 +2419,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2419
2419
|
btn.addEventListener('click', async () => {
|
|
2420
2420
|
if (confirm('确定要删除这个备份吗?')) {
|
|
2421
2421
|
try {
|
|
2422
|
-
await fetch(`http://localhost:
|
|
2422
|
+
await fetch(`http://localhost:8765/api/backup/${btn.dataset.filename}`, {
|
|
2423
2423
|
method: 'DELETE',
|
|
2424
2424
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2425
2425
|
});
|
|
@@ -2439,7 +2439,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2439
2439
|
btn.disabled = true;
|
|
2440
2440
|
btn.textContent = '⏳ 创建中...';
|
|
2441
2441
|
try {
|
|
2442
|
-
await fetch('http://localhost:
|
|
2442
|
+
await fetch('http://localhost:8765/api/backup/create', {
|
|
2443
2443
|
method: 'POST',
|
|
2444
2444
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2445
2445
|
});
|
|
@@ -2515,7 +2515,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2515
2515
|
// 加载导出历史
|
|
2516
2516
|
try {
|
|
2517
2517
|
const token = localStorage.getItem('token');
|
|
2518
|
-
const response = await fetch('http://localhost:
|
|
2518
|
+
const response = await fetch('http://localhost:8765/api/export/history', {
|
|
2519
2519
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2520
2520
|
});
|
|
2521
2521
|
const result = await response.json();
|
|
@@ -2528,7 +2528,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2528
2528
|
<div style="font-weight: 600; margin-bottom: 5px;">📦 ${exp.format.toUpperCase()} 导出</div>
|
|
2529
2529
|
<div style="font-size: 12px; color: var(--text-secondary);">📅 ${new Date(exp.createdAt).toLocaleString()}</div>
|
|
2530
2530
|
</div>
|
|
2531
|
-
<a href="http://localhost:
|
|
2531
|
+
<a href="http://localhost:8765/api/export/download/${exp.filename}" class="btn-sm btn-primary" download style="text-decoration: none;">⬇️ 下载</a>
|
|
2532
2532
|
</div>
|
|
2533
2533
|
`).join('');
|
|
2534
2534
|
} else {
|
|
@@ -2554,7 +2554,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2554
2554
|
|
|
2555
2555
|
try {
|
|
2556
2556
|
const token = localStorage.getItem('token');
|
|
2557
|
-
const response = await fetch('http://localhost:
|
|
2557
|
+
const response = await fetch('http://localhost:8765/api/export', {
|
|
2558
2558
|
method: 'POST',
|
|
2559
2559
|
headers: {
|
|
2560
2560
|
'Content-Type': 'application/json',
|
|
@@ -921,7 +921,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
921
921
|
|
|
922
922
|
try {
|
|
923
923
|
const token = localStorage.getItem('token');
|
|
924
|
-
const response = await fetch(`http://localhost:
|
|
924
|
+
const response = await fetch(`http://localhost:8765/api/knowledge/group/${currentGroup._id}`, {
|
|
925
925
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
926
926
|
});
|
|
927
927
|
const result = await response.json();
|
|
@@ -1019,7 +1019,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1019
1019
|
|
|
1020
1020
|
try {
|
|
1021
1021
|
const token = localStorage.getItem('token');
|
|
1022
|
-
const response = await fetch('http://localhost:
|
|
1022
|
+
const response = await fetch('http://localhost:8765/api/ai/ask', {
|
|
1023
1023
|
method: 'POST',
|
|
1024
1024
|
headers: {
|
|
1025
1025
|
'Content-Type': 'application/json',
|
package/src/services/api.js
CHANGED