collabdocchat 1.2.13 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) 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/generate-docs.js +448 -0
  7. package/scripts/pre-publish-check.js +213 -0
  8. package/scripts/start-app.js +15 -15
  9. package/server/index.js +38 -6
  10. package/server/middleware/cache.js +115 -0
  11. package/server/middleware/errorHandler.js +209 -0
  12. package/server/models/Document.js +66 -59
  13. package/server/models/File.js +49 -43
  14. package/server/models/Group.js +6 -0
  15. package/server/models/KnowledgeBase.js +254 -0
  16. package/server/models/Message.js +43 -0
  17. package/server/models/Task.js +87 -55
  18. package/server/models/User.js +67 -60
  19. package/server/models/Workflow.js +249 -0
  20. package/server/routes/ai.js +327 -0
  21. package/server/routes/audit.js +245 -210
  22. package/server/routes/backup.js +108 -0
  23. package/server/routes/chunked-upload.js +343 -0
  24. package/server/routes/export.js +440 -0
  25. package/server/routes/files.js +294 -218
  26. package/server/routes/groups.js +182 -0
  27. package/server/routes/knowledge.js +509 -0
  28. package/server/routes/tasks.js +257 -110
  29. package/server/routes/workflows.js +380 -0
  30. package/server/utils/backup.js +439 -0
  31. package/server/utils/cache.js +223 -0
  32. package/server/utils/workflow-engine.js +479 -0
  33. package/server/websocket/enhanced.js +509 -0
  34. package/server/websocket/index.js +233 -1
  35. package/src/components/knowledge-modal.js +485 -0
  36. package/src/components/optimized-poll-detail.js +724 -0
  37. package/src/main.js +5 -0
  38. package/src/pages/admin-dashboard.js +2248 -44
  39. package/src/pages/optimized-backup-view.js +616 -0
  40. package/src/pages/optimized-knowledge-view.js +803 -0
  41. package/src/pages/optimized-task-detail.js +843 -0
  42. package/src/pages/optimized-workflow-view.js +806 -0
  43. package/src/pages/simplified-workflows.js +651 -0
  44. package/src/pages/user-dashboard.js +677 -58
  45. package/src/services/api.js +64 -0
  46. package/src/services/auth.js +1 -1
  47. package/src/services/websocket.js +124 -16
  48. package/src/styles/collaboration-modern.js +708 -0
  49. package/src/styles/enhancements.css +392 -0
  50. package/src/styles/main.css +620 -1420
  51. package/src/styles/responsive.css +1000 -0
  52. package/src/styles/sidebar-fix.css +60 -0
  53. package/src/utils/ai-assistant.js +1398 -0
  54. package/src/utils/chat-enhancements.js +509 -0
  55. package/src/utils/collaboration-enhancer.js +1151 -0
  56. package/src/utils/feature-integrator.js +1724 -0
  57. package/src/utils/onboarding-guide.js +734 -0
  58. package/src/utils/performance.js +394 -0
  59. package/src/utils/permission-manager.js +890 -0
  60. package/src/utils/responsive-handler.js +491 -0
  61. package/src/utils/theme-manager.js +811 -0
  62. package/src/utils/ui-enhancements-loader.js +329 -0
  63. package/USAGE.md +0 -298
@@ -1,110 +1,257 @@
1
- import express from 'express';
2
- import Task from '../models/Task.js';
3
- import Group from '../models/Group.js';
4
- import { authenticate, isAdmin } from '../middleware/auth.js';
5
-
6
- const router = express.Router();
7
-
8
- // 创建任务(仅管理员)
9
- router.post('/', authenticate, isAdmin, async (req, res) => {
10
- try {
11
- const { title, description, groupId, assignedTo, relatedDocument, deadline } = req.body;
12
-
13
- const task = new Task({
14
- title,
15
- description,
16
- group: groupId,
17
- creator: req.user.userId,
18
- assignedTo,
19
- relatedDocument,
20
- deadline
21
- });
22
-
23
- await task.save();
24
-
25
- // 更新群组的任务列表
26
- await Group.findByIdAndUpdate(groupId, { $push: { tasks: task._id } });
27
-
28
- res.status(201).json({ message: '任务创建成功', task });
29
- } catch (error) {
30
- res.status(500).json({ message: '创建任务失败', error: error.message });
31
- }
32
- });
33
-
34
- // 获取群组的所有任务
35
- router.get('/group/:groupId', authenticate, async (req, res) => {
36
- try {
37
- const tasks = await Task.find({ group: req.params.groupId })
38
- .populate('creator', 'username avatar')
39
- .populate('assignedTo', 'username avatar')
40
- .populate('relatedDocument', 'title')
41
- .sort({ createdAt: -1 });
42
-
43
- res.json({ tasks });
44
- } catch (error) {
45
- res.status(500).json({ message: '获取任务失败', error: error.message });
46
- }
47
- });
48
-
49
- // 获取用户的任务
50
- router.get('/my', authenticate, async (req, res) => {
51
- try {
52
- const tasks = await Task.find({ assignedTo: req.user.userId })
53
- .populate('creator', 'username avatar')
54
- .populate('group', 'name')
55
- .populate('relatedDocument', 'title')
56
- .sort({ createdAt: -1 });
57
-
58
- res.json({ tasks });
59
- } catch (error) {
60
- res.status(500).json({ message: '获取任务失败', error: error.message });
61
- }
62
- });
63
-
64
- // 更新任务状态
65
- router.patch('/:id/status', authenticate, async (req, res) => {
66
- try {
67
- const { status } = req.body;
68
- const task = await Task.findById(req.params.id);
69
-
70
- if (!task) {
71
- return res.status(404).json({ message: '任务不存在' });
72
- }
73
-
74
- task.status = status;
75
-
76
- if (status === 'completed') {
77
- task.completedBy.push({
78
- user: req.user.userId,
79
- completedAt: new Date()
80
- });
81
- }
82
-
83
- await task.save();
84
-
85
- res.json({ message: '任务状态更新成功', task });
86
- } catch (error) {
87
- res.status(500).json({ message: '更新任务状态失败', error: error.message });
88
- }
89
- });
90
-
91
- // 删除任务(仅管理员)
92
- router.delete('/:id', authenticate, isAdmin, async (req, res) => {
93
- try {
94
- const task = await Task.findByIdAndDelete(req.params.id);
95
-
96
- if (!task) {
97
- return res.status(404).json({ message: '任务不存在' });
98
- }
99
-
100
- await Group.findByIdAndUpdate(task.group, { $pull: { tasks: task._id } });
101
-
102
- res.json({ message: '任务删除成功' });
103
- } catch (error) {
104
- res.status(500).json({ message: '删除任务失败', error: error.message });
105
- }
106
- });
107
-
108
- export default router;
109
-
110
-
1
+ import express from 'express';
2
+ import Task from '../models/Task.js';
3
+ import Group from '../models/Group.js';
4
+ import { authenticate, isAdmin } from '../middleware/auth.js';
5
+
6
+ const router = express.Router();
7
+
8
+ // 创建任务(仅管理员)
9
+ router.post('/', authenticate, isAdmin, async (req, res) => {
10
+ try {
11
+ const { title, description, groupId, assignedTo, relatedDocument, deadline, type, pollData } = req.body;
12
+
13
+ const taskData = {
14
+ title,
15
+ description,
16
+ group: groupId,
17
+ creator: req.user.userId,
18
+ assignedTo,
19
+ relatedDocument,
20
+ deadline
21
+ };
22
+
23
+ // 如果是投票任务,添加投票数据
24
+ if (type === 'poll' && pollData) {
25
+ taskData.type = 'poll';
26
+ taskData.pollData = pollData;
27
+ }
28
+
29
+ const task = new Task(taskData);
30
+
31
+ await task.save();
32
+
33
+ // 更新群组的任务列表
34
+ await Group.findByIdAndUpdate(groupId, { $push: { tasks: task._id } });
35
+
36
+ res.status(201).json({ message: '任务创建成功', task });
37
+ } catch (error) {
38
+ res.status(500).json({ message: '创建任务失败', error: error.message });
39
+ }
40
+ });
41
+
42
+ // 获取用户的任务(必须在 /:id 之前)
43
+ router.get('/my', authenticate, async (req, res) => {
44
+ try {
45
+ const tasks = await Task.find({ assignedTo: req.user.userId })
46
+ .populate('creator', 'username avatar')
47
+ .populate('group', 'name')
48
+ .populate('relatedDocument', 'title')
49
+ .sort({ createdAt: -1 });
50
+
51
+ res.json({ tasks });
52
+ } catch (error) {
53
+ res.status(500).json({ message: '获取任务失败', error: error.message });
54
+ }
55
+ });
56
+
57
+ // 获取群组的所有任务
58
+ router.get('/group/:groupId', authenticate, async (req, res) => {
59
+ try {
60
+ const tasks = await Task.find({ group: req.params.groupId })
61
+ .populate('creator', 'username avatar')
62
+ .populate('assignedTo', 'username avatar')
63
+ .populate('relatedDocument', 'title')
64
+ .sort({ createdAt: -1 });
65
+
66
+ res.json({ tasks });
67
+ } catch (error) {
68
+ res.status(500).json({ message: '获取任务失败', error: error.message });
69
+ }
70
+ });
71
+
72
+ // 获取单个任务详情
73
+ router.get('/:id', authenticate, async (req, res) => {
74
+ try {
75
+ const task = await Task.findById(req.params.id)
76
+ .populate('creator', 'username avatar')
77
+ .populate('assignedTo', 'username avatar')
78
+ .populate('completedBy.user', 'username avatar')
79
+ .populate({
80
+ path: 'group',
81
+ select: 'name description members',
82
+ populate: {
83
+ path: 'members',
84
+ select: 'username avatar'
85
+ }
86
+ })
87
+ .populate('relatedDocument', 'title');
88
+
89
+ if (!task) {
90
+ return res.status(404).json({ message: '任务不存在' });
91
+ }
92
+
93
+ res.json({ task });
94
+ } catch (error) {
95
+ console.error('获取任务详情失败:', error);
96
+ res.status(500).json({ message: '获取任务详情失败', error: error.message });
97
+ }
98
+ });
99
+
100
+ // 更新任务状态
101
+ router.patch('/:id/status', authenticate, async (req, res) => {
102
+ try {
103
+ const { status } = req.body;
104
+ const task = await Task.findById(req.params.id);
105
+
106
+ if (!task) {
107
+ return res.status(404).json({ message: '任务不存在' });
108
+ }
109
+
110
+ task.status = status;
111
+
112
+ if (status === 'completed') {
113
+ // 检查用户是否已经标记为完成
114
+ const alreadyCompleted = task.completedBy.some(
115
+ item => item.user.toString() === req.user.userId
116
+ );
117
+
118
+ if (!alreadyCompleted) {
119
+ task.completedBy.push({
120
+ user: req.user.userId,
121
+ completedAt: new Date()
122
+ });
123
+ }
124
+ }
125
+
126
+ await task.save();
127
+
128
+ // 重新查询以填充用户信息
129
+ const updatedTask = await Task.findById(task._id)
130
+ .populate('creator', 'username avatar')
131
+ .populate('assignedTo', 'username avatar')
132
+ .populate('completedBy.user', 'username avatar')
133
+ .populate('group', 'name');
134
+
135
+ res.json({ message: '任务状态更新成功', task: updatedTask });
136
+ } catch (error) {
137
+ res.status(500).json({ message: '更新任务状态失败', error: error.message });
138
+ }
139
+ });
140
+
141
+ // 删除任务(仅管理员)
142
+ router.delete('/:id', authenticate, isAdmin, async (req, res) => {
143
+ try {
144
+ const task = await Task.findByIdAndDelete(req.params.id);
145
+
146
+ if (!task) {
147
+ return res.status(404).json({ message: '任务不存在' });
148
+ }
149
+
150
+ await Group.findByIdAndUpdate(task.group, { $pull: { tasks: task._id } });
151
+
152
+ res.json({ message: '任务删除成功' });
153
+ } catch (error) {
154
+ res.status(500).json({ message: '删除任务失败', error: error.message });
155
+ }
156
+ });
157
+
158
+ // 提交投票
159
+ router.post('/:id/vote', authenticate, async (req, res) => {
160
+ try {
161
+ const { selectedOptions } = req.body; // 选中的选项索引数组
162
+ const task = await Task.findById(req.params.id);
163
+
164
+ console.log('投票请求:', {
165
+ taskId: req.params.id,
166
+ userId: req.user.userId,
167
+ selectedOptions
168
+ });
169
+
170
+ if (!task) {
171
+ return res.status(404).json({ message: '任务不存在' });
172
+ }
173
+
174
+ if (task.type !== 'poll') {
175
+ return res.status(400).json({ message: '该任务不是投票任务' });
176
+ }
177
+
178
+ if (!task.pollData || !task.pollData.options) {
179
+ return res.status(400).json({ message: '投票数据不完整' });
180
+ }
181
+
182
+ // 检查用户是否已投票(转换为字符串比较)
183
+ const userIdStr = req.user.userId.toString();
184
+ const hasVoted = task.pollData.options.some(opt =>
185
+ opt.votes && opt.votes.some(voteId => voteId.toString() === userIdStr)
186
+ );
187
+
188
+ if (hasVoted) {
189
+ return res.status(400).json({ message: '您已经投过票了' });
190
+ }
191
+
192
+ // 验证选项索引
193
+ if (!Array.isArray(selectedOptions) || selectedOptions.length === 0) {
194
+ return res.status(400).json({ message: '请选择至少一个选项' });
195
+ }
196
+
197
+ // 添加投票
198
+ selectedOptions.forEach(optionIndex => {
199
+ if (task.pollData.options[optionIndex]) {
200
+ if (!task.pollData.options[optionIndex].votes) {
201
+ task.pollData.options[optionIndex].votes = [];
202
+ }
203
+ task.pollData.options[optionIndex].votes.push(req.user.userId);
204
+ }
205
+ });
206
+
207
+ // 更新总投票数
208
+ task.pollData.totalVotes = (task.pollData.totalVotes || 0) + 1;
209
+
210
+ // 自动标记任务为已完成
211
+ const alreadyCompleted = task.completedBy.some(
212
+ item => item.user.toString() === userIdStr
213
+ );
214
+
215
+ if (!alreadyCompleted) {
216
+ task.completedBy.push({
217
+ user: req.user.userId,
218
+ completedAt: new Date()
219
+ });
220
+ }
221
+
222
+ task.status = 'completed';
223
+
224
+ // 标记 pollData 为已修改
225
+ task.markModified('pollData');
226
+ await task.save();
227
+
228
+ console.log('投票成功:', {
229
+ taskId: task._id,
230
+ totalVotes: task.pollData.totalVotes
231
+ });
232
+
233
+ // 重新查询以填充用户信息
234
+ const updatedTask = await Task.findById(task._id)
235
+ .populate('creator', 'username avatar')
236
+ .populate('assignedTo', 'username avatar')
237
+ .populate('completedBy.user', 'username avatar')
238
+ .populate('group', 'name');
239
+
240
+ res.json({
241
+ success: true,
242
+ message: '投票成功',
243
+ task: updatedTask
244
+ });
245
+ } catch (error) {
246
+ console.error('投票失败:', error);
247
+ res.status(500).json({
248
+ success: false,
249
+ message: '投票失败',
250
+ error: error.message
251
+ });
252
+ }
253
+ });
254
+
255
+ export default router;
256
+
257
+