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.
- package/README.md +219 -218
- package/index.html +2 -0
- package/install-and-start.bat +5 -0
- package/install-and-start.sh +5 -0
- package/package.json +9 -2
- package/scripts/pre-publish-check.js +213 -0
- package/scripts/start-app.js +15 -15
- package/server/index.js +38 -6
- package/server/middleware/cache.js +115 -0
- package/server/middleware/errorHandler.js +209 -0
- package/server/models/Document.js +66 -59
- package/server/models/File.js +49 -43
- package/server/models/Group.js +6 -0
- package/server/models/KnowledgeBase.js +254 -0
- package/server/models/Message.js +43 -0
- package/server/models/Task.js +87 -55
- package/server/models/User.js +67 -60
- package/server/models/Workflow.js +249 -0
- package/server/routes/ai.js +327 -0
- package/server/routes/audit.js +245 -210
- package/server/routes/backup.js +108 -0
- package/server/routes/chunked-upload.js +343 -0
- package/server/routes/export.js +440 -0
- package/server/routes/files.js +294 -218
- package/server/routes/groups.js +182 -0
- package/server/routes/knowledge.js +509 -0
- package/server/routes/tasks.js +257 -110
- package/server/routes/workflows.js +380 -0
- package/server/utils/backup.js +439 -0
- package/server/utils/cache.js +223 -0
- package/server/utils/workflow-engine.js +479 -0
- package/server/websocket/enhanced.js +509 -0
- package/server/websocket/index.js +233 -1
- package/src/components/knowledge-modal.js +485 -0
- package/src/components/optimized-poll-detail.js +724 -0
- package/src/main.js +5 -0
- package/src/pages/admin-dashboard.js +2248 -44
- package/src/pages/optimized-backup-view.js +616 -0
- package/src/pages/optimized-knowledge-view.js +803 -0
- package/src/pages/optimized-task-detail.js +843 -0
- package/src/pages/optimized-workflow-view.js +806 -0
- package/src/pages/simplified-workflows.js +651 -0
- package/src/pages/user-dashboard.js +677 -58
- package/src/services/api.js +65 -1
- package/src/services/auth.js +1 -1
- package/src/services/websocket.js +124 -16
- package/src/styles/collaboration-modern.js +708 -0
- package/src/styles/enhancements.css +392 -0
- package/src/styles/main.css +620 -1420
- package/src/styles/responsive.css +1000 -0
- package/src/styles/sidebar-fix.css +60 -0
- package/src/utils/ai-assistant.js +1398 -0
- package/src/utils/chat-enhancements.js +509 -0
- package/src/utils/collaboration-enhancer.js +1151 -0
- package/src/utils/feature-integrator.js +1724 -0
- package/src/utils/onboarding-guide.js +734 -0
- package/src/utils/performance.js +394 -0
- package/src/utils/permission-manager.js +890 -0
- package/src/utils/responsive-handler.js +491 -0
- package/src/utils/theme-manager.js +811 -0
- package/src/utils/ui-enhancements-loader.js +329 -0
- package/USAGE.md +0 -298
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
// 简化的工作流视图 - 为非技术用户设计
|
|
2
|
+
// 替换原有的复杂 JSON 配置方式
|
|
3
|
+
|
|
4
|
+
async function renderSimplifiedWorkflowsView(container) {
|
|
5
|
+
if (!currentGroup) {
|
|
6
|
+
container.innerHTML = '<div class="empty-state">请先选择一个群组</div>';
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const token = localStorage.getItem('token');
|
|
12
|
+
const response = await fetch(`http://localhost:8765/api/workflows/group/${currentGroup._id}`, {
|
|
13
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
14
|
+
});
|
|
15
|
+
const result = await response.json();
|
|
16
|
+
const workflows = (result.data && result.data.workflows) || [];
|
|
17
|
+
|
|
18
|
+
container.innerHTML = `
|
|
19
|
+
<div class="view-header">
|
|
20
|
+
<h2>🔄 工作流管理 - ${currentGroup.name}</h2>
|
|
21
|
+
<button class="btn-primary" id="createSimpleWorkflowBtn">+ 创建工作流</button>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="workflow-templates" style="margin-bottom: 30px;">
|
|
25
|
+
<h3 style="margin-bottom: 15px; color: var(--text-primary);">📋 快速创建模板</h3>
|
|
26
|
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px;">
|
|
27
|
+
<div class="template-card" data-template="task-reminder">
|
|
28
|
+
<div class="template-icon">⏰</div>
|
|
29
|
+
<h4>任务提醒</h4>
|
|
30
|
+
<p>定时提醒成员完成任务</p>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="template-card" data-template="daily-report">
|
|
33
|
+
<div class="template-icon">📊</div>
|
|
34
|
+
<h4>每日报告</h4>
|
|
35
|
+
<p>每天自动生成工作报告</p>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="template-card" data-template="doc-approval">
|
|
38
|
+
<div class="template-icon">✅</div>
|
|
39
|
+
<h4>文档审批</h4>
|
|
40
|
+
<p>文档创建后自动通知审批</p>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="template-card" data-template="welcome-message">
|
|
43
|
+
<div class="template-icon">👋</div>
|
|
44
|
+
<h4>欢迎消息</h4>
|
|
45
|
+
<p>新成员加入时自动发送欢迎</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="workflows-list" id="workflowsList">
|
|
51
|
+
${workflows.length === 0 ?
|
|
52
|
+
'<div class="empty-state">暂无工作流<br><small style="color: var(--text-secondary);">点击上方模板快速创建</small></div>' :
|
|
53
|
+
workflows.map(wf => createWorkflowCard(wf)).join('')
|
|
54
|
+
}
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- 简化的工作流创建模态框 -->
|
|
58
|
+
<div class="modal hidden" id="simpleWorkflowModal">
|
|
59
|
+
<div class="modal-content" style="max-width: 600px;">
|
|
60
|
+
<div class="modal-header">
|
|
61
|
+
<h3 id="workflowModalTitle">创建工作流</h3>
|
|
62
|
+
<button class="close-btn" id="closeWorkflowModal">×</button>
|
|
63
|
+
</div>
|
|
64
|
+
<form id="simpleWorkflowForm">
|
|
65
|
+
<div class="form-group">
|
|
66
|
+
<label>工作流名称 *</label>
|
|
67
|
+
<input type="text" id="wfName" required placeholder="例如:每日任务提醒">
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="form-group">
|
|
71
|
+
<label>描述</label>
|
|
72
|
+
<textarea id="wfDescription" rows="2" placeholder="简单描述这个工作流的作用"></textarea>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div class="form-group">
|
|
76
|
+
<label>触发方式 *</label>
|
|
77
|
+
<select id="wfTriggerType" required>
|
|
78
|
+
<option value="">请选择触发方式</option>
|
|
79
|
+
<option value="manual">手动触发 - 需要手动点击执行</option>
|
|
80
|
+
<option value="daily">每天执行 - 每天固定时间自动执行</option>
|
|
81
|
+
<option value="weekly">每周执行 - 每周固定时间自动执行</option>
|
|
82
|
+
<option value="event">事件触发 - 特定事件发生时执行</option>
|
|
83
|
+
</select>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<!-- 每日执行选项 -->
|
|
87
|
+
<div class="form-group hidden" id="dailyOptions">
|
|
88
|
+
<label>执行时间</label>
|
|
89
|
+
<input type="time" id="dailyTime" value="09:00">
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<!-- 每周执行选项 -->
|
|
93
|
+
<div class="form-group hidden" id="weeklyOptions">
|
|
94
|
+
<label>执行日期</label>
|
|
95
|
+
<select id="weeklyDay">
|
|
96
|
+
<option value="1">星期一</option>
|
|
97
|
+
<option value="2">星期二</option>
|
|
98
|
+
<option value="3">星期三</option>
|
|
99
|
+
<option value="4">星期四</option>
|
|
100
|
+
<option value="5">星期五</option>
|
|
101
|
+
<option value="6">星期六</option>
|
|
102
|
+
<option value="0">星期日</option>
|
|
103
|
+
</select>
|
|
104
|
+
<input type="time" id="weeklyTime" value="09:00" style="margin-top: 10px;">
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<!-- 事件触发选项 -->
|
|
108
|
+
<div class="form-group hidden" id="eventOptions">
|
|
109
|
+
<label>触发事件</label>
|
|
110
|
+
<select id="eventType">
|
|
111
|
+
<option value="task_created">任务创建时</option>
|
|
112
|
+
<option value="task_completed">任务完成时</option>
|
|
113
|
+
<option value="doc_created">文档创建时</option>
|
|
114
|
+
<option value="member_joined">成员加入时</option>
|
|
115
|
+
</select>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="form-group">
|
|
119
|
+
<label>执行动作 *</label>
|
|
120
|
+
<select id="wfActionType" required>
|
|
121
|
+
<option value="">请选择执行动作</option>
|
|
122
|
+
<option value="send_notification">发送通知</option>
|
|
123
|
+
<option value="send_message">发送消息</option>
|
|
124
|
+
<option value="create_task">创建任务</option>
|
|
125
|
+
<option value="send_email">发送邮件</option>
|
|
126
|
+
</select>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<!-- 发送通知选项 -->
|
|
130
|
+
<div class="form-group hidden" id="notificationOptions">
|
|
131
|
+
<label>通知内容</label>
|
|
132
|
+
<textarea id="notificationContent" rows="3" placeholder="输入要发送的通知内容"></textarea>
|
|
133
|
+
<label style="margin-top: 10px;">通知对象</label>
|
|
134
|
+
<select id="notificationTarget">
|
|
135
|
+
<option value="all">所有成员</option>
|
|
136
|
+
<option value="admin">仅管理员</option>
|
|
137
|
+
<option value="creator">任务创建者</option>
|
|
138
|
+
</select>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- 发送消息选项 -->
|
|
142
|
+
<div class="form-group hidden" id="messageOptions">
|
|
143
|
+
<label>消息内容</label>
|
|
144
|
+
<textarea id="messageContent" rows="3" placeholder="输入要发送的消息内容"></textarea>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- 创建任务选项 -->
|
|
148
|
+
<div class="form-group hidden" id="taskOptions">
|
|
149
|
+
<label>任务标题</label>
|
|
150
|
+
<input type="text" id="taskTitle" placeholder="例如:完成每日报告">
|
|
151
|
+
<label style="margin-top: 10px;">任务描述</label>
|
|
152
|
+
<textarea id="taskDescription" rows="2" placeholder="任务的详细说明"></textarea>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<!-- 发送邮件选项 -->
|
|
156
|
+
<div class="form-group hidden" id="emailOptions">
|
|
157
|
+
<label>邮件主题</label>
|
|
158
|
+
<input type="text" id="emailSubject" placeholder="邮件主题">
|
|
159
|
+
<label style="margin-top: 10px;">邮件内容</label>
|
|
160
|
+
<textarea id="emailContent" rows="3" placeholder="邮件正文"></textarea>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
|
164
|
+
<button type="submit" class="btn-primary">创建工作流</button>
|
|
165
|
+
<button type="button" class="btn-secondary" id="cancelWorkflow">取消</button>
|
|
166
|
+
</div>
|
|
167
|
+
</form>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
`;
|
|
171
|
+
|
|
172
|
+
// 添加模板卡片样式
|
|
173
|
+
const style = document.createElement('style');
|
|
174
|
+
style.textContent = `
|
|
175
|
+
.template-card {
|
|
176
|
+
background: linear-gradient(135deg, var(--bg-card) 0%, rgba(99,102,241,0.05) 100%);
|
|
177
|
+
border: 2px solid var(--border);
|
|
178
|
+
border-radius: 12px;
|
|
179
|
+
padding: 20px;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
transition: all 0.3s ease;
|
|
182
|
+
text-align: center;
|
|
183
|
+
}
|
|
184
|
+
.template-card:hover {
|
|
185
|
+
border-color: var(--primary);
|
|
186
|
+
transform: translateY(-5px);
|
|
187
|
+
box-shadow: 0 8px 24px rgba(99,102,241,0.2);
|
|
188
|
+
}
|
|
189
|
+
.template-icon {
|
|
190
|
+
font-size: 48px;
|
|
191
|
+
margin-bottom: 10px;
|
|
192
|
+
}
|
|
193
|
+
.template-card h4 {
|
|
194
|
+
margin: 10px 0 5px;
|
|
195
|
+
color: var(--text-primary);
|
|
196
|
+
font-size: 16px;
|
|
197
|
+
}
|
|
198
|
+
.template-card p {
|
|
199
|
+
margin: 0;
|
|
200
|
+
color: var(--text-secondary);
|
|
201
|
+
font-size: 13px;
|
|
202
|
+
}
|
|
203
|
+
.workflow-card {
|
|
204
|
+
background: var(--bg-card);
|
|
205
|
+
border: 1px solid var(--border);
|
|
206
|
+
border-radius: 12px;
|
|
207
|
+
padding: 20px;
|
|
208
|
+
margin-bottom: 15px;
|
|
209
|
+
transition: all 0.3s ease;
|
|
210
|
+
}
|
|
211
|
+
.workflow-card:hover {
|
|
212
|
+
border-color: var(--primary);
|
|
213
|
+
transform: translateX(5px);
|
|
214
|
+
}
|
|
215
|
+
.wf-header {
|
|
216
|
+
display: flex;
|
|
217
|
+
justify-content: space-between;
|
|
218
|
+
align-items: center;
|
|
219
|
+
margin-bottom: 10px;
|
|
220
|
+
}
|
|
221
|
+
.wf-status {
|
|
222
|
+
padding: 4px 12px;
|
|
223
|
+
border-radius: 12px;
|
|
224
|
+
font-size: 12px;
|
|
225
|
+
font-weight: 600;
|
|
226
|
+
}
|
|
227
|
+
.wf-status.active {
|
|
228
|
+
background: rgba(16,185,129,0.2);
|
|
229
|
+
color: var(--success);
|
|
230
|
+
}
|
|
231
|
+
.wf-status.inactive {
|
|
232
|
+
background: rgba(156,163,175,0.2);
|
|
233
|
+
color: var(--text-secondary);
|
|
234
|
+
}
|
|
235
|
+
.wf-meta {
|
|
236
|
+
display: flex;
|
|
237
|
+
gap: 15px;
|
|
238
|
+
margin: 10px 0;
|
|
239
|
+
font-size: 13px;
|
|
240
|
+
color: var(--text-secondary);
|
|
241
|
+
}
|
|
242
|
+
.wf-actions {
|
|
243
|
+
display: flex;
|
|
244
|
+
gap: 8px;
|
|
245
|
+
margin-top: 15px;
|
|
246
|
+
}
|
|
247
|
+
`;
|
|
248
|
+
document.head.appendChild(style);
|
|
249
|
+
|
|
250
|
+
// 创建工作流卡片
|
|
251
|
+
function createWorkflowCard(wf) {
|
|
252
|
+
const triggerText = getTriggerText(wf.trigger);
|
|
253
|
+
const actionText = getActionText(wf.steps);
|
|
254
|
+
|
|
255
|
+
return `
|
|
256
|
+
<div class="workflow-card">
|
|
257
|
+
<div class="wf-header">
|
|
258
|
+
<h3>${wf.name}</h3>
|
|
259
|
+
<span class="wf-status ${wf.status}">${wf.status === 'active' ? '✅ 已激活' : '⏸️ 已停用'}</span>
|
|
260
|
+
</div>
|
|
261
|
+
<p style="color: var(--text-secondary); margin: 10px 0;">${wf.description || '暂无描述'}</p>
|
|
262
|
+
<div class="wf-meta">
|
|
263
|
+
<span>🔔 ${triggerText}</span>
|
|
264
|
+
<span>⚡ ${actionText}</span>
|
|
265
|
+
<span>📊 执行 ${wf.stats?.totalExecutions || 0} 次</span>
|
|
266
|
+
</div>
|
|
267
|
+
<div class="wf-actions">
|
|
268
|
+
${wf.status === 'active' ? `
|
|
269
|
+
<button class="btn-secondary btn-sm" data-id="${wf._id}" data-action="trigger-wf">立即执行</button>
|
|
270
|
+
<button class="btn-warning btn-sm" data-id="${wf._id}" data-action="deactivate-wf">停用</button>
|
|
271
|
+
` : `
|
|
272
|
+
<button class="btn-success btn-sm" data-id="${wf._id}" data-action="activate-wf">激活</button>
|
|
273
|
+
`}
|
|
274
|
+
<button class="btn-secondary btn-sm" data-id="${wf._id}" data-action="edit-wf">编辑</button>
|
|
275
|
+
<button class="btn-danger btn-sm" data-id="${wf._id}" data-action="delete-wf">删除</button>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 获取触发方式文本
|
|
282
|
+
function getTriggerText(trigger) {
|
|
283
|
+
if (!trigger) return '手动触发';
|
|
284
|
+
if (trigger.type === 'manual') return '手动触发';
|
|
285
|
+
if (trigger.type === 'scheduled') return '定时执行';
|
|
286
|
+
if (trigger.type === 'event') return '事件触发';
|
|
287
|
+
return '未知';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 获取动作文本
|
|
291
|
+
function getActionText(steps) {
|
|
292
|
+
if (!steps || steps.length === 0) return '无动作';
|
|
293
|
+
const firstStep = steps[0];
|
|
294
|
+
if (firstStep.type === 'notification') return '发送通知';
|
|
295
|
+
if (firstStep.type === 'message') return '发送消息';
|
|
296
|
+
if (firstStep.type === 'task') return '创建任务';
|
|
297
|
+
if (firstStep.type === 'email') return '发送邮件';
|
|
298
|
+
return `${steps.length} 个步骤`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 模板卡片点击事件
|
|
302
|
+
document.querySelectorAll('.template-card').forEach(card => {
|
|
303
|
+
card.addEventListener('click', () => {
|
|
304
|
+
const template = card.dataset.template;
|
|
305
|
+
openWorkflowModalWithTemplate(template);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// 创建工作流按钮
|
|
310
|
+
document.getElementById('createSimpleWorkflowBtn').addEventListener('click', () => {
|
|
311
|
+
openWorkflowModal();
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// 工作流操作事件
|
|
315
|
+
setupWorkflowActions(token);
|
|
316
|
+
|
|
317
|
+
} catch (error) {
|
|
318
|
+
console.error('加载工作流失败:', error);
|
|
319
|
+
container.innerHTML = `
|
|
320
|
+
<div class="view-header">
|
|
321
|
+
<h2>🔄 工作流管理</h2>
|
|
322
|
+
</div>
|
|
323
|
+
<div class="empty-state">加载失败: ${error.message}</div>
|
|
324
|
+
`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// 打开工作流模态框
|
|
329
|
+
function openWorkflowModal(workflow = null) {
|
|
330
|
+
const modal = document.getElementById('simpleWorkflowModal');
|
|
331
|
+
const form = document.getElementById('simpleWorkflowForm');
|
|
332
|
+
|
|
333
|
+
// 重置表单
|
|
334
|
+
form.reset();
|
|
335
|
+
hideAllOptions();
|
|
336
|
+
|
|
337
|
+
// 如果是编辑模式,填充数据
|
|
338
|
+
if (workflow) {
|
|
339
|
+
document.getElementById('workflowModalTitle').textContent = '编辑工作流';
|
|
340
|
+
document.getElementById('wfName').value = workflow.name;
|
|
341
|
+
document.getElementById('wfDescription').value = workflow.description || '';
|
|
342
|
+
// ... 填充其他字段
|
|
343
|
+
} else {
|
|
344
|
+
document.getElementById('workflowModalTitle').textContent = '创建工作流';
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
modal.classList.remove('hidden');
|
|
348
|
+
|
|
349
|
+
// 设置事件监听
|
|
350
|
+
setupModalEvents();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// 使用模板打开模态框
|
|
354
|
+
function openWorkflowModalWithTemplate(templateType) {
|
|
355
|
+
openWorkflowModal();
|
|
356
|
+
|
|
357
|
+
const templates = {
|
|
358
|
+
'task-reminder': {
|
|
359
|
+
name: '任务提醒',
|
|
360
|
+
description: '每天早上9点提醒成员完成待办任务',
|
|
361
|
+
trigger: 'daily',
|
|
362
|
+
action: 'send_notification'
|
|
363
|
+
},
|
|
364
|
+
'daily-report': {
|
|
365
|
+
name: '每日报告',
|
|
366
|
+
description: '每天下午6点自动生成工作报告',
|
|
367
|
+
trigger: 'daily',
|
|
368
|
+
action: 'send_message'
|
|
369
|
+
},
|
|
370
|
+
'doc-approval': {
|
|
371
|
+
name: '文档审批',
|
|
372
|
+
description: '文档创建后自动通知管理员审批',
|
|
373
|
+
trigger: 'event',
|
|
374
|
+
action: 'send_notification'
|
|
375
|
+
},
|
|
376
|
+
'welcome-message': {
|
|
377
|
+
name: '欢迎消息',
|
|
378
|
+
description: '新成员加入时自动发送欢迎消息',
|
|
379
|
+
trigger: 'event',
|
|
380
|
+
action: 'send_message'
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const template = templates[templateType];
|
|
385
|
+
if (template) {
|
|
386
|
+
document.getElementById('wfName').value = template.name;
|
|
387
|
+
document.getElementById('wfDescription').value = template.description;
|
|
388
|
+
document.getElementById('wfTriggerType').value = template.trigger;
|
|
389
|
+
document.getElementById('wfActionType').value = template.action;
|
|
390
|
+
|
|
391
|
+
// 触发change事件以显示相应选项
|
|
392
|
+
document.getElementById('wfTriggerType').dispatchEvent(new Event('change'));
|
|
393
|
+
document.getElementById('wfActionType').dispatchEvent(new Event('change'));
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// 设置模态框事件
|
|
398
|
+
function setupModalEvents() {
|
|
399
|
+
const triggerSelect = document.getElementById('wfTriggerType');
|
|
400
|
+
const actionSelect = document.getElementById('wfActionType');
|
|
401
|
+
|
|
402
|
+
// 触发方式改变
|
|
403
|
+
triggerSelect.addEventListener('change', () => {
|
|
404
|
+
hideAllTriggerOptions();
|
|
405
|
+
const value = triggerSelect.value;
|
|
406
|
+
if (value === 'daily') {
|
|
407
|
+
document.getElementById('dailyOptions').classList.remove('hidden');
|
|
408
|
+
} else if (value === 'weekly') {
|
|
409
|
+
document.getElementById('weeklyOptions').classList.remove('hidden');
|
|
410
|
+
} else if (value === 'event') {
|
|
411
|
+
document.getElementById('eventOptions').classList.remove('hidden');
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// 执行动作改变
|
|
416
|
+
actionSelect.addEventListener('change', () => {
|
|
417
|
+
hideAllActionOptions();
|
|
418
|
+
const value = actionSelect.value;
|
|
419
|
+
if (value === 'send_notification') {
|
|
420
|
+
document.getElementById('notificationOptions').classList.remove('hidden');
|
|
421
|
+
} else if (value === 'send_message') {
|
|
422
|
+
document.getElementById('messageOptions').classList.remove('hidden');
|
|
423
|
+
} else if (value === 'create_task') {
|
|
424
|
+
document.getElementById('taskOptions').classList.remove('hidden');
|
|
425
|
+
} else if (value === 'send_email') {
|
|
426
|
+
document.getElementById('emailOptions').classList.remove('hidden');
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// 关闭按钮
|
|
431
|
+
document.getElementById('closeWorkflowModal').addEventListener('click', () => {
|
|
432
|
+
document.getElementById('simpleWorkflowModal').classList.add('hidden');
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
document.getElementById('cancelWorkflow').addEventListener('click', () => {
|
|
436
|
+
document.getElementById('simpleWorkflowModal').classList.add('hidden');
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// 表单提交
|
|
440
|
+
document.getElementById('simpleWorkflowForm').addEventListener('submit', handleWorkflowSubmit);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// 隐藏所有选项
|
|
444
|
+
function hideAllOptions() {
|
|
445
|
+
hideAllTriggerOptions();
|
|
446
|
+
hideAllActionOptions();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function hideAllTriggerOptions() {
|
|
450
|
+
document.getElementById('dailyOptions').classList.add('hidden');
|
|
451
|
+
document.getElementById('weeklyOptions').classList.add('hidden');
|
|
452
|
+
document.getElementById('eventOptions').classList.add('hidden');
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function hideAllActionOptions() {
|
|
456
|
+
document.getElementById('notificationOptions').classList.add('hidden');
|
|
457
|
+
document.getElementById('messageOptions').classList.add('hidden');
|
|
458
|
+
document.getElementById('taskOptions').classList.add('hidden');
|
|
459
|
+
document.getElementById('emailOptions').classList.add('hidden');
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// 处理表单提交
|
|
463
|
+
async function handleWorkflowSubmit(e) {
|
|
464
|
+
e.preventDefault();
|
|
465
|
+
|
|
466
|
+
const name = document.getElementById('wfName').value.trim();
|
|
467
|
+
const description = document.getElementById('wfDescription').value.trim();
|
|
468
|
+
const triggerType = document.getElementById('wfTriggerType').value;
|
|
469
|
+
const actionType = document.getElementById('wfActionType').value;
|
|
470
|
+
|
|
471
|
+
if (!name || !triggerType || !actionType) {
|
|
472
|
+
alert('请填写所有必填项!');
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// 构建触发器配置
|
|
477
|
+
const trigger = buildTriggerConfig(triggerType);
|
|
478
|
+
|
|
479
|
+
// 构建步骤配置
|
|
480
|
+
const steps = buildStepsConfig(actionType);
|
|
481
|
+
|
|
482
|
+
try {
|
|
483
|
+
const token = localStorage.getItem('token');
|
|
484
|
+
const response = await fetch('http://localhost:8765/api/workflows', {
|
|
485
|
+
method: 'POST',
|
|
486
|
+
headers: {
|
|
487
|
+
'Content-Type': 'application/json',
|
|
488
|
+
'Authorization': `Bearer ${token}`
|
|
489
|
+
},
|
|
490
|
+
body: JSON.stringify({
|
|
491
|
+
name,
|
|
492
|
+
description,
|
|
493
|
+
groupId: currentGroup._id,
|
|
494
|
+
trigger,
|
|
495
|
+
steps
|
|
496
|
+
})
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const result = await response.json();
|
|
500
|
+
|
|
501
|
+
if (result.success || response.ok) {
|
|
502
|
+
alert('工作流创建成功!');
|
|
503
|
+
document.getElementById('simpleWorkflowModal').classList.add('hidden');
|
|
504
|
+
// 刷新列表
|
|
505
|
+
const contentArea = document.getElementById('contentArea');
|
|
506
|
+
renderSimplifiedWorkflowsView(contentArea);
|
|
507
|
+
} else {
|
|
508
|
+
alert('创建失败: ' + (result.error?.message || result.message || '未知错误'));
|
|
509
|
+
}
|
|
510
|
+
} catch (error) {
|
|
511
|
+
console.error('创建工作流失败:', error);
|
|
512
|
+
alert('创建失败: ' + error.message);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// 构建触发器配置
|
|
517
|
+
function buildTriggerConfig(triggerType) {
|
|
518
|
+
const trigger = { type: triggerType };
|
|
519
|
+
|
|
520
|
+
if (triggerType === 'daily') {
|
|
521
|
+
const time = document.getElementById('dailyTime').value;
|
|
522
|
+
const [hour, minute] = time.split(':');
|
|
523
|
+
trigger.schedule = `${minute} ${hour} * * *`; // Cron: 每天指定时间
|
|
524
|
+
} else if (triggerType === 'weekly') {
|
|
525
|
+
const day = document.getElementById('weeklyDay').value;
|
|
526
|
+
const time = document.getElementById('weeklyTime').value;
|
|
527
|
+
const [hour, minute] = time.split(':');
|
|
528
|
+
trigger.schedule = `${minute} ${hour} * * ${day}`; // Cron: 每周指定时间
|
|
529
|
+
} else if (triggerType === 'event') {
|
|
530
|
+
trigger.event = document.getElementById('eventType').value;
|
|
531
|
+
} else {
|
|
532
|
+
trigger.type = 'manual';
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return trigger;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// 构建步骤配置
|
|
539
|
+
function buildStepsConfig(actionType) {
|
|
540
|
+
const steps = [];
|
|
541
|
+
|
|
542
|
+
if (actionType === 'send_notification') {
|
|
543
|
+
const content = document.getElementById('notificationContent').value;
|
|
544
|
+
const target = document.getElementById('notificationTarget').value;
|
|
545
|
+
steps.push({
|
|
546
|
+
name: '发送通知',
|
|
547
|
+
type: 'notification',
|
|
548
|
+
config: {
|
|
549
|
+
message: content,
|
|
550
|
+
target: target
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
} else if (actionType === 'send_message') {
|
|
554
|
+
const content = document.getElementById('messageContent').value;
|
|
555
|
+
steps.push({
|
|
556
|
+
name: '发送消息',
|
|
557
|
+
type: 'message',
|
|
558
|
+
config: {
|
|
559
|
+
content: content
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
} else if (actionType === 'create_task') {
|
|
563
|
+
const title = document.getElementById('taskTitle').value;
|
|
564
|
+
const description = document.getElementById('taskDescription').value;
|
|
565
|
+
steps.push({
|
|
566
|
+
name: '创建任务',
|
|
567
|
+
type: 'task',
|
|
568
|
+
config: {
|
|
569
|
+
title: title,
|
|
570
|
+
description: description
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
} else if (actionType === 'send_email') {
|
|
574
|
+
const subject = document.getElementById('emailSubject').value;
|
|
575
|
+
const content = document.getElementById('emailContent').value;
|
|
576
|
+
steps.push({
|
|
577
|
+
name: '发送邮件',
|
|
578
|
+
type: 'email',
|
|
579
|
+
config: {
|
|
580
|
+
subject: subject,
|
|
581
|
+
body: content
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return steps;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// 设置工作流操作
|
|
590
|
+
function setupWorkflowActions(token) {
|
|
591
|
+
// 激活/停用
|
|
592
|
+
document.querySelectorAll('[data-action="activate-wf"], [data-action="deactivate-wf"]').forEach(btn => {
|
|
593
|
+
btn.addEventListener('click', async () => {
|
|
594
|
+
const action = btn.dataset.action === 'activate-wf' ? 'activate' : 'deactivate';
|
|
595
|
+
try {
|
|
596
|
+
await fetch(`http://localhost:8765/api/workflows/${btn.dataset.id}/${action}`, {
|
|
597
|
+
method: 'POST',
|
|
598
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
599
|
+
});
|
|
600
|
+
alert(action === 'activate' ? '已激活工作流' : '已停用工作流');
|
|
601
|
+
const contentArea = document.getElementById('contentArea');
|
|
602
|
+
renderSimplifiedWorkflowsView(contentArea);
|
|
603
|
+
} catch (error) {
|
|
604
|
+
alert('操作失败: ' + error.message);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
// 立即执行
|
|
610
|
+
document.querySelectorAll('[data-action="trigger-wf"]').forEach(btn => {
|
|
611
|
+
btn.addEventListener('click', async () => {
|
|
612
|
+
if (confirm('确定要立即执行此工作流吗?')) {
|
|
613
|
+
try {
|
|
614
|
+
await fetch(`http://localhost:8765/api/workflows/${btn.dataset.id}/trigger`, {
|
|
615
|
+
method: 'POST',
|
|
616
|
+
headers: {
|
|
617
|
+
'Content-Type': 'application/json',
|
|
618
|
+
'Authorization': `Bearer ${token}`
|
|
619
|
+
},
|
|
620
|
+
body: JSON.stringify({ triggerData: {} })
|
|
621
|
+
});
|
|
622
|
+
alert('工作流已触发!');
|
|
623
|
+
} catch (error) {
|
|
624
|
+
alert('触发失败: ' + error.message);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// 删除
|
|
631
|
+
document.querySelectorAll('[data-action="delete-wf"]').forEach(btn => {
|
|
632
|
+
btn.addEventListener('click', async () => {
|
|
633
|
+
if (confirm('确定要删除这个工作流吗?删除后无法恢复!')) {
|
|
634
|
+
try {
|
|
635
|
+
await fetch(`http://localhost:8765/api/workflows/${btn.dataset.id}`, {
|
|
636
|
+
method: 'DELETE',
|
|
637
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
638
|
+
});
|
|
639
|
+
alert('工作流删除成功!');
|
|
640
|
+
const contentArea = document.getElementById('contentArea');
|
|
641
|
+
renderSimplifiedWorkflowsView(contentArea);
|
|
642
|
+
} catch (error) {
|
|
643
|
+
alert('删除失败: ' + error.message);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
|