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
@@ -0,0 +1,254 @@
1
+ import mongoose from 'mongoose';
2
+
3
+ const knowledgeBaseSchema = new mongoose.Schema({
4
+ title: {
5
+ type: String,
6
+ required: true,
7
+ trim: true
8
+ },
9
+ content: {
10
+ type: String,
11
+ required: true
12
+ },
13
+ category: {
14
+ type: String,
15
+ default: '未分类'
16
+ },
17
+ tags: [{
18
+ type: String,
19
+ trim: true
20
+ }],
21
+ author: {
22
+ type: mongoose.Schema.Types.ObjectId,
23
+ ref: 'User',
24
+ required: true
25
+ },
26
+ group: {
27
+ type: mongoose.Schema.Types.ObjectId,
28
+ ref: 'Group',
29
+ required: true
30
+ },
31
+ // 版本控制
32
+ versions: [{
33
+ content: String,
34
+ updatedBy: {
35
+ type: mongoose.Schema.Types.ObjectId,
36
+ ref: 'User'
37
+ },
38
+ updatedAt: {
39
+ type: Date,
40
+ default: Date.now
41
+ },
42
+ changeLog: String
43
+ }],
44
+ currentVersion: {
45
+ type: Number,
46
+ default: 1
47
+ },
48
+ // 是否为模板
49
+ isTemplate: {
50
+ type: Boolean,
51
+ default: false
52
+ },
53
+ // 访问统计
54
+ views: {
55
+ type: Number,
56
+ default: 0
57
+ },
58
+ // 点赞
59
+ likes: [{
60
+ type: mongoose.Schema.Types.ObjectId,
61
+ ref: 'User'
62
+ }],
63
+ // 收藏
64
+ favorites: [{
65
+ type: mongoose.Schema.Types.ObjectId,
66
+ ref: 'User'
67
+ }],
68
+ // 评论
69
+ comments: [{
70
+ user: {
71
+ type: mongoose.Schema.Types.ObjectId,
72
+ ref: 'User'
73
+ },
74
+ content: String,
75
+ createdAt: {
76
+ type: Date,
77
+ default: Date.now
78
+ }
79
+ }],
80
+ // 附件
81
+ attachments: [{
82
+ filename: String,
83
+ originalName: String,
84
+ path: String,
85
+ size: Number,
86
+ mimetype: String,
87
+ uploadedAt: {
88
+ type: Date,
89
+ default: Date.now
90
+ }
91
+ }],
92
+ // 简化的权限字段(用于前端)
93
+ permission: {
94
+ type: String,
95
+ enum: ['private', 'group', 'public'],
96
+ default: 'private'
97
+ },
98
+ // 权限设置(详细)
99
+ permissions: {
100
+ read: {
101
+ type: String,
102
+ enum: ['public', 'group', 'private'],
103
+ default: 'group'
104
+ },
105
+ write: {
106
+ type: String,
107
+ enum: ['author', 'admin', 'all'],
108
+ default: 'author'
109
+ }
110
+ },
111
+ // 状态
112
+ status: {
113
+ type: String,
114
+ enum: ['draft', 'published', 'archived'],
115
+ default: 'draft'
116
+ },
117
+ // 发布时间
118
+ publishedAt: Date,
119
+ // 归档时间
120
+ archivedAt: Date
121
+ }, {
122
+ timestamps: true
123
+ });
124
+
125
+ // 索引优化
126
+ knowledgeBaseSchema.index({ title: 'text', content: 'text', tags: 'text' });
127
+ knowledgeBaseSchema.index({ group: 1, status: 1 });
128
+ knowledgeBaseSchema.index({ author: 1, createdAt: -1 });
129
+ knowledgeBaseSchema.index({ category: 1 });
130
+ knowledgeBaseSchema.index({ tags: 1 });
131
+ knowledgeBaseSchema.index({ views: -1 });
132
+ knowledgeBaseSchema.index({ createdAt: -1 });
133
+
134
+ // 虚拟字段:点赞数
135
+ knowledgeBaseSchema.virtual('likesCount').get(function() {
136
+ return this.likes.length;
137
+ });
138
+
139
+ // 虚拟字段:收藏数
140
+ knowledgeBaseSchema.virtual('favoritesCount').get(function() {
141
+ return this.favorites.length;
142
+ });
143
+
144
+ // 虚拟字段:评论数
145
+ knowledgeBaseSchema.virtual('commentsCount').get(function() {
146
+ return this.comments.length;
147
+ });
148
+
149
+ // 保存前钩子:创建版本
150
+ knowledgeBaseSchema.pre('save', function(next) {
151
+ if (this.isModified('content') && !this.isNew) {
152
+ this.versions.push({
153
+ content: this.content,
154
+ updatedBy: this.author,
155
+ updatedAt: new Date(),
156
+ changeLog: '内容更新'
157
+ });
158
+ this.currentVersion += 1;
159
+ }
160
+ next();
161
+ });
162
+
163
+ // 实例方法:增加浏览量
164
+ knowledgeBaseSchema.methods.incrementViews = function() {
165
+ this.views += 1;
166
+ return this.save();
167
+ };
168
+
169
+ // 实例方法:点赞/取消点赞
170
+ knowledgeBaseSchema.methods.toggleLike = function(userId) {
171
+ const index = this.likes.indexOf(userId);
172
+ if (index > -1) {
173
+ this.likes.splice(index, 1);
174
+ } else {
175
+ this.likes.push(userId);
176
+ }
177
+ return this.save();
178
+ };
179
+
180
+ // 实例方法:收藏/取消收藏
181
+ knowledgeBaseSchema.methods.toggleFavorite = function(userId) {
182
+ const index = this.favorites.indexOf(userId);
183
+ if (index > -1) {
184
+ this.favorites.splice(index, 1);
185
+ } else {
186
+ this.favorites.push(userId);
187
+ }
188
+ return this.save();
189
+ };
190
+
191
+ // 实例方法:添加评论
192
+ knowledgeBaseSchema.methods.addComment = function(userId, content) {
193
+ this.comments.push({
194
+ user: userId,
195
+ content,
196
+ createdAt: new Date()
197
+ });
198
+ return this.save();
199
+ };
200
+
201
+ // 实例方法:发布
202
+ knowledgeBaseSchema.methods.publish = function() {
203
+ this.status = 'published';
204
+ this.publishedAt = new Date();
205
+ return this.save();
206
+ };
207
+
208
+ // 实例方法:归档
209
+ knowledgeBaseSchema.methods.archive = function() {
210
+ this.status = 'archived';
211
+ this.archivedAt = new Date();
212
+ return this.save();
213
+ };
214
+
215
+ // 静态方法:搜索
216
+ knowledgeBaseSchema.statics.search = function(query, options = {}) {
217
+ const { group, category, tags, status = 'published', limit = 20, skip = 0 } = options;
218
+
219
+ const searchQuery = {
220
+ $text: { $search: query },
221
+ status
222
+ };
223
+
224
+ if (group) searchQuery.group = group;
225
+ if (category) searchQuery.category = category;
226
+ if (tags && tags.length > 0) searchQuery.tags = { $in: tags };
227
+
228
+ return this.find(searchQuery)
229
+ .select({ score: { $meta: 'textScore' } })
230
+ .sort({ score: { $meta: 'textScore' } })
231
+ .limit(limit)
232
+ .skip(skip)
233
+ .populate('author', 'username avatar')
234
+ .populate('group', 'name');
235
+ };
236
+
237
+ // 静态方法:获取热门文档
238
+ knowledgeBaseSchema.statics.getPopular = function(groupId, limit = 10) {
239
+ return this.find({ group: groupId, status: 'published' })
240
+ .sort({ views: -1, likes: -1 })
241
+ .limit(limit)
242
+ .populate('author', 'username avatar');
243
+ };
244
+
245
+ // 静态方法:获取最新文档
246
+ knowledgeBaseSchema.statics.getRecent = function(groupId, limit = 10) {
247
+ return this.find({ group: groupId, status: 'published' })
248
+ .sort({ publishedAt: -1 })
249
+ .limit(limit)
250
+ .populate('author', 'username avatar');
251
+ };
252
+
253
+ export default mongoose.model('KnowledgeBase', knowledgeBaseSchema);
254
+
@@ -22,10 +22,53 @@ const messageSchema = new mongoose.Schema({
22
22
  timestamp: {
23
23
  type: Date,
24
24
  default: Date.now
25
+ },
26
+ // 消息撤回
27
+ isRecalled: {
28
+ type: Boolean,
29
+ default: false
30
+ },
31
+ recalledAt: {
32
+ type: Date
33
+ },
34
+ // @提及的用户
35
+ mentions: [{
36
+ type: mongoose.Schema.Types.ObjectId,
37
+ ref: 'User'
38
+ }],
39
+ // 已读状态
40
+ readBy: [{
41
+ user: {
42
+ type: mongoose.Schema.Types.ObjectId,
43
+ ref: 'User'
44
+ },
45
+ readAt: {
46
+ type: Date,
47
+ default: Date.now
48
+ }
49
+ }],
50
+ // 消息类型(文本、图片、文件等)
51
+ messageType: {
52
+ type: String,
53
+ enum: ['text', 'image', 'file', 'system'],
54
+ default: 'text'
55
+ },
56
+ // 附件信息(如果是文件消息)
57
+ attachment: {
58
+ fileId: mongoose.Schema.Types.ObjectId,
59
+ fileName: String,
60
+ fileSize: Number,
61
+ fileType: String
25
62
  }
26
63
  }, {
27
64
  timestamps: true
28
65
  });
29
66
 
67
+ // 索引优化
68
+ messageSchema.index({ group: 1, timestamp: -1 });
69
+ messageSchema.index({ sender: 1, timestamp: -1 });
70
+ messageSchema.index({ timestamp: -1 });
71
+ messageSchema.index({ content: 'text' }); // 全文搜索
72
+
30
73
  export default mongoose.model('Message', messageSchema);
31
74
 
@@ -1,55 +1,87 @@
1
- import mongoose from 'mongoose';
2
-
3
- const taskSchema = new mongoose.Schema({
4
- title: {
5
- type: String,
6
- required: true,
7
- trim: true
8
- },
9
- description: {
10
- type: String,
11
- default: ''
12
- },
13
- group: {
14
- type: mongoose.Schema.Types.ObjectId,
15
- ref: 'Group',
16
- required: true
17
- },
18
- creator: {
19
- type: mongoose.Schema.Types.ObjectId,
20
- ref: 'User',
21
- required: true
22
- },
23
- assignedTo: [{
24
- type: mongoose.Schema.Types.ObjectId,
25
- ref: 'User'
26
- }],
27
- relatedDocument: {
28
- type: mongoose.Schema.Types.ObjectId,
29
- ref: 'Document'
30
- },
31
- status: {
32
- type: String,
33
- enum: ['pending', 'in_progress', 'completed', 'terminated'],
34
- default: 'pending'
35
- },
36
- deadline: {
37
- type: Date
38
- },
39
- completedBy: [{
40
- user: {
41
- type: mongoose.Schema.Types.ObjectId,
42
- ref: 'User'
43
- },
44
- completedAt: {
45
- type: Date,
46
- default: Date.now
47
- }
48
- }]
49
- }, {
50
- timestamps: true
51
- });
52
-
53
- export default mongoose.model('Task', taskSchema);
54
-
55
-
1
+ import mongoose from 'mongoose';
2
+
3
+ const taskSchema = new mongoose.Schema({
4
+ title: {
5
+ type: String,
6
+ required: true,
7
+ trim: true
8
+ },
9
+ description: {
10
+ type: String,
11
+ default: ''
12
+ },
13
+ group: {
14
+ type: mongoose.Schema.Types.ObjectId,
15
+ ref: 'Group',
16
+ required: true
17
+ },
18
+ creator: {
19
+ type: mongoose.Schema.Types.ObjectId,
20
+ ref: 'User',
21
+ required: true
22
+ },
23
+ assignedTo: [{
24
+ type: mongoose.Schema.Types.ObjectId,
25
+ ref: 'User'
26
+ }],
27
+ relatedDocument: {
28
+ type: mongoose.Schema.Types.ObjectId,
29
+ ref: 'Document'
30
+ },
31
+ status: {
32
+ type: String,
33
+ enum: ['pending', 'in_progress', 'completed', 'terminated'],
34
+ default: 'pending'
35
+ },
36
+ deadline: {
37
+ type: Date
38
+ },
39
+ completedBy: [{
40
+ user: {
41
+ type: mongoose.Schema.Types.ObjectId,
42
+ ref: 'User'
43
+ },
44
+ completedAt: {
45
+ type: Date,
46
+ default: Date.now
47
+ }
48
+ }],
49
+ // 投票任务相关字段
50
+ type: {
51
+ type: String,
52
+ enum: ['normal', 'poll'],
53
+ default: 'normal'
54
+ },
55
+ pollData: {
56
+ question: String,
57
+ options: [{
58
+ text: String,
59
+ votes: [{
60
+ type: mongoose.Schema.Types.ObjectId,
61
+ ref: 'User'
62
+ }]
63
+ }],
64
+ allowMultiple: {
65
+ type: Boolean,
66
+ default: false
67
+ },
68
+ totalVotes: {
69
+ type: Number,
70
+ default: 0
71
+ }
72
+ }
73
+ }, {
74
+ timestamps: true
75
+ });
76
+
77
+ // 索引优化
78
+ taskSchema.index({ group: 1, status: 1, createdAt: -1 });
79
+ taskSchema.index({ creator: 1, createdAt: -1 });
80
+ taskSchema.index({ assignedTo: 1, status: 1 });
81
+ taskSchema.index({ deadline: 1, status: 1 });
82
+ taskSchema.index({ status: 1, updatedAt: -1 });
83
+ taskSchema.index({ title: 'text', description: 'text' }); // 全文搜索
84
+
85
+ export default mongoose.model('Task', taskSchema);
86
+
87
+
@@ -1,60 +1,67 @@
1
- import mongoose from 'mongoose';
2
- import bcrypt from 'bcryptjs';
3
-
4
- const userSchema = new mongoose.Schema({
5
- username: {
6
- type: String,
7
- required: true,
8
- unique: true,
9
- trim: true
10
- },
11
- email: {
12
- type: String,
13
- required: true,
14
- unique: true,
15
- lowercase: true
16
- },
17
- password: {
18
- type: String,
19
- required: true
20
- },
21
- role: {
22
- type: String,
23
- enum: ['admin', 'user'],
24
- default: 'user'
25
- },
26
- avatar: {
27
- type: String,
28
- default: ''
29
- },
30
- groups: [{
31
- type: mongoose.Schema.Types.ObjectId,
32
- ref: 'Group'
33
- }],
34
- isOnline: {
35
- type: Boolean,
36
- default: false
37
- },
38
- lastSeen: {
39
- type: Date,
40
- default: Date.now
41
- }
42
- }, {
43
- timestamps: true
44
- });
45
-
46
- // 密码加密
47
- userSchema.pre('save', async function(next) {
48
- if (!this.isModified('password')) return next();
49
- this.password = await bcrypt.hash(this.password, 10);
50
- next();
51
- });
52
-
53
- // 密码验证
54
- userSchema.methods.comparePassword = async function(candidatePassword) {
55
- return await bcrypt.compare(candidatePassword, this.password);
56
- };
57
-
58
- export default mongoose.model('User', userSchema);
59
-
60
-
1
+ import mongoose from 'mongoose';
2
+ import bcrypt from 'bcryptjs';
3
+
4
+ const userSchema = new mongoose.Schema({
5
+ username: {
6
+ type: String,
7
+ required: true,
8
+ unique: true,
9
+ trim: true
10
+ },
11
+ email: {
12
+ type: String,
13
+ required: true,
14
+ unique: true,
15
+ lowercase: true
16
+ },
17
+ password: {
18
+ type: String,
19
+ required: true
20
+ },
21
+ role: {
22
+ type: String,
23
+ enum: ['admin', 'user'],
24
+ default: 'user'
25
+ },
26
+ avatar: {
27
+ type: String,
28
+ default: ''
29
+ },
30
+ groups: [{
31
+ type: mongoose.Schema.Types.ObjectId,
32
+ ref: 'Group'
33
+ }],
34
+ isOnline: {
35
+ type: Boolean,
36
+ default: false
37
+ },
38
+ lastSeen: {
39
+ type: Date,
40
+ default: Date.now
41
+ }
42
+ }, {
43
+ timestamps: true
44
+ });
45
+
46
+ // 密码加密
47
+ userSchema.pre('save', async function(next) {
48
+ if (!this.isModified('password')) return next();
49
+ this.password = await bcrypt.hash(this.password, 10);
50
+ next();
51
+ });
52
+
53
+ // 密码验证
54
+ userSchema.methods.comparePassword = async function(candidatePassword) {
55
+ return await bcrypt.compare(candidatePassword, this.password);
56
+ };
57
+
58
+ // 索引优化
59
+ userSchema.index({ username: 1 }, { unique: true });
60
+ userSchema.index({ email: 1 }, { unique: true });
61
+ userSchema.index({ createdAt: -1 });
62
+ userSchema.index({ isOnline: 1, lastSeen: -1 });
63
+ userSchema.index({ role: 1 });
64
+
65
+ export default mongoose.model('User', userSchema);
66
+
67
+