collabdocchat 2.0.4 → 2.0.6
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/generate-docs.js +1 -0
- package/scripts/pre-publish-check.js +1 -0
- package/src/components/knowledge-modal.js +17 -18
- package/src/components/optimized-poll-detail.js +19 -21
- package/src/main.js +3 -2
- package/src/pages/admin-dashboard.js +283 -325
- package/src/pages/login.js +9 -8
- package/src/pages/optimized-backup-view.js +34 -36
- package/src/pages/optimized-knowledge-view.js +36 -42
- package/src/pages/optimized-task-detail.js +38 -43
- package/src/pages/optimized-workflow-view.js +66 -82
- package/src/pages/simplified-workflows.js +67 -66
- package/src/pages/user-dashboard.js +97 -112
- package/src/services/api.js +5 -7
- package/src/services/auth.js +2 -1
- package/src/services/websocket.js +13 -15
- package/src/styles/collaboration-modern.js +10 -11
- package/src/utils/ai-assistant.js +76 -90
- package/src/utils/chat-enhancements.js +20 -19
- package/src/utils/collaboration-enhancer.js +86 -127
- package/src/utils/feature-integrator.js +80 -94
- package/src/utils/onboarding-guide.js +84 -94
- package/src/utils/performance.js +11 -10
- package/src/utils/permission-manager.js +41 -59
- package/src/utils/responsive-handler.js +24 -23
- package/src/utils/theme-manager.js +39 -50
- package/src/utils/ui-enhancements-loader.js +32 -41
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 优化后的任务详情界面
|
|
1
|
+
// 优化后的任务详情界面
|
|
2
2
|
// 使用卡片式布局,提升视觉效果和信息层次
|
|
3
3
|
|
|
4
4
|
function renderOptimizedTaskDetail(task, container) {
|
|
@@ -18,7 +18,7 @@ function renderOptimizedTaskDetail(task, container) {
|
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
20
|
<button class="btn-close-modern" id="closeTaskDetail">
|
|
21
|
-
<span
|
|
21
|
+
<span>�?/span>
|
|
22
22
|
</button>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
@@ -32,21 +32,20 @@ function renderOptimizedTaskDetail(task, container) {
|
|
|
32
32
|
<div class="info-label-modern">
|
|
33
33
|
<span class="label-icon">👤</span> 任务组长
|
|
34
34
|
</div>
|
|
35
|
-
<div class="info-value-modern">${task.assignedTo || '
|
|
35
|
+
<div class="info-value-modern">${task.assignedTo || '未分�?}</div>
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
38
|
<div class="info-item-modern">
|
|
39
39
|
<div class="info-label-modern">
|
|
40
|
-
<span class="label-icon">👥</span>
|
|
41
|
-
</div>
|
|
42
|
-
<div class="info-value-modern">${task.group || '未指定'}</div>
|
|
40
|
+
<span class="label-icon">👥</span> 所属群�? </div>
|
|
41
|
+
<div class="info-value-modern">${task.group || '未指�?}</div>
|
|
43
42
|
</div>
|
|
44
43
|
|
|
45
44
|
<div class="info-item-modern">
|
|
46
45
|
<div class="info-label-modern">
|
|
47
46
|
<span class="label-icon">📅</span> 截止日期
|
|
48
47
|
</div>
|
|
49
|
-
<div class="info-value-modern">${task.deadline ? new Date(task.deadline).toLocaleString() : '
|
|
48
|
+
<div class="info-value-modern">${task.deadline ? new Date(task.deadline).toLocaleString() : '�?}</div>
|
|
50
49
|
</div>
|
|
51
50
|
|
|
52
51
|
<div class="info-item-modern">
|
|
@@ -76,23 +75,23 @@ function renderOptimizedTaskDetail(task, container) {
|
|
|
76
75
|
<div class="stat-item-modern stat-total">
|
|
77
76
|
<div class="stat-icon-modern">👥</div>
|
|
78
77
|
<div class="stat-content-modern">
|
|
79
|
-
<div class="stat-label-modern"
|
|
78
|
+
<div class="stat-label-modern">总人�?/div>
|
|
80
79
|
<div class="stat-value-modern">${task.members?.length || 0}</div>
|
|
81
80
|
</div>
|
|
82
81
|
</div>
|
|
83
82
|
|
|
84
83
|
<div class="stat-item-modern stat-completed">
|
|
85
|
-
<div class="stat-icon-modern"
|
|
84
|
+
<div class="stat-icon-modern">�?/div>
|
|
86
85
|
<div class="stat-content-modern">
|
|
87
|
-
<div class="stat-label-modern"
|
|
86
|
+
<div class="stat-label-modern">已完�?/div>
|
|
88
87
|
<div class="stat-value-modern">${task.completedCount || 0}</div>
|
|
89
88
|
</div>
|
|
90
89
|
</div>
|
|
91
90
|
|
|
92
91
|
<div class="stat-item-modern stat-pending">
|
|
93
|
-
<div class="stat-icon-modern"
|
|
92
|
+
<div class="stat-icon-modern">�?/div>
|
|
94
93
|
<div class="stat-content-modern">
|
|
95
|
-
<div class="stat-label-modern"
|
|
94
|
+
<div class="stat-label-modern">未完�?/div>
|
|
96
95
|
<div class="stat-value-modern">${(task.members?.length || 0) - (task.completedCount || 0)}</div>
|
|
97
96
|
</div>
|
|
98
97
|
</div>
|
|
@@ -100,13 +99,13 @@ function renderOptimizedTaskDetail(task, container) {
|
|
|
100
99
|
<div class="stat-item-modern stat-progress">
|
|
101
100
|
<div class="stat-icon-modern">📈</div>
|
|
102
101
|
<div class="stat-content-modern">
|
|
103
|
-
<div class="stat-label-modern"
|
|
102
|
+
<div class="stat-label-modern">完成�?/div>
|
|
104
103
|
<div class="stat-value-modern">${calculateProgress(task)}%</div>
|
|
105
104
|
</div>
|
|
106
105
|
</div>
|
|
107
106
|
</div>
|
|
108
107
|
|
|
109
|
-
<!--
|
|
108
|
+
<!-- 进度�?-->
|
|
110
109
|
<div class="progress-bar-container-modern">
|
|
111
110
|
<div class="progress-bar-modern">
|
|
112
111
|
<div class="progress-fill-modern" style="width: ${calculateProgress(task)}%">
|
|
@@ -116,7 +115,7 @@ function renderOptimizedTaskDetail(task, container) {
|
|
|
116
115
|
</div>
|
|
117
116
|
</div>
|
|
118
117
|
|
|
119
|
-
<!--
|
|
118
|
+
<!-- 投票结果卡片(如果有投票�?-->
|
|
120
119
|
${task.poll ? renderPollResults(task.poll) : ''}
|
|
121
120
|
|
|
122
121
|
<!-- 成员完成情况卡片 -->
|
|
@@ -135,10 +134,10 @@ function renderOptimizedTaskDetail(task, container) {
|
|
|
135
134
|
<span>✏️</span> 编辑任务
|
|
136
135
|
</button>
|
|
137
136
|
<button class="btn-action-modern btn-complete" id="completeTask">
|
|
138
|
-
<span
|
|
137
|
+
<span>�?/span> 标记完成
|
|
139
138
|
</button>
|
|
140
139
|
<button class="btn-action-modern btn-delete" id="deleteTask">
|
|
141
|
-
<span
|
|
140
|
+
<span>🗑�?/span> 删除任务
|
|
142
141
|
</button>
|
|
143
142
|
</div>
|
|
144
143
|
</div>
|
|
@@ -170,7 +169,7 @@ function renderPollResults(poll) {
|
|
|
170
169
|
<div class="poll-option-modern">
|
|
171
170
|
<div class="poll-option-header-modern">
|
|
172
171
|
<span class="poll-option-text-modern">${option.text}</span>
|
|
173
|
-
<span class="poll-option-count-modern">${option.votes || 0}
|
|
172
|
+
<span class="poll-option-count-modern">${option.votes || 0} �?(${percentage}%)</span>
|
|
174
173
|
</div>
|
|
175
174
|
<div class="poll-option-bar-modern">
|
|
176
175
|
<div class="poll-option-fill-modern" style="width: ${percentage}%"></div>
|
|
@@ -184,10 +183,9 @@ function renderPollResults(poll) {
|
|
|
184
183
|
`;
|
|
185
184
|
}
|
|
186
185
|
|
|
187
|
-
//
|
|
188
|
-
function renderMemberItem(member) {
|
|
186
|
+
// 渲染成员�?function renderMemberItem(member) {
|
|
189
187
|
const isCompleted = member.completed || member.status === 'completed';
|
|
190
|
-
const completedTime = member.completedAt ? new Date(member.completedAt).toLocaleString() : '
|
|
188
|
+
const completedTime = member.completedAt ? new Date(member.completedAt).toLocaleString() : '未完�?;
|
|
191
189
|
|
|
192
190
|
return `
|
|
193
191
|
<div class="member-item-modern ${isCompleted ? 'completed' : 'pending'}">
|
|
@@ -197,13 +195,13 @@ function renderMemberItem(member) {
|
|
|
197
195
|
<div class="member-info-modern">
|
|
198
196
|
<div class="member-name-modern">${member.username || '未知用户'}</div>
|
|
199
197
|
<div class="member-time-modern">
|
|
200
|
-
${isCompleted ?
|
|
198
|
+
${isCompleted ? `�?${completedTime}` : '�?待完�?}
|
|
201
199
|
</div>
|
|
202
200
|
</div>
|
|
203
201
|
<div class="member-status-modern">
|
|
204
202
|
${isCompleted ?
|
|
205
|
-
'<span class="status-badge-small completed"
|
|
206
|
-
'<span class="status-badge-small pending"
|
|
203
|
+
'<span class="status-badge-small completed">已完�?/span>' :
|
|
204
|
+
'<span class="status-badge-small pending">未完�?/span>'}
|
|
207
205
|
</div>
|
|
208
206
|
</div>
|
|
209
207
|
`;
|
|
@@ -216,36 +214,33 @@ function calculateProgress(task) {
|
|
|
216
214
|
return Math.round((completed / task.members.length) * 100);
|
|
217
215
|
}
|
|
218
216
|
|
|
219
|
-
//
|
|
220
|
-
function getStatusIcon(status) {
|
|
217
|
+
// 获取状态图�?function getStatusIcon(status) {
|
|
221
218
|
const icons = {
|
|
222
|
-
'pending': '
|
|
219
|
+
'pending': '�?,
|
|
223
220
|
'in_progress': '🔄',
|
|
224
|
-
'completed': '
|
|
225
|
-
'terminated': '
|
|
221
|
+
'completed': '�?,
|
|
222
|
+
'terminated': '�?
|
|
226
223
|
};
|
|
227
224
|
return icons[status] || '📋';
|
|
228
225
|
}
|
|
229
226
|
|
|
230
|
-
//
|
|
231
|
-
function getStatusText(status) {
|
|
227
|
+
// 获取状态文�?function getStatusText(status) {
|
|
232
228
|
const texts = {
|
|
233
|
-
'pending': '
|
|
234
|
-
'in_progress': '
|
|
235
|
-
'completed': '
|
|
236
|
-
'terminated': '
|
|
229
|
+
'pending': '待处�?,
|
|
230
|
+
'in_progress': '进行�?,
|
|
231
|
+
'completed': '已完�?,
|
|
232
|
+
'terminated': '已终�?
|
|
237
233
|
};
|
|
238
234
|
return texts[status] || '未知';
|
|
239
235
|
}
|
|
240
236
|
|
|
241
|
-
//
|
|
242
|
-
function getPriorityIcon(priority) {
|
|
237
|
+
// 获取优先级图�?function getPriorityIcon(priority) {
|
|
243
238
|
const icons = {
|
|
244
239
|
'high': '🔴',
|
|
245
240
|
'medium': '🟡',
|
|
246
241
|
'low': '🟢'
|
|
247
242
|
};
|
|
248
|
-
return icons[priority] || '
|
|
243
|
+
return icons[priority] || '�?;
|
|
249
244
|
}
|
|
250
245
|
|
|
251
246
|
// 添加样式
|
|
@@ -267,7 +262,7 @@ function addTaskDetailStyles() {
|
|
|
267
262
|
overflow-x: hidden;
|
|
268
263
|
}
|
|
269
264
|
|
|
270
|
-
/*
|
|
265
|
+
/* 滚动条样�?*/
|
|
271
266
|
.task-detail-view-modern::-webkit-scrollbar {
|
|
272
267
|
width: 8px;
|
|
273
268
|
}
|
|
@@ -830,14 +825,14 @@ function setupTaskDetailEvents(task, container) {
|
|
|
830
825
|
|
|
831
826
|
// 删除任务
|
|
832
827
|
container.querySelector('#deleteTask')?.addEventListener('click', async () => {
|
|
833
|
-
if (confirm('
|
|
828
|
+
if (confirm('确定要删除此任务吗?此操作不可撤销�?)) {
|
|
834
829
|
// 调用 API 删除任务
|
|
835
|
-
alert('
|
|
830
|
+
alert('任务已删�?);
|
|
836
831
|
container.closest('.modal')?.remove();
|
|
837
832
|
}
|
|
838
833
|
});
|
|
839
834
|
}
|
|
840
835
|
|
|
841
|
-
//
|
|
842
|
-
export { renderOptimizedTaskDetail };
|
|
836
|
+
// 导出函数供其他模块使�?export { renderOptimizedTaskDetail };
|
|
843
837
|
|
|
838
|
+
|
|
@@ -1,42 +1,39 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* 可视化创建工作流,无需编写JSON代码
|
|
1
|
+
/**
|
|
2
|
+
* 优化后的工作流管理界�? * 可视化创建工作流,无需编写JSON代码
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
async function renderOptimizedWorkflowView(container, currentGroup, apiService) {
|
|
7
6
|
if (!currentGroup) {
|
|
8
|
-
container.innerHTML = '<div class="empty-state"
|
|
7
|
+
container.innerHTML = '<div class="empty-state">请先选择一个群�?/div>';
|
|
9
8
|
return;
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
try {
|
|
13
12
|
const token = localStorage.getItem('token');
|
|
14
13
|
|
|
15
|
-
//
|
|
16
|
-
const workflowsResponse = await fetch(`http://localhost:8765/api/workflows/group/${currentGroup._id}`, {
|
|
14
|
+
// 获取工作流列�? const workflowsResponse = await fetch(`http://localhost:3000/api/workflows/group/${currentGroup._id}`, {
|
|
17
15
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
18
16
|
});
|
|
19
17
|
const workflowsResult = await workflowsResponse.json();
|
|
20
18
|
const workflows = workflowsResult.data?.workflows || [];
|
|
21
19
|
|
|
22
|
-
console.log('📋
|
|
20
|
+
console.log('📋 工作流列�?', workflows);
|
|
23
21
|
|
|
24
22
|
container.innerHTML = `
|
|
25
23
|
<div class="view-header">
|
|
26
|
-
<h2>🔄
|
|
24
|
+
<h2>🔄 工作流管�?- ${currentGroup.name}</h2>
|
|
27
25
|
<button class="btn-primary" id="createWorkflowBtn">
|
|
28
|
-
<span style="font-size: 18px;"
|
|
29
|
-
</button>
|
|
26
|
+
<span style="font-size: 18px;">�?/span> 创建工作�? </button>
|
|
30
27
|
</div>
|
|
31
28
|
|
|
32
29
|
<!-- 工作流模板选择 -->
|
|
33
30
|
<div class="workflow-templates-section">
|
|
34
|
-
<h3 style="margin: 20px 0; color: var(--text-primary);">📋
|
|
31
|
+
<h3 style="margin: 20px 0; color: var(--text-primary);">📋 快速开�?- 选择模板</h3>
|
|
35
32
|
<div class="workflow-templates-grid">
|
|
36
33
|
<div class="template-card" data-template="document-approval">
|
|
37
34
|
<div class="template-icon">📄</div>
|
|
38
35
|
<h4>文档审批流程</h4>
|
|
39
|
-
<p
|
|
36
|
+
<p>创建文档后自动通知审批�?/p>
|
|
40
37
|
<button class="btn-use-template">使用模板</button>
|
|
41
38
|
</div>
|
|
42
39
|
|
|
@@ -56,21 +53,21 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
56
53
|
|
|
57
54
|
<div class="template-card" data-template="custom">
|
|
58
55
|
<div class="template-icon">⚙️</div>
|
|
59
|
-
<h4
|
|
60
|
-
<p
|
|
56
|
+
<h4>自定义流�?/h4>
|
|
57
|
+
<p>从零开始创建自定义工作�?/p>
|
|
61
58
|
<button class="btn-use-template">创建</button>
|
|
62
59
|
</div>
|
|
63
60
|
</div>
|
|
64
61
|
</div>
|
|
65
62
|
|
|
66
|
-
<!--
|
|
63
|
+
<!-- 现有工作流列�?-->
|
|
67
64
|
<div class="workflows-list-section">
|
|
68
|
-
<h3 style="margin: 30px 0 20px; color: var(--text-primary);">📦
|
|
65
|
+
<h3 style="margin: 30px 0 20px; color: var(--text-primary);">📦 现有工作�?/h3>
|
|
69
66
|
<div class="workflows-cards-grid" id="workflowCards">
|
|
70
67
|
${workflows.length === 0 ? `
|
|
71
68
|
<div class="empty-state-modern">
|
|
72
69
|
<div class="empty-icon">📭</div>
|
|
73
|
-
<h3
|
|
70
|
+
<h3>暂无工作�?/h3>
|
|
74
71
|
<p>选择上方模板快速创建工作流</p>
|
|
75
72
|
</div>
|
|
76
73
|
` : workflows.map(workflow => createWorkflowCard(workflow)).join('')}
|
|
@@ -81,7 +78,7 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
81
78
|
<div class="modal hidden" id="createWorkflowModal">
|
|
82
79
|
<div class="modal-content" style="max-width: 800px;">
|
|
83
80
|
<div class="modal-header">
|
|
84
|
-
<h3
|
|
81
|
+
<h3>创建工作�?/h3>
|
|
85
82
|
<button class="close-btn" id="closeCreateWorkflow">×</button>
|
|
86
83
|
</div>
|
|
87
84
|
<form id="createWorkflowForm">
|
|
@@ -90,34 +87,34 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
90
87
|
<div class="form-section">
|
|
91
88
|
<h4>📝 基本信息</h4>
|
|
92
89
|
<div class="form-group">
|
|
93
|
-
<label
|
|
94
|
-
<input type="text" id="workflowName" placeholder="
|
|
90
|
+
<label>工作流名�?*</label>
|
|
91
|
+
<input type="text" id="workflowName" placeholder="例如:文档审批流�? required>
|
|
95
92
|
</div>
|
|
96
93
|
<div class="form-group">
|
|
97
94
|
<label>描述</label>
|
|
98
|
-
<textarea id="workflowDescription" rows="3" placeholder="
|
|
95
|
+
<textarea id="workflowDescription" rows="3" placeholder="描述这个工作流的用�?.."></textarea>
|
|
99
96
|
</div>
|
|
100
97
|
</div>
|
|
101
98
|
|
|
102
99
|
<!-- 触发条件 -->
|
|
103
100
|
<div class="form-section">
|
|
104
|
-
<h4
|
|
101
|
+
<h4>�?触发条件</h4>
|
|
105
102
|
<div class="form-group">
|
|
106
103
|
<label>触发类型 *</label>
|
|
107
104
|
<select id="triggerType" required>
|
|
108
105
|
<option value="">请选择触发类型</option>
|
|
109
|
-
<option value="document_create"
|
|
110
|
-
<option value="document_update"
|
|
111
|
-
<option value="task_create"
|
|
112
|
-
<option value="task_complete"
|
|
106
|
+
<option value="document_create">文档创建�?/option>
|
|
107
|
+
<option value="document_update">文档更新�?/option>
|
|
108
|
+
<option value="task_create">任务创建�?/option>
|
|
109
|
+
<option value="task_complete">任务完成�?/option>
|
|
113
110
|
<option value="message_send">消息发送时</option>
|
|
114
111
|
<option value="scheduled">定时触发</option>
|
|
115
112
|
</select>
|
|
116
113
|
</div>
|
|
117
114
|
<div class="form-group hidden" id="scheduleGroup">
|
|
118
115
|
<label>定时规则(Cron表达式)</label>
|
|
119
|
-
<input type="text" id="scheduleRule" placeholder="
|
|
120
|
-
<small
|
|
116
|
+
<input type="text" id="scheduleRule" placeholder="例如�? 9 * * * (每天9�?">
|
|
117
|
+
<small>示例�? 9 * * * (每天9�?�? */6 * * * (�?小时)</small>
|
|
121
118
|
</div>
|
|
122
119
|
</div>
|
|
123
120
|
|
|
@@ -129,7 +126,7 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
129
126
|
<select id="actionType" required>
|
|
130
127
|
<option value="">请选择动作类型</option>
|
|
131
128
|
<option value="notification">发送通知</option>
|
|
132
|
-
<option value="email"
|
|
129
|
+
<option value="email">发送邮�?/option>
|
|
133
130
|
<option value="create_task">创建任务</option>
|
|
134
131
|
<option value="backup">执行备份</option>
|
|
135
132
|
<option value="webhook">调用Webhook</option>
|
|
@@ -145,9 +142,9 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
145
142
|
<div class="form-group">
|
|
146
143
|
<label>通知对象</label>
|
|
147
144
|
<select id="notificationTarget">
|
|
148
|
-
<option value="all"
|
|
145
|
+
<option value="all">所有成�?/option>
|
|
149
146
|
<option value="admin">仅管理员</option>
|
|
150
|
-
<option value="creator"
|
|
147
|
+
<option value="creator">创建�?/option>
|
|
151
148
|
</select>
|
|
152
149
|
</div>
|
|
153
150
|
</div>
|
|
@@ -200,8 +197,8 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
200
197
|
<input type="text" id="conditionField" placeholder="例如:title">
|
|
201
198
|
</div>
|
|
202
199
|
<div class="form-group">
|
|
203
|
-
<label
|
|
204
|
-
<input type="text" id="conditionValue" placeholder="
|
|
200
|
+
<label>条件�?/label>
|
|
201
|
+
<input type="text" id="conditionValue" placeholder="例如:重�?>
|
|
205
202
|
</div>
|
|
206
203
|
</div>
|
|
207
204
|
</div>
|
|
@@ -209,10 +206,9 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
209
206
|
|
|
210
207
|
<div style="display: flex; gap: 10px; margin-top: 20px; justify-content: center;">
|
|
211
208
|
<button type="submit" class="btn-primary btn-large">
|
|
212
|
-
<span
|
|
213
|
-
</button>
|
|
209
|
+
<span>�?/span> 创建工作�? </button>
|
|
214
210
|
<button type="button" class="btn-secondary btn-large" id="cancelCreateWorkflow">
|
|
215
|
-
<span
|
|
211
|
+
<span>�?/span> 取消
|
|
216
212
|
</button>
|
|
217
213
|
</div>
|
|
218
214
|
</form>
|
|
@@ -227,22 +223,21 @@ async function renderOptimizedWorkflowView(container, currentGroup, apiService)
|
|
|
227
223
|
setupWorkflowEvents(token, container, currentGroup, apiService);
|
|
228
224
|
|
|
229
225
|
} catch (error) {
|
|
230
|
-
console.error('
|
|
226
|
+
console.error('加载工作流管理失�?', error);
|
|
231
227
|
container.innerHTML = `
|
|
232
228
|
<div class="view-header">
|
|
233
|
-
<h2>🔄
|
|
229
|
+
<h2>🔄 工作流管�?/h2>
|
|
234
230
|
</div>
|
|
235
231
|
<div class="empty-state">加载失败: ${error.message}</div>
|
|
236
232
|
`;
|
|
237
233
|
}
|
|
238
234
|
}
|
|
239
235
|
|
|
240
|
-
//
|
|
241
|
-
function createWorkflowCard(workflow) {
|
|
236
|
+
// 创建工作流卡�?function createWorkflowCard(workflow) {
|
|
242
237
|
const statusConfig = {
|
|
243
|
-
active: { icon: '
|
|
244
|
-
inactive: { icon: '⏸️', label: '
|
|
245
|
-
error: { icon: '
|
|
238
|
+
active: { icon: '�?, label: '运行�?, color: '#10b981' },
|
|
239
|
+
inactive: { icon: '⏸️', label: '已暂�?, color: '#f59e0b' },
|
|
240
|
+
error: { icon: '�?, label: '错误', color: '#ef4444' }
|
|
246
241
|
};
|
|
247
242
|
|
|
248
243
|
const config = statusConfig[workflow.status] || statusConfig.inactive;
|
|
@@ -261,14 +256,14 @@ function createWorkflowCard(workflow) {
|
|
|
261
256
|
</div>
|
|
262
257
|
|
|
263
258
|
<div class="workflow-card-body">
|
|
264
|
-
<p class="workflow-description">${workflow.description || '
|
|
259
|
+
<p class="workflow-description">${workflow.description || '无描�?}</p>
|
|
265
260
|
<div class="workflow-info-row">
|
|
266
|
-
<span class="info-label"
|
|
261
|
+
<span class="info-label">触发�?/span>
|
|
267
262
|
<span class="info-value">${getTriggerText(workflow.trigger)}</span>
|
|
268
263
|
</div>
|
|
269
264
|
<div class="workflow-info-row">
|
|
270
265
|
<span class="info-label">执行次数</span>
|
|
271
|
-
<span class="info-value">${workflow.executionCount || 0}
|
|
266
|
+
<span class="info-value">${workflow.executionCount || 0} �?/span>
|
|
272
267
|
</div>
|
|
273
268
|
</div>
|
|
274
269
|
|
|
@@ -280,15 +275,14 @@ function createWorkflowCard(workflow) {
|
|
|
280
275
|
<span>✏️</span> 编辑
|
|
281
276
|
</button>
|
|
282
277
|
<button class="btn-action btn-delete" data-id="${workflow._id}">
|
|
283
|
-
<span
|
|
278
|
+
<span>🗑�?/span> 删除
|
|
284
279
|
</button>
|
|
285
280
|
</div>
|
|
286
281
|
</div>
|
|
287
282
|
`;
|
|
288
283
|
}
|
|
289
284
|
|
|
290
|
-
//
|
|
291
|
-
function getTriggerText(trigger) {
|
|
285
|
+
// 获取触发器文�?function getTriggerText(trigger) {
|
|
292
286
|
if (!trigger) return '未知';
|
|
293
287
|
|
|
294
288
|
const typeMap = {
|
|
@@ -302,7 +296,7 @@ function getTriggerText(trigger) {
|
|
|
302
296
|
'document_update': '文档更新',
|
|
303
297
|
'task_create': '任务创建',
|
|
304
298
|
'task_complete': '任务完成',
|
|
305
|
-
'message_send': '
|
|
299
|
+
'message_send': '消息发�?
|
|
306
300
|
};
|
|
307
301
|
|
|
308
302
|
if (trigger.type === 'event' && trigger.event) {
|
|
@@ -537,8 +531,7 @@ function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
|
537
531
|
});
|
|
538
532
|
});
|
|
539
533
|
|
|
540
|
-
//
|
|
541
|
-
document.getElementById('createWorkflowBtn')?.addEventListener('click', () => {
|
|
534
|
+
// 创建工作流按�? document.getElementById('createWorkflowBtn')?.addEventListener('click', () => {
|
|
542
535
|
openWorkflowModal('custom');
|
|
543
536
|
});
|
|
544
537
|
|
|
@@ -563,8 +556,7 @@ function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
|
563
556
|
|
|
564
557
|
// 动作类型变化
|
|
565
558
|
document.getElementById('actionType')?.addEventListener('change', (e) => {
|
|
566
|
-
//
|
|
567
|
-
document.querySelectorAll('.action-config').forEach(el => el.classList.add('hidden'));
|
|
559
|
+
// 隐藏所有配�? document.querySelectorAll('.action-config').forEach(el => el.classList.add('hidden'));
|
|
568
560
|
|
|
569
561
|
// 显示对应配置
|
|
570
562
|
const configMap = {
|
|
@@ -580,8 +572,7 @@ function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
|
580
572
|
}
|
|
581
573
|
});
|
|
582
574
|
|
|
583
|
-
//
|
|
584
|
-
document.getElementById('enableCondition')?.addEventListener('change', (e) => {
|
|
575
|
+
// 条件过滤开�? document.getElementById('enableCondition')?.addEventListener('change', (e) => {
|
|
585
576
|
const conditionConfig = document.getElementById('conditionConfig');
|
|
586
577
|
if (e.target.checked) {
|
|
587
578
|
conditionConfig.classList.remove('hidden');
|
|
@@ -590,21 +581,19 @@ function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
|
590
581
|
}
|
|
591
582
|
});
|
|
592
583
|
|
|
593
|
-
//
|
|
594
|
-
document.getElementById('createWorkflowForm')?.addEventListener('submit', async (e) => {
|
|
584
|
+
// 创建工作流表单提�? document.getElementById('createWorkflowForm')?.addEventListener('submit', async (e) => {
|
|
595
585
|
e.preventDefault();
|
|
596
586
|
await createWorkflow(token, container, currentGroup, apiService);
|
|
597
587
|
});
|
|
598
588
|
|
|
599
|
-
//
|
|
600
|
-
document.querySelectorAll('.btn-toggle').forEach(btn => {
|
|
589
|
+
// 工作流操作按�? document.querySelectorAll('.btn-toggle').forEach(btn => {
|
|
601
590
|
btn.addEventListener('click', async () => {
|
|
602
591
|
const workflowId = btn.dataset.id;
|
|
603
592
|
const currentStatus = btn.dataset.status;
|
|
604
593
|
const newStatus = currentStatus === 'active' ? 'inactive' : 'active';
|
|
605
594
|
|
|
606
595
|
try {
|
|
607
|
-
await fetch(`http://localhost:
|
|
596
|
+
await fetch(`http://localhost:3000/api/workflows/${workflowId}/status`, {
|
|
608
597
|
method: 'PUT',
|
|
609
598
|
headers: {
|
|
610
599
|
'Content-Type': 'application/json',
|
|
@@ -623,11 +612,11 @@ function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
|
623
612
|
|
|
624
613
|
document.querySelectorAll('.btn-delete').forEach(btn => {
|
|
625
614
|
btn.addEventListener('click', async () => {
|
|
626
|
-
if (!confirm('
|
|
615
|
+
if (!confirm('确定要删除此工作流吗�?)) return;
|
|
627
616
|
|
|
628
617
|
const workflowId = btn.dataset.id;
|
|
629
618
|
try {
|
|
630
|
-
await fetch(`http://localhost:
|
|
619
|
+
await fetch(`http://localhost:3000/api/workflows/${workflowId}`, {
|
|
631
620
|
method: 'DELETE',
|
|
632
621
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
633
622
|
});
|
|
@@ -641,8 +630,7 @@ function setupWorkflowEvents(token, container, currentGroup, apiService) {
|
|
|
641
630
|
});
|
|
642
631
|
}
|
|
643
632
|
|
|
644
|
-
//
|
|
645
|
-
function openWorkflowModal(template) {
|
|
633
|
+
// 打开工作流模态框并填充模�?function openWorkflowModal(template) {
|
|
646
634
|
const modal = document.getElementById('createWorkflowModal');
|
|
647
635
|
modal.classList.remove('hidden');
|
|
648
636
|
|
|
@@ -650,7 +638,7 @@ function openWorkflowModal(template) {
|
|
|
650
638
|
const templates = {
|
|
651
639
|
'document-approval': {
|
|
652
640
|
name: '文档审批流程',
|
|
653
|
-
description: '
|
|
641
|
+
description: '文档创建后自动通知管理员审�?,
|
|
654
642
|
trigger: 'document_create',
|
|
655
643
|
action: 'notification',
|
|
656
644
|
notificationMessage: '新文档待审批',
|
|
@@ -658,7 +646,7 @@ function openWorkflowModal(template) {
|
|
|
658
646
|
},
|
|
659
647
|
'task-notification': {
|
|
660
648
|
name: '任务通知流程',
|
|
661
|
-
description: '
|
|
649
|
+
description: '任务创建时自动通知所有成�?,
|
|
662
650
|
trigger: 'task_create',
|
|
663
651
|
action: 'notification',
|
|
664
652
|
notificationMessage: '新任务已分配',
|
|
@@ -666,7 +654,7 @@ function openWorkflowModal(template) {
|
|
|
666
654
|
},
|
|
667
655
|
'auto-backup': {
|
|
668
656
|
name: '自动备份流程',
|
|
669
|
-
description: '每天凌晨2
|
|
657
|
+
description: '每天凌晨2点自动备份数�?,
|
|
670
658
|
trigger: 'scheduled',
|
|
671
659
|
scheduleRule: '0 2 * * *',
|
|
672
660
|
action: 'notification'
|
|
@@ -696,15 +684,13 @@ function openWorkflowModal(template) {
|
|
|
696
684
|
}
|
|
697
685
|
}
|
|
698
686
|
|
|
699
|
-
//
|
|
700
|
-
async function createWorkflow(token, container, currentGroup, apiService) {
|
|
687
|
+
// 创建工作�?async function createWorkflow(token, container, currentGroup, apiService) {
|
|
701
688
|
const name = document.getElementById('workflowName').value;
|
|
702
689
|
const description = document.getElementById('workflowDescription').value;
|
|
703
690
|
const triggerType = document.getElementById('triggerType').value;
|
|
704
691
|
const actionType = document.getElementById('actionType').value;
|
|
705
692
|
|
|
706
|
-
//
|
|
707
|
-
const trigger = {};
|
|
693
|
+
// 构建触发器配�? const trigger = {};
|
|
708
694
|
|
|
709
695
|
// 判断触发类型
|
|
710
696
|
if (triggerType === 'scheduled') {
|
|
@@ -715,8 +701,7 @@ async function createWorkflow(token, container, currentGroup, apiService) {
|
|
|
715
701
|
trigger.event = triggerType;
|
|
716
702
|
}
|
|
717
703
|
|
|
718
|
-
//
|
|
719
|
-
const workflowData = {
|
|
704
|
+
// 构建工作流数�? const workflowData = {
|
|
720
705
|
name,
|
|
721
706
|
description,
|
|
722
707
|
groupId: currentGroup._id,
|
|
@@ -727,7 +712,7 @@ async function createWorkflow(token, container, currentGroup, apiService) {
|
|
|
727
712
|
// 构建动作步骤
|
|
728
713
|
const step = {
|
|
729
714
|
name: actionType === 'notification' ? '发送通知' :
|
|
730
|
-
actionType === 'email' ? '
|
|
715
|
+
actionType === 'email' ? '发送邮�? :
|
|
731
716
|
actionType === 'create_task' ? '创建任务' :
|
|
732
717
|
actionType === 'webhook' ? '调用Webhook' : '执行动作',
|
|
733
718
|
type: actionType,
|
|
@@ -739,8 +724,7 @@ async function createWorkflow(token, container, currentGroup, apiService) {
|
|
|
739
724
|
case 'notification':
|
|
740
725
|
step.config.message = document.getElementById('notificationMessage').value;
|
|
741
726
|
step.config.notificationType = 'system';
|
|
742
|
-
// 根据目标设置接收者(这里简化处理,实际应该获取用户ID
|
|
743
|
-
step.config.recipients = [];
|
|
727
|
+
// 根据目标设置接收者(这里简化处理,实际应该获取用户ID�? step.config.recipients = [];
|
|
744
728
|
break;
|
|
745
729
|
case 'email':
|
|
746
730
|
step.config.notificationType = 'email';
|
|
@@ -775,7 +759,7 @@ async function createWorkflow(token, container, currentGroup, apiService) {
|
|
|
775
759
|
console.log('📤 发送工作流数据:', workflowData);
|
|
776
760
|
|
|
777
761
|
try {
|
|
778
|
-
const response = await fetch('http://localhost:
|
|
762
|
+
const response = await fetch('http://localhost:3000/api/workflows', {
|
|
779
763
|
method: 'POST',
|
|
780
764
|
headers: {
|
|
781
765
|
'Content-Type': 'application/json',
|
|
@@ -785,18 +769,17 @@ async function createWorkflow(token, container, currentGroup, apiService) {
|
|
|
785
769
|
});
|
|
786
770
|
|
|
787
771
|
const result = await response.json();
|
|
788
|
-
console.log('📥
|
|
772
|
+
console.log('📥 服务器响�?', result);
|
|
789
773
|
|
|
790
774
|
if (result.success) {
|
|
791
775
|
alert('工作流创建成功!');
|
|
792
776
|
document.getElementById('createWorkflowModal').classList.add('hidden');
|
|
793
|
-
//
|
|
794
|
-
await renderOptimizedWorkflowView(container, currentGroup, apiService);
|
|
777
|
+
// 重新渲染工作流列�? await renderOptimizedWorkflowView(container, currentGroup, apiService);
|
|
795
778
|
} else {
|
|
796
779
|
alert('创建失败: ' + (result.error?.message || result.message || '未知错误'));
|
|
797
780
|
}
|
|
798
781
|
} catch (error) {
|
|
799
|
-
console.error('
|
|
782
|
+
console.error('�?创建工作流失�?', error);
|
|
800
783
|
alert('创建失败: ' + error.message);
|
|
801
784
|
}
|
|
802
785
|
}
|
|
@@ -804,3 +787,4 @@ async function createWorkflow(token, container, currentGroup, apiService) {
|
|
|
804
787
|
// 导出函数
|
|
805
788
|
export { renderOptimizedWorkflowView };
|
|
806
789
|
|
|
790
|
+
|