collabdocchat 1.2.13 → 2.0.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.
Files changed (62) hide show
  1. package/README.md +219 -218
  2. package/index.html +2 -0
  3. package/install-and-start.bat +5 -0
  4. package/install-and-start.sh +5 -0
  5. package/package.json +9 -2
  6. package/scripts/pre-publish-check.js +213 -0
  7. package/scripts/start-app.js +15 -15
  8. package/server/index.js +38 -6
  9. package/server/middleware/cache.js +115 -0
  10. package/server/middleware/errorHandler.js +209 -0
  11. package/server/models/Document.js +66 -59
  12. package/server/models/File.js +49 -43
  13. package/server/models/Group.js +6 -0
  14. package/server/models/KnowledgeBase.js +254 -0
  15. package/server/models/Message.js +43 -0
  16. package/server/models/Task.js +87 -55
  17. package/server/models/User.js +67 -60
  18. package/server/models/Workflow.js +249 -0
  19. package/server/routes/ai.js +327 -0
  20. package/server/routes/audit.js +245 -210
  21. package/server/routes/backup.js +108 -0
  22. package/server/routes/chunked-upload.js +343 -0
  23. package/server/routes/export.js +440 -0
  24. package/server/routes/files.js +294 -218
  25. package/server/routes/groups.js +182 -0
  26. package/server/routes/knowledge.js +509 -0
  27. package/server/routes/tasks.js +257 -110
  28. package/server/routes/workflows.js +380 -0
  29. package/server/utils/backup.js +439 -0
  30. package/server/utils/cache.js +223 -0
  31. package/server/utils/workflow-engine.js +479 -0
  32. package/server/websocket/enhanced.js +509 -0
  33. package/server/websocket/index.js +233 -1
  34. package/src/components/knowledge-modal.js +485 -0
  35. package/src/components/optimized-poll-detail.js +724 -0
  36. package/src/main.js +5 -0
  37. package/src/pages/admin-dashboard.js +2248 -44
  38. package/src/pages/optimized-backup-view.js +616 -0
  39. package/src/pages/optimized-knowledge-view.js +803 -0
  40. package/src/pages/optimized-task-detail.js +843 -0
  41. package/src/pages/optimized-workflow-view.js +806 -0
  42. package/src/pages/simplified-workflows.js +651 -0
  43. package/src/pages/user-dashboard.js +677 -58
  44. package/src/services/api.js +65 -1
  45. package/src/services/auth.js +1 -1
  46. package/src/services/websocket.js +124 -16
  47. package/src/styles/collaboration-modern.js +708 -0
  48. package/src/styles/enhancements.css +392 -0
  49. package/src/styles/main.css +620 -1420
  50. package/src/styles/responsive.css +1000 -0
  51. package/src/styles/sidebar-fix.css +60 -0
  52. package/src/utils/ai-assistant.js +1398 -0
  53. package/src/utils/chat-enhancements.js +509 -0
  54. package/src/utils/collaboration-enhancer.js +1151 -0
  55. package/src/utils/feature-integrator.js +1724 -0
  56. package/src/utils/onboarding-guide.js +734 -0
  57. package/src/utils/performance.js +394 -0
  58. package/src/utils/permission-manager.js +890 -0
  59. package/src/utils/responsive-handler.js +491 -0
  60. package/src/utils/theme-manager.js +811 -0
  61. package/src/utils/ui-enhancements-loader.js +329 -0
  62. package/USAGE.md +0 -298
@@ -1,4 +1,4 @@
1
- const API_URL = 'http://localhost:3000/api';
1
+ const API_URL = 'http://localhost:8765/api';
2
2
 
3
3
  export class ApiService {
4
4
  constructor() {
@@ -95,6 +95,48 @@ export class ApiService {
95
95
  return await this.request(`/groups/${groupId}/messages`);
96
96
  }
97
97
 
98
+ // 清除聊天记录(管理员)
99
+ async clearChatMessages(groupId, options = {}) {
100
+ return await this.request(`/groups/${groupId}/messages`, {
101
+ method: 'DELETE',
102
+ body: JSON.stringify(options)
103
+ });
104
+ }
105
+
106
+ // 清除指定用户的消息(管理员)
107
+ async clearUserMessages(groupId, userId) {
108
+ return await this.request(`/groups/${groupId}/messages/user/${userId}`, {
109
+ method: 'DELETE'
110
+ });
111
+ }
112
+
113
+ // 撤回消息
114
+ async recallMessage(groupId, messageId) {
115
+ return await this.request(`/groups/${groupId}/messages/${messageId}/recall`, {
116
+ method: 'POST'
117
+ });
118
+ }
119
+
120
+ // 标记消息为已读
121
+ async markMessageAsRead(groupId, messageId) {
122
+ return await this.request(`/groups/${groupId}/messages/${messageId}/read`, {
123
+ method: 'POST'
124
+ });
125
+ }
126
+
127
+ // 批量标记消息为已读
128
+ async markMessagesAsRead(groupId, messageIds) {
129
+ return await this.request(`/groups/${groupId}/messages/read-all`, {
130
+ method: 'POST',
131
+ body: JSON.stringify({ messageIds })
132
+ });
133
+ }
134
+
135
+ // 获取未读消息数量
136
+ async getUnreadCount(groupId) {
137
+ return await this.request(`/groups/${groupId}/messages/unread-count`);
138
+ }
139
+
98
140
  async randomCall(groupId, count = 1) {
99
141
  return await this.request(`/groups/${groupId}/call`, {
100
142
  method: 'POST',
@@ -131,6 +173,14 @@ export class ApiService {
131
173
  });
132
174
  }
133
175
 
176
+ // 投票相关
177
+ async submitPollVote(taskId, selectedOptions) {
178
+ return await this.request(`/tasks/${taskId}/vote`, {
179
+ method: 'POST',
180
+ body: JSON.stringify({ selectedOptions })
181
+ });
182
+ }
183
+
134
184
  // 文档相关
135
185
  async getDocuments(groupId) {
136
186
  return await this.request(`/documents/group/${groupId}`);
@@ -217,12 +267,22 @@ export class ApiService {
217
267
  return await this.request(`/audit/group/${groupId}${queryString ? '?' + queryString : ''}`);
218
268
  }
219
269
 
270
+ // 获取单个任务详情
271
+ async getTask(taskId) {
272
+ return await this.request(`/tasks/${taskId}`);
273
+ }
274
+
220
275
  async getAuditSummary(filters = {}) {
221
276
  const params = new URLSearchParams(filters);
222
277
  const queryString = params.toString();
223
278
  return await this.request(`/audit/stats/summary${queryString ? '?' + queryString : ''}`);
224
279
  }
225
280
 
281
+ // 获取审计日志详情
282
+ async getAuditLogDetail(logId) {
283
+ return await this.request(`/audit/${logId}`);
284
+ }
285
+
226
286
  // 文件相关
227
287
  async uploadFile(groupId, file, description = '') {
228
288
  const formData = new FormData();
@@ -261,5 +321,9 @@ export class ApiService {
261
321
  getFileDownloadUrl(fileId) {
262
322
  return `${API_URL}/files/${fileId}/download?token=${this.token}`;
263
323
  }
324
+
325
+ getFileViewUrl(fileId) {
326
+ return `${API_URL}/files/${fileId}/view?token=${this.token}`;
327
+ }
264
328
  }
265
329
 
@@ -1,4 +1,4 @@
1
- const API_URL = 'http://localhost:3000/api';
1
+ const API_URL = 'http://localhost:8765/api';
2
2
 
3
3
  export class AuthService {
4
4
  async login(username, password) {
@@ -2,29 +2,122 @@ export class WebSocketService {
2
2
  constructor() {
3
3
  this.ws = null;
4
4
  this.listeners = new Map();
5
+ this.token = null;
6
+ this.reconnectAttempts = 0;
7
+ this.maxReconnectAttempts = 10;
8
+ this.reconnectDelay = 1000;
9
+ this.heartbeatInterval = null;
10
+ this.isConnecting = false;
11
+ this.isAuthenticated = false;
5
12
  }
6
13
 
7
14
  connect(token) {
8
- this.ws = new WebSocket('ws://localhost:3000');
15
+ if (this.isConnecting) {
16
+ console.log('⏳ 正在连接中,请稍候...');
17
+ return;
18
+ }
9
19
 
10
- this.ws.onopen = () => {
11
- console.log('✅ WebSocket 连接成功');
12
- this.send({ type: 'auth', token });
13
- };
20
+ this.token = token;
21
+ this.isConnecting = true;
22
+
23
+ try {
24
+ this.ws = new WebSocket('ws://localhost:8765');
25
+
26
+ this.ws.onopen = () => {
27
+ console.log('✅ WebSocket 连接成功');
28
+ this.isConnecting = false;
29
+ this.reconnectAttempts = 0;
30
+ this.reconnectDelay = 1000;
31
+ this.send({ type: 'auth', token });
32
+ this.startHeartbeat();
33
+ };
34
+
35
+ this.ws.onmessage = (event) => {
36
+ try {
37
+ const data = JSON.parse(event.data);
38
+
39
+ if (data.type === 'auth_success') {
40
+ this.isAuthenticated = true;
41
+ console.log('✅ WebSocket 认证成功');
42
+ } else if (data.type === 'pong') {
43
+ // 心跳响应
44
+ console.log('💓 心跳正常');
45
+ }
46
+
47
+ this.notifyListeners(data.type, data);
48
+ } catch (error) {
49
+ console.error('❌ 解析消息失败:', error);
50
+ }
51
+ };
52
+
53
+ this.ws.onerror = (error) => {
54
+ console.error('❌ WebSocket 错误:', error);
55
+ this.isConnecting = false;
56
+ };
57
+
58
+ this.ws.onclose = (event) => {
59
+ console.log(`🔌 WebSocket 连接关闭 (代码: ${event.code}, 原因: ${event.reason || '未知'})`);
60
+ this.isConnecting = false;
61
+ this.isAuthenticated = false;
62
+ this.stopHeartbeat();
63
+ this.handleReconnect();
64
+ };
65
+ } catch (error) {
66
+ console.error('❌ WebSocket 连接失败:', error);
67
+ this.isConnecting = false;
68
+ this.handleReconnect();
69
+ }
70
+ }
71
+
72
+ handleReconnect() {
73
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
74
+ console.error('❌ 达到最大重连次数,停止重连');
75
+ this.notifyListeners('max_reconnect_reached', {
76
+ message: '无法连接到服务器,请刷新页面重试'
77
+ });
78
+ return;
79
+ }
14
80
 
15
- this.ws.onmessage = (event) => {
16
- const data = JSON.parse(event.data);
17
- this.notifyListeners(data.type, data);
18
- };
81
+ this.reconnectAttempts++;
82
+ const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), 30000);
83
+
84
+ console.log(`🔄 ${delay / 1000}秒后尝试第 ${this.reconnectAttempts} 次重连...`);
85
+
86
+ setTimeout(() => {
87
+ if (this.token) {
88
+ this.connect(this.token);
89
+ }
90
+ }, delay);
91
+ }
19
92
 
20
- this.ws.onerror = (error) => {
21
- console.error('❌ WebSocket 错误:', error);
22
- };
93
+ startHeartbeat() {
94
+ this.stopHeartbeat();
95
+
96
+ this.heartbeatInterval = setInterval(() => {
97
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
98
+ this.send({ type: 'ping', timestamp: Date.now() });
99
+ }
100
+ }, 30000); // 每30秒发送一次心跳
101
+ }
23
102
 
24
- this.ws.onclose = () => {
25
- console.log('🔌 WebSocket 连接关闭');
26
- setTimeout(() => this.connect(token), 3000);
27
- };
103
+ stopHeartbeat() {
104
+ if (this.heartbeatInterval) {
105
+ clearInterval(this.heartbeatInterval);
106
+ this.heartbeatInterval = null;
107
+ }
108
+ }
109
+
110
+ disconnect() {
111
+ this.stopHeartbeat();
112
+ this.reconnectAttempts = this.maxReconnectAttempts; // 阻止自动重连
113
+
114
+ if (this.ws) {
115
+ this.ws.close(1000, '用户主动断开');
116
+ this.ws = null;
117
+ }
118
+
119
+ this.isAuthenticated = false;
120
+ console.log('👋 WebSocket 已断开');
28
121
  }
29
122
 
30
123
  send(data) {
@@ -75,6 +168,21 @@ export class WebSocketService {
75
168
  sendTyping(documentId, username, isTyping) {
76
169
  this.send({ type: 'typing', documentId, username, isTyping });
77
170
  }
171
+
172
+ // 撤回消息
173
+ recallMessage(messageId) {
174
+ this.send({ type: 'recall_message', messageId });
175
+ }
176
+
177
+ // 标记消息为已读
178
+ markMessageAsRead(messageId) {
179
+ this.send({ type: 'message_read', messageId });
180
+ }
181
+
182
+ // 发送用户在线状态
183
+ sendUserOnline(username) {
184
+ this.send({ type: 'user_online', username });
185
+ }
78
186
  }
79
187
 
80
188