collabdocchat 2.1.3 → 2.1.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.
- package/package.json +1 -1
- package/scripts/add-missing-functions.js +66 -0
- package/scripts/add-user-functions.js +201 -0
- package/scripts/check-encoding.js +41 -0
- package/scripts/fix-optimized-views.js +37 -0
- package/src/pages/admin-dashboard.js +64 -0
- package/src/pages/user-dashboard.js +154 -0
- package/src/utils/onboarding-guide.js +37 -37
- package/src/pages/optimized-backup-view.js +0 -614
- package/src/pages/optimized-knowledge-view.js +0 -797
- package/src/pages/optimized-workflow-view.js +0 -790
|
@@ -1,790 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 优化后的工作流管理界�? * 可视化创建工作流,无需编写JSON代码
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
async function renderOptimizedWorkflowView(container, currentGroup, apiService) {
|
|
6
|
-
if (!currentGroup) {
|
|
7
|
-
container.innerHTML = '<div class="empty-state">请先选择一个群�?/div>';
|
|
8
|
-
return;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
const token = localStorage.getItem('token');
|
|
13
|
-
|
|
14
|
-
// 获取工作流列�? const workflowsResponse = await fetch(`http://localhost:3000/api/workflows/group/${currentGroup._id}`, {
|
|
15
|
-
headers: { 'Authorization': `Bearer ${token}` }
|
|
16
|
-
});
|
|
17
|
-
const workflowsResult = await workflowsResponse.json();
|
|
18
|
-
const workflows = workflowsResult.data?.workflows || [];
|
|
19
|
-
|
|
20
|
-
console.log('📋 工作流列�?', workflows);
|
|
21
|
-
|
|
22
|
-
container.innerHTML = `
|
|
23
|
-
<div class="view-header">
|
|
24
|
-
<h2>🔄 工作流管�?- ${currentGroup.name}</h2>
|
|
25
|
-
<button class="btn-primary" id="createWorkflowBtn">
|
|
26
|
-
<span style="font-size: 18px;">�?/span> 创建工作�? </button>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<!-- 工作流模板选择 -->
|
|
30
|
-
<div class="workflow-templates-section">
|
|
31
|
-
<h3 style="margin: 20px 0; color: var(--text-primary);">📋 快速开�?- 选择模板</h3>
|
|
32
|
-
<div class="workflow-templates-grid">
|
|
33
|
-
<div class="template-card" data-template="document-approval">
|
|
34
|
-
<div class="template-icon">📄</div>
|
|
35
|
-
<h4>文档审批流程</h4>
|
|
36
|
-
<p>创建文档后自动通知审批�?/p>
|
|
37
|
-
<button class="btn-use-template">使用模板</button>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<div class="template-card" data-template="task-notification">
|
|
41
|
-
<div class="template-icon">📋</div>
|
|
42
|
-
<h4>任务通知流程</h4>
|
|
43
|
-
<p>任务创建时自动通知相关人员</p>
|
|
44
|
-
<button class="btn-use-template">使用模板</button>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<div class="template-card" data-template="auto-backup">
|
|
48
|
-
<div class="template-icon">💾</div>
|
|
49
|
-
<h4>自动备份流程</h4>
|
|
50
|
-
<p>定时自动备份重要数据</p>
|
|
51
|
-
<button class="btn-use-template">使用模板</button>
|
|
52
|
-
</div>
|
|
53
|
-
|
|
54
|
-
<div class="template-card" data-template="custom">
|
|
55
|
-
<div class="template-icon">⚙️</div>
|
|
56
|
-
<h4>自定义流�?/h4>
|
|
57
|
-
<p>从零开始创建自定义工作�?/p>
|
|
58
|
-
<button class="btn-use-template">创建</button>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<!-- 现有工作流列�?-->
|
|
64
|
-
<div class="workflows-list-section">
|
|
65
|
-
<h3 style="margin: 30px 0 20px; color: var(--text-primary);">📦 现有工作�?/h3>
|
|
66
|
-
<div class="workflows-cards-grid" id="workflowCards">
|
|
67
|
-
${workflows.length === 0 ? `
|
|
68
|
-
<div class="empty-state-modern">
|
|
69
|
-
<div class="empty-icon">📭</div>
|
|
70
|
-
<h3>暂无工作�?/h3>
|
|
71
|
-
<p>选择上方模板快速创建工作流</p>
|
|
72
|
-
</div>
|
|
73
|
-
` : workflows.map(workflow => createWorkflowCard(workflow)).join('')}
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<!-- 创建工作流模态框 -->
|
|
78
|
-
<div class="modal hidden" id="createWorkflowModal">
|
|
79
|
-
<div class="modal-content" style="max-width: 800px;">
|
|
80
|
-
<div class="modal-header">
|
|
81
|
-
<h3>创建工作�?/h3>
|
|
82
|
-
<button class="close-btn" id="closeCreateWorkflow">×</button>
|
|
83
|
-
</div>
|
|
84
|
-
<form id="createWorkflowForm">
|
|
85
|
-
<div class="workflow-form-modern">
|
|
86
|
-
<!-- 基本信息 -->
|
|
87
|
-
<div class="form-section">
|
|
88
|
-
<h4>📝 基本信息</h4>
|
|
89
|
-
<div class="form-group">
|
|
90
|
-
<label>工作流名�?*</label>
|
|
91
|
-
<input type="text" id="workflowName" placeholder="例如:文档审批流�? required>
|
|
92
|
-
</div>
|
|
93
|
-
<div class="form-group">
|
|
94
|
-
<label>描述</label>
|
|
95
|
-
<textarea id="workflowDescription" rows="3" placeholder="描述这个工作流的用�?.."></textarea>
|
|
96
|
-
</div>
|
|
97
|
-
</div>
|
|
98
|
-
|
|
99
|
-
<!-- 触发条件 -->
|
|
100
|
-
<div class="form-section">
|
|
101
|
-
<h4>�?触发条件</h4>
|
|
102
|
-
<div class="form-group">
|
|
103
|
-
<label>触发类型 *</label>
|
|
104
|
-
<select id="triggerType" required>
|
|
105
|
-
<option value="">请选择触发类型</option>
|
|
106
|
-
<option value="document_create">文档创建�?/option>
|
|
107
|
-
<option value="document_update">文档更新�?/option>
|
|
108
|
-
<option value="task_create">任务创建�?/option>
|
|
109
|
-
<option value="task_complete">任务完成�?/option>
|
|
110
|
-
<option value="message_send">消息发送时</option>
|
|
111
|
-
<option value="scheduled">定时触发</option>
|
|
112
|
-
</select>
|
|
113
|
-
</div>
|
|
114
|
-
<div class="form-group hidden" id="scheduleGroup">
|
|
115
|
-
<label>定时规则(Cron表达式)</label>
|
|
116
|
-
<input type="text" id="scheduleRule" placeholder="例如�? 9 * * * (每天9�?">
|
|
117
|
-
<small>示例�? 9 * * * (每天9�?�? */6 * * * (�?小时)</small>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
<!-- 执行动作 -->
|
|
122
|
-
<div class="form-section">
|
|
123
|
-
<h4>🎯 执行动作</h4>
|
|
124
|
-
<div class="form-group">
|
|
125
|
-
<label>动作类型 *</label>
|
|
126
|
-
<select id="actionType" required>
|
|
127
|
-
<option value="">请选择动作类型</option>
|
|
128
|
-
<option value="notification">发送通知</option>
|
|
129
|
-
<option value="email">发送邮�?/option>
|
|
130
|
-
<option value="create_task">创建任务</option>
|
|
131
|
-
<option value="backup">执行备份</option>
|
|
132
|
-
<option value="webhook">调用Webhook</option>
|
|
133
|
-
</select>
|
|
134
|
-
</div>
|
|
135
|
-
|
|
136
|
-
<!-- 通知配置 -->
|
|
137
|
-
<div class="action-config hidden" id="notificationConfig">
|
|
138
|
-
<div class="form-group">
|
|
139
|
-
<label>通知消息</label>
|
|
140
|
-
<textarea id="notificationMessage" rows="2" placeholder="通知内容..."></textarea>
|
|
141
|
-
</div>
|
|
142
|
-
<div class="form-group">
|
|
143
|
-
<label>通知对象</label>
|
|
144
|
-
<select id="notificationTarget">
|
|
145
|
-
<option value="all">所有成�?/option>
|
|
146
|
-
<option value="admin">仅管理员</option>
|
|
147
|
-
<option value="creator">创建�?/option>
|
|
148
|
-
</select>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
|
|
152
|
-
<!-- 邮件配置 -->
|
|
153
|
-
<div class="action-config hidden" id="emailConfig">
|
|
154
|
-
<div class="form-group">
|
|
155
|
-
<label>邮件主题</label>
|
|
156
|
-
<input type="text" id="emailSubject" placeholder="邮件主题">
|
|
157
|
-
</div>
|
|
158
|
-
<div class="form-group">
|
|
159
|
-
<label>邮件内容</label>
|
|
160
|
-
<textarea id="emailBody" rows="3" placeholder="邮件内容..."></textarea>
|
|
161
|
-
</div>
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
<!-- 任务配置 -->
|
|
165
|
-
<div class="action-config hidden" id="taskConfig">
|
|
166
|
-
<div class="form-group">
|
|
167
|
-
<label>任务标题</label>
|
|
168
|
-
<input type="text" id="taskTitle" placeholder="任务标题">
|
|
169
|
-
</div>
|
|
170
|
-
<div class="form-group">
|
|
171
|
-
<label>任务描述</label>
|
|
172
|
-
<textarea id="taskDescription" rows="2" placeholder="任务描述..."></textarea>
|
|
173
|
-
</div>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
<!-- Webhook配置 -->
|
|
177
|
-
<div class="action-config hidden" id="webhookConfig">
|
|
178
|
-
<div class="form-group">
|
|
179
|
-
<label>Webhook URL</label>
|
|
180
|
-
<input type="url" id="webhookUrl" placeholder="https://example.com/webhook">
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
<!-- 条件过滤 -->
|
|
186
|
-
<div class="form-section">
|
|
187
|
-
<h4>🔍 条件过滤(可选)</h4>
|
|
188
|
-
<div class="form-group">
|
|
189
|
-
<label>
|
|
190
|
-
<input type="checkbox" id="enableCondition">
|
|
191
|
-
启用条件过滤
|
|
192
|
-
</label>
|
|
193
|
-
</div>
|
|
194
|
-
<div class="condition-config hidden" id="conditionConfig">
|
|
195
|
-
<div class="form-group">
|
|
196
|
-
<label>条件字段</label>
|
|
197
|
-
<input type="text" id="conditionField" placeholder="例如:title">
|
|
198
|
-
</div>
|
|
199
|
-
<div class="form-group">
|
|
200
|
-
<label>条件�?/label>
|
|
201
|
-
<input type="text" id="conditionValue" placeholder="例如:重�?>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
</div>
|
|
205
|
-
</div>
|
|
206
|
-
|
|
207
|
-
<div style="display: flex; gap: 10px; margin-top: 20px; justify-content: center;">
|
|
208
|
-
<button type="submit" class="btn-primary btn-large">
|
|
209
|
-
<span>�?/span> 创建工作�? </button>
|
|
210
|
-
<button type="button" class="btn-secondary btn-large" id="cancelCreateWorkflow">
|
|
211
|
-
<span>�?/span> 取消
|
|
212
|
-
</button>
|
|
213
|
-
</div>
|
|
214
|
-
</form>
|
|
215
|
-
</div>
|
|
216
|
-
</div>
|
|
217
|
-
`;
|
|
218
|
-
|
|
219
|
-
// 添加样式
|
|
220
|
-
addWorkflowStyles();
|
|
221
|
-
|
|
222
|
-
// 绑定事件
|
|
223
|
-
setupWorkflowEvents(token, container, currentGroup, apiService);
|
|
224
|
-
|
|
225
|
-
} catch (error) {
|
|
226
|
-
console.error('加载工作流管理失�?', error);
|
|
227
|
-
container.innerHTML = `
|
|
228
|
-
<div class="view-header">
|
|
229
|
-
<h2>🔄 工作流管�?/h2>
|
|
230
|
-
</div>
|
|
231
|
-
<div class="empty-state">加载失败: ${error.message}</div>
|
|
232
|
-
`;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// 创建工作流卡�?function createWorkflowCard(workflow) {
|
|
237
|
-
const statusConfig = {
|
|
238
|
-
active: { icon: '�?, label: '运行�?, color: '#10b981' },
|
|
239
|
-
inactive: { icon: '⏸️', label: '已暂�?, color: '#f59e0b' },
|
|
240
|
-
error: { icon: '�?, label: '错误', color: '#ef4444' }
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
const config = statusConfig[workflow.status] || statusConfig.inactive;
|
|
244
|
-
|
|
245
|
-
return `
|
|
246
|
-
<div class="workflow-card-modern">
|
|
247
|
-
<div class="workflow-card-header">
|
|
248
|
-
<div class="workflow-icon">🔄</div>
|
|
249
|
-
<div class="workflow-card-title">
|
|
250
|
-
<h4>${workflow.name}</h4>
|
|
251
|
-
<span class="workflow-time">${new Date(workflow.createdAt).toLocaleString()}</span>
|
|
252
|
-
</div>
|
|
253
|
-
<div class="workflow-status-badge" style="background: ${config.color}20; color: ${config.color};">
|
|
254
|
-
${config.icon} ${config.label}
|
|
255
|
-
</div>
|
|
256
|
-
</div>
|
|
257
|
-
|
|
258
|
-
<div class="workflow-card-body">
|
|
259
|
-
<p class="workflow-description">${workflow.description || '无描�?}</p>
|
|
260
|
-
<div class="workflow-info-row">
|
|
261
|
-
<span class="info-label">触发�?/span>
|
|
262
|
-
<span class="info-value">${getTriggerText(workflow.trigger)}</span>
|
|
263
|
-
</div>
|
|
264
|
-
<div class="workflow-info-row">
|
|
265
|
-
<span class="info-label">执行次数</span>
|
|
266
|
-
<span class="info-value">${workflow.executionCount || 0} �?/span>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
|
|
270
|
-
<div class="workflow-card-actions">
|
|
271
|
-
<button class="btn-action btn-toggle" data-id="${workflow._id}" data-status="${workflow.status}">
|
|
272
|
-
<span>${workflow.status === 'active' ? '⏸️' : '▶️'}</span> ${workflow.status === 'active' ? '暂停' : '启动'}
|
|
273
|
-
</button>
|
|
274
|
-
<button class="btn-action btn-edit" data-id="${workflow._id}">
|
|
275
|
-
<span>✏️</span> 编辑
|
|
276
|
-
</button>
|
|
277
|
-
<button class="btn-action btn-delete" data-id="${workflow._id}">
|
|
278
|
-
<span>🗑�?/span> 删除
|
|
279
|
-
</button>
|
|
280
|
-
</div>
|
|
281
|
-
</div>
|
|
282
|
-
`;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// 获取触发器文�?function getTriggerText(trigger) {
|
|
286
|
-
if (!trigger) return '未知';
|
|
287
|
-
|
|
288
|
-
const typeMap = {
|
|
289
|
-
'manual': '手动触发',
|
|
290
|
-
'scheduled': '定时触发',
|
|
291
|
-
'event': '事件触发'
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
const eventMap = {
|
|
295
|
-
'document_create': '文档创建',
|
|
296
|
-
'document_update': '文档更新',
|
|
297
|
-
'task_create': '任务创建',
|
|
298
|
-
'task_complete': '任务完成',
|
|
299
|
-
'message_send': '消息发�?
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
if (trigger.type === 'event' && trigger.event) {
|
|
303
|
-
return eventMap[trigger.event] || trigger.event;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return typeMap[trigger.type] || trigger.type;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// 添加样式
|
|
310
|
-
function addWorkflowStyles() {
|
|
311
|
-
if (document.getElementById('workflow-modern-styles')) return;
|
|
312
|
-
|
|
313
|
-
const style = document.createElement('style');
|
|
314
|
-
style.id = 'workflow-modern-styles';
|
|
315
|
-
style.textContent = `
|
|
316
|
-
.workflow-templates-grid {
|
|
317
|
-
display: grid;
|
|
318
|
-
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
319
|
-
gap: 20px;
|
|
320
|
-
margin-bottom: 30px;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
.template-card {
|
|
324
|
-
background: linear-gradient(135deg, var(--bg-card) 0%, rgba(99,102,241,0.05) 100%);
|
|
325
|
-
border: 2px solid var(--border);
|
|
326
|
-
border-radius: 16px;
|
|
327
|
-
padding: 24px;
|
|
328
|
-
text-align: center;
|
|
329
|
-
transition: all 0.3s ease;
|
|
330
|
-
cursor: pointer;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
.template-card:hover {
|
|
334
|
-
transform: translateY(-8px);
|
|
335
|
-
box-shadow: 0 12px 32px rgba(99,102,241,0.2);
|
|
336
|
-
border-color: var(--primary);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
.template-icon {
|
|
340
|
-
font-size: 48px;
|
|
341
|
-
margin-bottom: 16px;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.template-card h4 {
|
|
345
|
-
margin: 0 0 8px;
|
|
346
|
-
font-size: 16px;
|
|
347
|
-
color: var(--text-primary);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
.template-card p {
|
|
351
|
-
margin: 0 0 16px;
|
|
352
|
-
font-size: 13px;
|
|
353
|
-
color: var(--text-secondary);
|
|
354
|
-
line-height: 1.5;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
.btn-use-template {
|
|
358
|
-
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
359
|
-
color: white;
|
|
360
|
-
border: none;
|
|
361
|
-
padding: 10px 20px;
|
|
362
|
-
border-radius: 8px;
|
|
363
|
-
font-weight: 600;
|
|
364
|
-
cursor: pointer;
|
|
365
|
-
transition: all 0.3s ease;
|
|
366
|
-
width: 100%;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.btn-use-template:hover {
|
|
370
|
-
transform: scale(1.05);
|
|
371
|
-
box-shadow: 0 4px 12px rgba(99,102,241,0.4);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
.workflows-cards-grid {
|
|
375
|
-
display: grid;
|
|
376
|
-
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
377
|
-
gap: 20px;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
.workflow-card-modern {
|
|
381
|
-
background: var(--bg-card);
|
|
382
|
-
border: 2px solid var(--border);
|
|
383
|
-
border-radius: 16px;
|
|
384
|
-
padding: 20px;
|
|
385
|
-
transition: all 0.3s ease;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
.workflow-card-modern:hover {
|
|
389
|
-
transform: translateY(-5px);
|
|
390
|
-
box-shadow: 0 8px 24px rgba(99,102,241,0.15);
|
|
391
|
-
border-color: var(--primary);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
.workflow-card-header {
|
|
395
|
-
display: flex;
|
|
396
|
-
align-items: center;
|
|
397
|
-
gap: 12px;
|
|
398
|
-
margin-bottom: 16px;
|
|
399
|
-
padding-bottom: 16px;
|
|
400
|
-
border-bottom: 1px solid var(--border);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
.workflow-icon {
|
|
404
|
-
width: 48px;
|
|
405
|
-
height: 48px;
|
|
406
|
-
border-radius: 12px;
|
|
407
|
-
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
|
|
408
|
-
display: flex;
|
|
409
|
-
align-items: center;
|
|
410
|
-
justify-content: center;
|
|
411
|
-
font-size: 24px;
|
|
412
|
-
flex-shrink: 0;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
.workflow-card-title {
|
|
416
|
-
flex: 1;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
.workflow-card-title h4 {
|
|
420
|
-
margin: 0 0 4px;
|
|
421
|
-
font-size: 16px;
|
|
422
|
-
color: var(--text-primary);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
.workflow-time {
|
|
426
|
-
font-size: 12px;
|
|
427
|
-
color: var(--text-secondary);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
.workflow-status-badge {
|
|
431
|
-
padding: 6px 12px;
|
|
432
|
-
border-radius: 8px;
|
|
433
|
-
font-size: 12px;
|
|
434
|
-
font-weight: 600;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
.workflow-card-body {
|
|
438
|
-
margin-bottom: 16px;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
.workflow-description {
|
|
442
|
-
margin: 0 0 12px;
|
|
443
|
-
font-size: 14px;
|
|
444
|
-
color: var(--text-secondary);
|
|
445
|
-
line-height: 1.5;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
.workflow-info-row {
|
|
449
|
-
display: flex;
|
|
450
|
-
justify-content: space-between;
|
|
451
|
-
padding: 8px 0;
|
|
452
|
-
font-size: 14px;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
.workflow-card-actions {
|
|
456
|
-
display: flex;
|
|
457
|
-
gap: 8px;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
.workflow-form-modern {
|
|
461
|
-
max-height: 60vh;
|
|
462
|
-
overflow-y: auto;
|
|
463
|
-
padding-right: 10px;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
.form-section {
|
|
467
|
-
background: var(--bg-dark);
|
|
468
|
-
border: 1px solid var(--border);
|
|
469
|
-
border-radius: 12px;
|
|
470
|
-
padding: 20px;
|
|
471
|
-
margin-bottom: 20px;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
.form-section h4 {
|
|
475
|
-
margin: 0 0 16px;
|
|
476
|
-
font-size: 16px;
|
|
477
|
-
color: var(--text-primary);
|
|
478
|
-
display: flex;
|
|
479
|
-
align-items: center;
|
|
480
|
-
gap: 8px;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
.action-config,
|
|
484
|
-
.condition-config {
|
|
485
|
-
margin-top: 16px;
|
|
486
|
-
padding-top: 16px;
|
|
487
|
-
border-top: 1px solid var(--border);
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
.btn-large {
|
|
491
|
-
padding: 14px 28px;
|
|
492
|
-
font-size: 15px;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
.empty-state-modern {
|
|
496
|
-
grid-column: 1 / -1;
|
|
497
|
-
text-align: center;
|
|
498
|
-
padding: 60px 20px;
|
|
499
|
-
background: linear-gradient(135deg, var(--bg-dark) 0%, rgba(99,102,241,0.03) 100%);
|
|
500
|
-
border-radius: 16px;
|
|
501
|
-
border: 2px dashed var(--border);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
.empty-icon {
|
|
505
|
-
font-size: 64px;
|
|
506
|
-
margin-bottom: 20px;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
.empty-state-modern h3 {
|
|
510
|
-
margin: 0 0 10px;
|
|
511
|
-
color: var(--text-primary);
|
|
512
|
-
font-size: 20px;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
.empty-state-modern p {
|
|
516
|
-
margin: 0;
|
|
517
|
-
color: var(--text-secondary);
|
|
518
|
-
font-size: 14px;
|
|
519
|
-
}
|
|
520
|
-
`;
|
|
521
|
-
document.head.appendChild(style);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// 设置事件监听
|
|
525
|
-
function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
526
|
-
// 模板选择
|
|
527
|
-
document.querySelectorAll('.template-card').forEach(card => {
|
|
528
|
-
card.addEventListener('click', () => {
|
|
529
|
-
const template = card.dataset.template;
|
|
530
|
-
openWorkflowModal(template);
|
|
531
|
-
});
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
// 创建工作流按�? document.getElementById('createWorkflowBtn')?.addEventListener('click', () => {
|
|
535
|
-
openWorkflowModal('custom');
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
// 关闭模态框
|
|
539
|
-
document.getElementById('closeCreateWorkflow')?.addEventListener('click', () => {
|
|
540
|
-
document.getElementById('createWorkflowModal').classList.add('hidden');
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
document.getElementById('cancelCreateWorkflow')?.addEventListener('click', () => {
|
|
544
|
-
document.getElementById('createWorkflowModal').classList.add('hidden');
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
// 触发类型变化
|
|
548
|
-
document.getElementById('triggerType')?.addEventListener('change', (e) => {
|
|
549
|
-
const scheduleGroup = document.getElementById('scheduleGroup');
|
|
550
|
-
if (e.target.value === 'scheduled') {
|
|
551
|
-
scheduleGroup.classList.remove('hidden');
|
|
552
|
-
} else {
|
|
553
|
-
scheduleGroup.classList.add('hidden');
|
|
554
|
-
}
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
// 动作类型变化
|
|
558
|
-
document.getElementById('actionType')?.addEventListener('change', (e) => {
|
|
559
|
-
// 隐藏所有配�? document.querySelectorAll('.action-config').forEach(el => el.classList.add('hidden'));
|
|
560
|
-
|
|
561
|
-
// 显示对应配置
|
|
562
|
-
const configMap = {
|
|
563
|
-
'notification': 'notificationConfig',
|
|
564
|
-
'email': 'emailConfig',
|
|
565
|
-
'create_task': 'taskConfig',
|
|
566
|
-
'webhook': 'webhookConfig'
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
const configId = configMap[e.target.value];
|
|
570
|
-
if (configId) {
|
|
571
|
-
document.getElementById(configId)?.classList.remove('hidden');
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
// 条件过滤开�? document.getElementById('enableCondition')?.addEventListener('change', (e) => {
|
|
576
|
-
const conditionConfig = document.getElementById('conditionConfig');
|
|
577
|
-
if (e.target.checked) {
|
|
578
|
-
conditionConfig.classList.remove('hidden');
|
|
579
|
-
} else {
|
|
580
|
-
conditionConfig.classList.add('hidden');
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
// 创建工作流表单提�? document.getElementById('createWorkflowForm')?.addEventListener('submit', async (e) => {
|
|
585
|
-
e.preventDefault();
|
|
586
|
-
await createWorkflow(token, container, currentGroup, apiService);
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
// 工作流操作按�? document.querySelectorAll('.btn-toggle').forEach(btn => {
|
|
590
|
-
btn.addEventListener('click', async () => {
|
|
591
|
-
const workflowId = btn.dataset.id;
|
|
592
|
-
const currentStatus = btn.dataset.status;
|
|
593
|
-
const newStatus = currentStatus === 'active' ? 'inactive' : 'active';
|
|
594
|
-
|
|
595
|
-
try {
|
|
596
|
-
await fetch(`http://localhost:3000/api/workflows/${workflowId}/status`, {
|
|
597
|
-
method: 'PUT',
|
|
598
|
-
headers: {
|
|
599
|
-
'Content-Type': 'application/json',
|
|
600
|
-
'Authorization': `Bearer ${token}`
|
|
601
|
-
},
|
|
602
|
-
body: JSON.stringify({ status: newStatus })
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
alert(`工作流已${newStatus === 'active' ? '启动' : '暂停'}!`);
|
|
606
|
-
renderOptimizedWorkflowView(container, currentGroup, apiService);
|
|
607
|
-
} catch (error) {
|
|
608
|
-
alert('操作失败: ' + error.message);
|
|
609
|
-
}
|
|
610
|
-
});
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
document.querySelectorAll('.btn-delete').forEach(btn => {
|
|
614
|
-
btn.addEventListener('click', async () => {
|
|
615
|
-
if (!confirm('确定要删除此工作流吗�?)) return;
|
|
616
|
-
|
|
617
|
-
const workflowId = btn.dataset.id;
|
|
618
|
-
try {
|
|
619
|
-
await fetch(`http://localhost:3000/api/workflows/${workflowId}`, {
|
|
620
|
-
method: 'DELETE',
|
|
621
|
-
headers: { 'Authorization': `Bearer ${token}` }
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
alert('工作流删除成功!');
|
|
625
|
-
renderOptimizedWorkflowView(container, currentGroup, apiService);
|
|
626
|
-
} catch (error) {
|
|
627
|
-
alert('删除失败: ' + error.message);
|
|
628
|
-
}
|
|
629
|
-
});
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// 打开工作流模态框并填充模�?function openWorkflowModal(template) {
|
|
634
|
-
const modal = document.getElementById('createWorkflowModal');
|
|
635
|
-
modal.classList.remove('hidden');
|
|
636
|
-
|
|
637
|
-
// 根据模板填充表单
|
|
638
|
-
const templates = {
|
|
639
|
-
'document-approval': {
|
|
640
|
-
name: '文档审批流程',
|
|
641
|
-
description: '文档创建后自动通知管理员审�?,
|
|
642
|
-
trigger: 'document_create',
|
|
643
|
-
action: 'notification',
|
|
644
|
-
notificationMessage: '新文档待审批',
|
|
645
|
-
notificationTarget: 'admin'
|
|
646
|
-
},
|
|
647
|
-
'task-notification': {
|
|
648
|
-
name: '任务通知流程',
|
|
649
|
-
description: '任务创建时自动通知所有成�?,
|
|
650
|
-
trigger: 'task_create',
|
|
651
|
-
action: 'notification',
|
|
652
|
-
notificationMessage: '新任务已分配',
|
|
653
|
-
notificationTarget: 'all'
|
|
654
|
-
},
|
|
655
|
-
'auto-backup': {
|
|
656
|
-
name: '自动备份流程',
|
|
657
|
-
description: '每天凌晨2点自动备份数�?,
|
|
658
|
-
trigger: 'scheduled',
|
|
659
|
-
scheduleRule: '0 2 * * *',
|
|
660
|
-
action: 'notification'
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
|
-
|
|
664
|
-
const templateData = templates[template];
|
|
665
|
-
if (templateData) {
|
|
666
|
-
document.getElementById('workflowName').value = templateData.name;
|
|
667
|
-
document.getElementById('workflowDescription').value = templateData.description;
|
|
668
|
-
document.getElementById('triggerType').value = templateData.trigger;
|
|
669
|
-
document.getElementById('actionType').value = templateData.action;
|
|
670
|
-
|
|
671
|
-
// 触发类型变化事件
|
|
672
|
-
document.getElementById('triggerType').dispatchEvent(new Event('change'));
|
|
673
|
-
document.getElementById('actionType').dispatchEvent(new Event('change'));
|
|
674
|
-
|
|
675
|
-
if (templateData.scheduleRule) {
|
|
676
|
-
document.getElementById('scheduleRule').value = templateData.scheduleRule;
|
|
677
|
-
}
|
|
678
|
-
if (templateData.notificationMessage) {
|
|
679
|
-
document.getElementById('notificationMessage').value = templateData.notificationMessage;
|
|
680
|
-
}
|
|
681
|
-
if (templateData.notificationTarget) {
|
|
682
|
-
document.getElementById('notificationTarget').value = templateData.notificationTarget;
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// 创建工作�?async function createWorkflow(token, container, currentGroup, apiService) {
|
|
688
|
-
const name = document.getElementById('workflowName').value;
|
|
689
|
-
const description = document.getElementById('workflowDescription').value;
|
|
690
|
-
const triggerType = document.getElementById('triggerType').value;
|
|
691
|
-
const actionType = document.getElementById('actionType').value;
|
|
692
|
-
|
|
693
|
-
// 构建触发器配�? const trigger = {};
|
|
694
|
-
|
|
695
|
-
// 判断触发类型
|
|
696
|
-
if (triggerType === 'scheduled') {
|
|
697
|
-
trigger.type = 'scheduled';
|
|
698
|
-
trigger.schedule = document.getElementById('scheduleRule').value;
|
|
699
|
-
} else {
|
|
700
|
-
trigger.type = 'event';
|
|
701
|
-
trigger.event = triggerType;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// 构建工作流数�? const workflowData = {
|
|
705
|
-
name,
|
|
706
|
-
description,
|
|
707
|
-
groupId: currentGroup._id,
|
|
708
|
-
trigger: trigger,
|
|
709
|
-
steps: []
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
// 构建动作步骤
|
|
713
|
-
const step = {
|
|
714
|
-
name: actionType === 'notification' ? '发送通知' :
|
|
715
|
-
actionType === 'email' ? '发送邮�? :
|
|
716
|
-
actionType === 'create_task' ? '创建任务' :
|
|
717
|
-
actionType === 'webhook' ? '调用Webhook' : '执行动作',
|
|
718
|
-
type: actionType,
|
|
719
|
-
order: 1,
|
|
720
|
-
config: {}
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
switch (actionType) {
|
|
724
|
-
case 'notification':
|
|
725
|
-
step.config.message = document.getElementById('notificationMessage').value;
|
|
726
|
-
step.config.notificationType = 'system';
|
|
727
|
-
// 根据目标设置接收者(这里简化处理,实际应该获取用户ID�? step.config.recipients = [];
|
|
728
|
-
break;
|
|
729
|
-
case 'email':
|
|
730
|
-
step.config.notificationType = 'email';
|
|
731
|
-
step.config.message = document.getElementById('emailSubject').value + '\n' + document.getElementById('emailBody').value;
|
|
732
|
-
break;
|
|
733
|
-
case 'create_task':
|
|
734
|
-
step.type = 'assignment';
|
|
735
|
-
step.config.message = document.getElementById('taskTitle').value;
|
|
736
|
-
break;
|
|
737
|
-
case 'webhook':
|
|
738
|
-
step.config.url = document.getElementById('webhookUrl').value;
|
|
739
|
-
step.config.method = 'POST';
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
workflowData.steps.push(step);
|
|
744
|
-
|
|
745
|
-
// 添加条件过滤
|
|
746
|
-
if (document.getElementById('enableCondition').checked) {
|
|
747
|
-
const conditionField = document.getElementById('conditionField').value;
|
|
748
|
-
const conditionValue = document.getElementById('conditionValue').value;
|
|
749
|
-
|
|
750
|
-
if (conditionField && conditionValue) {
|
|
751
|
-
workflowData.trigger.conditions = [{
|
|
752
|
-
field: conditionField,
|
|
753
|
-
operator: 'contains',
|
|
754
|
-
value: conditionValue
|
|
755
|
-
}];
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
console.log('📤 发送工作流数据:', workflowData);
|
|
760
|
-
|
|
761
|
-
try {
|
|
762
|
-
const response = await fetch('http://localhost:3000/api/workflows', {
|
|
763
|
-
method: 'POST',
|
|
764
|
-
headers: {
|
|
765
|
-
'Content-Type': 'application/json',
|
|
766
|
-
'Authorization': `Bearer ${token}`
|
|
767
|
-
},
|
|
768
|
-
body: JSON.stringify(workflowData)
|
|
769
|
-
});
|
|
770
|
-
|
|
771
|
-
const result = await response.json();
|
|
772
|
-
console.log('📥 服务器响�?', result);
|
|
773
|
-
|
|
774
|
-
if (result.success) {
|
|
775
|
-
alert('工作流创建成功!');
|
|
776
|
-
document.getElementById('createWorkflowModal').classList.add('hidden');
|
|
777
|
-
// 重新渲染工作流列�? await renderOptimizedWorkflowView(container, currentGroup, apiService);
|
|
778
|
-
} else {
|
|
779
|
-
alert('创建失败: ' + (result.error?.message || result.message || '未知错误'));
|
|
780
|
-
}
|
|
781
|
-
} catch (error) {
|
|
782
|
-
console.error('�?创建工作流失�?', error);
|
|
783
|
-
alert('创建失败: ' + error.message);
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// 导出函数
|
|
788
|
-
export { renderOptimizedWorkflowView };
|
|
789
|
-
|
|
790
|
-
|