collabdocchat 2.4.4 → 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.
Files changed (79) hide show
  1. package/package.json +2 -2
  2. package/scripts/add-button-hover.js +2 -0
  3. package/scripts/add-missing-braces.js +27 -0
  4. package/scripts/add-missing-functions.js +2 -0
  5. package/scripts/add-more-features.js +2 -0
  6. package/scripts/add-user-functions.js +2 -0
  7. package/scripts/auto-publish.js +2 -0
  8. package/scripts/beautify-buttons.js +2 -0
  9. package/scripts/beautify-ui.js +2 -0
  10. package/scripts/check-brackets.js +50 -0
  11. package/scripts/check-encoding.js +2 -0
  12. package/scripts/check-syntax.js +2 -0
  13. package/scripts/delete-orphan-block.js +27 -0
  14. package/scripts/find-buttons.js +2 -0
  15. package/scripts/find-duplicate.js +2 -0
  16. package/scripts/find-extra-brace.js +63 -0
  17. package/scripts/find-sidebar-buttons.js +2 -0
  18. package/scripts/fix-file-end.js +46 -0
  19. package/scripts/fix-help.js +2 -0
  20. package/scripts/fix-issues-step1.js +2 -0
  21. package/scripts/fix-issues-step2.js +2 -0
  22. package/scripts/fix-issues-step3.js +2 -0
  23. package/scripts/fix-issues-step4.js +2 -0
  24. package/scripts/fix-optimized-views.js +2 -0
  25. package/scripts/fix-settings.js +2 -0
  26. package/scripts/fix-syntax-error.js +38 -0
  27. package/scripts/fix-workflow.js +2 -0
  28. package/scripts/refactor-step1.js +2 -0
  29. package/scripts/refactor-step2.js +2 -0
  30. package/scripts/refactor-step3.js +2 -0
  31. package/scripts/refactor-step4.js +2 -0
  32. package/scripts/refactor-step5.js +2 -0
  33. package/scripts/refactor-step6.js +2 -0
  34. package/scripts/refactor-step7.js +2 -0
  35. package/scripts/remove-orphan-code.js +57 -0
  36. package/scripts/update-port-user.js +2 -0
  37. package/scripts/update-port.js +2 -0
  38. package/server/index.js +4 -0
  39. package/server/index.js.bak +97 -0
  40. package/server/models/Document.js +5 -0
  41. package/server/models/KnowledgeBase.js +259 -254
  42. package/server/models/Poll.js +97 -0
  43. package/server/routes/ai.js +391 -327
  44. package/server/routes/audit.js +61 -0
  45. package/server/routes/documents.js +74 -5
  46. package/server/routes/export.js +171 -10
  47. package/server/routes/files.js +27 -4
  48. package/server/routes/knowledge.js +31 -22
  49. package/server/routes/messages.js +142 -0
  50. package/server/routes/polls.js +241 -0
  51. package/server/routes/tasks.js +1 -0
  52. package/server/routes/workflows.js +27 -0
  53. package/server/utils/auditLogger.js +268 -238
  54. package/src/pages/admin-dashboard.js +1431 -335
  55. package/src/pages/admin-dashboard.js.audit-optimize.bak +4134 -0
  56. package/src/pages/admin-dashboard.js.bak +4041 -0
  57. package/src/pages/admin-dashboard.js.broken.bak +4099 -0
  58. package/src/pages/admin-dashboard.js.comprehensive.bak +4099 -0
  59. package/src/pages/admin-dashboard.js.escape.bak +4099 -0
  60. package/src/pages/admin-dashboard.js.final-final-fix.bak +4099 -0
  61. package/src/pages/admin-dashboard.js.final-fix.bak +4099 -0
  62. package/src/pages/admin-dashboard.js.final.bak +4099 -0
  63. package/src/pages/admin-dashboard.js.indent-fix.bak +4099 -0
  64. package/src/pages/admin-dashboard.js.last-fix.bak +4099 -0
  65. package/src/pages/admin-dashboard.js.line595-fix.bak +4099 -0
  66. package/src/pages/admin-dashboard.js.pre-manual-fix.bak +4099 -0
  67. package/src/pages/admin-dashboard.js.syntax.bak +4099 -0
  68. package/src/pages/admin-dashboard.js.test.bak +4099 -0
  69. package/src/pages/optimized-task-detail-original.js +838 -0
  70. package/src/pages/optimized-task-detail.js +324 -22
  71. package/src/pages/optimized-task-detail.js.bak +1162 -0
  72. package/src/pages/poll-detail-enhanced.js +394 -0
  73. package/src/pages/update-poll-display.js +380 -0
  74. package/src/pages/user-dashboard.js +1860 -1006
  75. package/src/services/api.js +326 -265
  76. package/src/services/auth.js +54 -54
  77. package/src/services/websocket.js +88 -80
  78. package/src/pages/simplified-workflows.js +0 -652
  79. package/src/utils/ai-assistant.js +0 -1384
@@ -151,10 +151,22 @@ function renderOptimizedTaskDetail(task, container) {
151
151
  }
152
152
 
153
153
  // 渲染投票结果
154
+ // 渲染投票结果(增强版 - 显示投票成员详情)
154
155
  function renderPollResults(poll) {
155
156
  if (!poll || !poll.options) return '';
156
157
 
157
158
  const totalVotes = poll.options.reduce((sum, opt) => sum + (opt.votes || 0), 0);
159
+
160
+ // 获取所有已投票成员
161
+ const votedMembers = new Set();
162
+ poll.options.forEach(option => {
163
+ if (option.voters) {
164
+ option.voters.forEach(voter => {
165
+ const voterName = typeof voter === 'string' ? voter : voter.username;
166
+ votedMembers.add(voterName);
167
+ });
168
+ }
169
+ });
158
170
 
159
171
  return `
160
172
  <div class="task-poll-card-modern">
@@ -162,52 +174,116 @@ function renderPollResults(poll) {
162
174
  <span class="card-icon">📊</span> 投票结果
163
175
  </h3>
164
176
  <div class="poll-question-modern">${poll.question || '投票'}</div>
177
+
178
+ <!-- 投票统计摘要 -->
179
+ <div class="poll-stats-summary">
180
+ <div class="poll-stat-item">
181
+ <span class="poll-stat-icon">✅</span>
182
+ <span class="poll-stat-label">已投票:</span>
183
+ <span class="poll-stat-value">${votedMembers.size}人</span>
184
+ </div>
185
+ <div class="poll-stat-item">
186
+ <span class="poll-stat-icon">⏳</span>
187
+ <span class="poll-stat-label">未投票:</span>
188
+ <span class="poll-stat-value">${(poll.totalMembers || 0) - votedMembers.size}人</span>
189
+ </div>
190
+ <div class="poll-stat-item">
191
+ <span class="poll-stat-icon">📊</span>
192
+ <span class="poll-stat-label">总票数:</span>
193
+ <span class="poll-stat-value">${totalVotes}票</span>
194
+ </div>
195
+ </div>
196
+
197
+ <!-- 投票选项列表 -->
165
198
  <div class="poll-options-modern">
166
- ${poll.options.map(option => {
199
+ ${poll.options.map((option, index) => {
167
200
  const percentage = totalVotes > 0 ? Math.round((option.votes || 0) / totalVotes * 100) : 0;
201
+ const voters = option.voters || [];
168
202
  return `
169
203
  <div class="poll-option-modern">
170
204
  <div class="poll-option-header-modern">
171
205
  <span class="poll-option-text-modern">${option.text}</span>
172
- <span class="poll-option-count-modern">${option.votes || 0} �?(${percentage}%)</span>
206
+ <span class="poll-option-count-modern">${option.votes || 0} (${percentage}%)</span>
173
207
  </div>
174
208
  <div class="poll-option-bar-modern">
175
209
  <div class="poll-option-fill-modern" style="width: ${percentage}%"></div>
176
210
  </div>
211
+ ${voters.length > 0 ? `
212
+ <div class="poll-voters-list">
213
+ <div class="poll-voters-header">
214
+ <span class="poll-voters-icon">👥</span>
215
+ <span class="poll-voters-title">投票成员 (${voters.length}人):</span>
216
+ </div>
217
+ <div class="poll-voters-tags">
218
+ ${voters.map(voter => {
219
+ const voterName = typeof voter === 'string' ? voter : voter.username;
220
+ return `
221
+ <span class="poll-voter-tag">
222
+ <span class="voter-avatar">${voterName ? voterName[0].toUpperCase() : '?'}</span>
223
+ <span class="voter-name">${voterName || '未知用户'}</span>
224
+ </span>
225
+ `;
226
+ }).join('')}
227
+ </div>
228
+ </div>
229
+ ` : `
230
+ <div class="poll-voters-empty">
231
+ <span class="empty-icon">📭</span>
232
+ <span class="empty-text">暂无人投票</span>
233
+ </div>
234
+ `}
177
235
  </div>
178
236
  `;
179
237
  }).join('')}
180
238
  </div>
181
- <div class="poll-total-modern">总投票数: ${totalVotes}</div>
239
+
240
+ <!-- 未投票成员列表 -->
241
+ ${renderUnvotedMembers(poll, votedMembers)}
182
242
  </div>
183
243
  `;
184
244
  }
185
245
 
186
- // 渲染成员�?function renderMemberItem(member) {
187
- const isCompleted = member.completed || member.status === 'completed';
188
- const completedTime = member.completedAt ? new Date(member.completedAt).toLocaleString() : '未完�?;
189
-
190
- return `
191
- <div class="member-item-modern ${isCompleted ? 'completed' : 'pending'}">
192
- <div class="member-avatar-modern">
193
- ${member.username ? member.username[0].toUpperCase() : '?'}
194
- </div>
195
- <div class="member-info-modern">
196
- <div class="member-name-modern">${member.username || '未知用户'}</div>
197
- <div class="member-time-modern">
198
- ${isCompleted ? `�?${completedTime}` : '�?待完�?}
246
+ // 渲染未投票成员列表
247
+ function renderUnvotedMembers(poll, votedMembers) {
248
+ if (!poll.allMembers || poll.allMembers.length === 0) return '';
249
+
250
+ const unvotedMembers = poll.allMembers.filter(member => {
251
+ const memberName = typeof member === 'string' ? member : member.username;
252
+ return !votedMembers.has(memberName);
253
+ });
254
+
255
+ if (unvotedMembers.length === 0) {
256
+ return `
257
+ <div class="poll-unvoted-section all-voted">
258
+ <div class="poll-unvoted-header">
259
+ <span class="unvoted-icon">✅</span>
260
+ <span class="unvoted-title">所有成员已完成投票</span>
199
261
  </div>
200
262
  </div>
201
- <div class="member-status-modern">
202
- ${isCompleted ?
203
- '<span class="status-badge-small completed">已完�?/span>' :
204
- '<span class="status-badge-small pending">未完�?/span>'}
263
+ `;
264
+ }
265
+
266
+ return `
267
+ <div class="poll-unvoted-section">
268
+ <div class="poll-unvoted-header">
269
+ <span class="unvoted-icon">⚠️</span>
270
+ <span class="unvoted-title">未投票成员 (${unvotedMembers.length}人):</span>
271
+ </div>
272
+ <div class="poll-unvoted-list">
273
+ ${unvotedMembers.map(member => {
274
+ const memberName = typeof member === 'string' ? member : member.username;
275
+ return `
276
+ <span class="poll-unvoted-tag">
277
+ <span class="unvoted-avatar">${memberName ? memberName[0].toUpperCase() : '?'}</span>
278
+ <span class="unvoted-name">${memberName || '未知用户'}</span>
279
+ <span class="unvoted-status">未投票</span>
280
+ </span>
281
+ `;
282
+ }).join('')}
205
283
  </div>
206
284
  </div>
207
285
  `;
208
286
  }
209
-
210
- // 计算完成进度
211
287
  function calculateProgress(task) {
212
288
  if (!task.members || task.members.length === 0) return 0;
213
289
  const completed = task.completedCount || 0;
@@ -776,6 +852,232 @@ function addTaskDetailStyles() {
776
852
  font-size: 15px;
777
853
  }
778
854
 
855
+
856
+ /* ========== 投票详情增强样式 ========== */
857
+
858
+ /* 投票统计摘要 */
859
+ .poll-stats-summary {
860
+ display: grid;
861
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
862
+ gap: 12px;
863
+ margin-bottom: 24px;
864
+ padding: 16px;
865
+ background: linear-gradient(135deg, rgba(99,102,241,0.05) 0%, rgba(139,92,246,0.05) 100%);
866
+ border-radius: 12px;
867
+ border: 1px solid var(--border);
868
+ }
869
+
870
+ .poll-stat-item {
871
+ display: flex;
872
+ align-items: center;
873
+ gap: 8px;
874
+ padding: 12px;
875
+ background: var(--bg-dark);
876
+ border-radius: 8px;
877
+ border: 1px solid var(--border);
878
+ transition: all 0.3s ease;
879
+ }
880
+
881
+ .poll-stat-item:hover {
882
+ transform: translateY(-2px);
883
+ box-shadow: 0 4px 12px rgba(99,102,241,0.2);
884
+ border-color: var(--primary);
885
+ }
886
+
887
+ .poll-stat-icon {
888
+ font-size: 20px;
889
+ flex-shrink: 0;
890
+ }
891
+
892
+ .poll-stat-label {
893
+ font-size: 13px;
894
+ color: var(--text-secondary);
895
+ font-weight: 600;
896
+ }
897
+
898
+ .poll-stat-value {
899
+ font-size: 16px;
900
+ color: var(--text-primary);
901
+ font-weight: 700;
902
+ margin-left: auto;
903
+ }
904
+
905
+ /* 投票成员列表 */
906
+ .poll-voters-list {
907
+ margin-top: 16px;
908
+ padding-top: 16px;
909
+ border-top: 1px solid var(--border);
910
+ }
911
+
912
+ .poll-voters-header {
913
+ display: flex;
914
+ align-items: center;
915
+ gap: 8px;
916
+ margin-bottom: 12px;
917
+ font-size: 13px;
918
+ color: var(--text-secondary);
919
+ font-weight: 600;
920
+ }
921
+
922
+ .poll-voters-icon {
923
+ font-size: 16px;
924
+ }
925
+
926
+ .poll-voters-title {
927
+ flex: 1;
928
+ }
929
+
930
+ .poll-voters-tags {
931
+ display: flex;
932
+ flex-wrap: wrap;
933
+ gap: 8px;
934
+ }
935
+
936
+ .poll-voter-tag {
937
+ display: inline-flex;
938
+ align-items: center;
939
+ gap: 8px;
940
+ padding: 6px 12px;
941
+ background: linear-gradient(135deg, rgba(99,102,241,0.1) 0%, rgba(139,92,246,0.1) 100%);
942
+ border: 1px solid rgba(99,102,241,0.3);
943
+ border-radius: 20px;
944
+ transition: all 0.3s ease;
945
+ cursor: default;
946
+ }
947
+
948
+ .poll-voter-tag:hover {
949
+ background: linear-gradient(135deg, rgba(99,102,241,0.2) 0%, rgba(139,92,246,0.2) 100%);
950
+ border-color: var(--primary);
951
+ transform: scale(1.05);
952
+ }
953
+
954
+ .voter-avatar {
955
+ width: 24px;
956
+ height: 24px;
957
+ border-radius: 50%;
958
+ background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
959
+ display: flex;
960
+ align-items: center;
961
+ justify-content: center;
962
+ font-size: 12px;
963
+ font-weight: 700;
964
+ color: white;
965
+ flex-shrink: 0;
966
+ }
967
+
968
+ .voter-name {
969
+ font-size: 13px;
970
+ font-weight: 600;
971
+ color: var(--text-primary);
972
+ }
973
+
974
+ /* 空状态 */
975
+ .poll-voters-empty {
976
+ display: flex;
977
+ align-items: center;
978
+ justify-content: center;
979
+ gap: 8px;
980
+ padding: 16px;
981
+ margin-top: 12px;
982
+ background: rgba(239,68,68,0.05);
983
+ border: 1px dashed rgba(239,68,68,0.3);
984
+ border-radius: 8px;
985
+ color: var(--text-secondary);
986
+ font-size: 13px;
987
+ }
988
+
989
+ .empty-icon {
990
+ font-size: 18px;
991
+ }
992
+
993
+ .empty-text {
994
+ font-weight: 500;
995
+ }
996
+
997
+ /* 未投票成员区域 */
998
+ .poll-unvoted-section {
999
+ margin-top: 24px;
1000
+ padding: 20px;
1001
+ background: linear-gradient(135deg, rgba(239,68,68,0.05) 0%, rgba(220,38,38,0.05) 100%);
1002
+ border: 1px solid rgba(239,68,68,0.2);
1003
+ border-radius: 12px;
1004
+ }
1005
+
1006
+ .poll-unvoted-section.all-voted {
1007
+ background: linear-gradient(135deg, rgba(16,185,129,0.05) 0%, rgba(5,150,105,0.05) 100%);
1008
+ border-color: rgba(16,185,129,0.3);
1009
+ }
1010
+
1011
+ .poll-unvoted-header {
1012
+ display: flex;
1013
+ align-items: center;
1014
+ gap: 10px;
1015
+ margin-bottom: 16px;
1016
+ font-size: 15px;
1017
+ font-weight: 700;
1018
+ color: var(--text-primary);
1019
+ }
1020
+
1021
+ .unvoted-icon {
1022
+ font-size: 20px;
1023
+ }
1024
+
1025
+ .unvoted-title {
1026
+ flex: 1;
1027
+ }
1028
+
1029
+ .poll-unvoted-list {
1030
+ display: flex;
1031
+ flex-wrap: wrap;
1032
+ gap: 10px;
1033
+ }
1034
+
1035
+ .poll-unvoted-tag {
1036
+ display: inline-flex;
1037
+ align-items: center;
1038
+ gap: 8px;
1039
+ padding: 8px 14px;
1040
+ background: var(--bg-dark);
1041
+ border: 2px solid rgba(239,68,68,0.3);
1042
+ border-radius: 20px;
1043
+ transition: all 0.3s ease;
1044
+ cursor: default;
1045
+ }
1046
+
1047
+ .poll-unvoted-tag:hover {
1048
+ background: rgba(239,68,68,0.1);
1049
+ border-color: var(--danger);
1050
+ transform: scale(1.05);
1051
+ }
1052
+
1053
+ .unvoted-avatar {
1054
+ width: 28px;
1055
+ height: 28px;
1056
+ border-radius: 50%;
1057
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
1058
+ display: flex;
1059
+ align-items: center;
1060
+ justify-content: center;
1061
+ font-size: 13px;
1062
+ font-weight: 700;
1063
+ color: white;
1064
+ flex-shrink: 0;
1065
+ }
1066
+
1067
+ .unvoted-name {
1068
+ font-size: 14px;
1069
+ font-weight: 600;
1070
+ color: var(--text-primary);
1071
+ }
1072
+
1073
+ .unvoted-status {
1074
+ font-size: 11px;
1075
+ font-weight: 600;
1076
+ color: var(--danger);
1077
+ background: rgba(239,68,68,0.1);
1078
+ padding: 2px 8px;
1079
+ border-radius: 10px;
1080
+ }
779
1081
  @media (max-width: 768px) {
780
1082
  .task-detail-header-modern {
781
1083
  flex-direction: column;