@jari-ace/element-plus-component 0.4.4 → 0.5.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/dist/components/avatar/JaAvatar.vue.d.ts.map +1 -1
- package/dist/components/avatar/JaAvatar.vue.js +4 -2
- package/dist/components/avatar/JaAvatar.vue.js.map +1 -1
- package/dist/components/flowShell/FlowFormShell.vue.d.ts +403 -0
- package/dist/components/flowShell/FlowFormShell.vue.d.ts.map +1 -0
- package/dist/components/flowShell/FlowFormShell.vue.js +671 -0
- package/dist/components/flowShell/FlowFormShell.vue.js.map +1 -0
- package/dist/components/flowShell/index.d.ts +4 -0
- package/dist/components/flowShell/index.d.ts.map +1 -0
- package/dist/components/flowShell/index.js +4 -0
- package/dist/components/flowShell/index.js.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/upload/uploader.vue.d.ts.map +1 -1
- package/dist/components/upload/uploader.vue.js +1 -2
- package/dist/components/upload/uploader.vue.js.map +1 -1
- package/dist/components/userPicker/src/JaUserList.vue.d.ts.map +1 -1
- package/dist/components/userPicker/src/JaUserList.vue.js +0 -2
- package/dist/components/userPicker/src/JaUserList.vue.js.map +1 -1
- package/dist/components/userTag/UserInfoTag.vue.d.ts +1 -1
- package/dist/components/userTag/UserInfoTag.vue.d.ts.map +1 -1
- package/dist/components/userTag/UserInfoTag.vue.js +2 -2
- package/dist/components/userTag/UserInfoTag.vue.js.map +1 -1
- package/dist/hooks/useRouteableVisible.d.ts +12 -0
- package/dist/hooks/useRouteableVisible.d.ts.map +1 -0
- package/dist/hooks/useRouteableVisible.js +34 -0
- package/dist/hooks/useRouteableVisible.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.js +10623 -9904
- package/lib/index.umd.cjs +39 -35
- package/package.json +4 -2
- package/packages/components/avatar/JaAvatar.vue +4 -2
- package/packages/components/flowShell/FlowFormShell.vue +628 -0
- package/packages/components/flowShell/index.ts +5 -0
- package/packages/components/index.ts +1 -0
- package/packages/components/upload/uploader.vue +1 -2
- package/packages/components/userPicker/src/JaUserList.vue +0 -1
- package/packages/components/userTag/UserInfoTag.vue +2 -2
- package/packages/hooks/useRouteableVisible.ts +35 -0
- package/packages/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jari-ace/element-plus-component",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"main": "lib/index.umd.cjs",
|
|
6
6
|
"module": "lib/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -23,9 +23,11 @@
|
|
|
23
23
|
"@uppy/vue": "^3.1.0",
|
|
24
24
|
"@uppy/webcam": "^5.0.2",
|
|
25
25
|
"animate.css": "^4.1.1",
|
|
26
|
+
"dayjs": "^1.11.13",
|
|
26
27
|
"pretty-bytes": "^7.1.0",
|
|
27
28
|
"vue-pdf-embed": "^2.1.3",
|
|
28
|
-
"
|
|
29
|
+
"vue-router": "^5.0.1",
|
|
30
|
+
"@jari-ace/app-bolts": "0.7.0"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
33
|
"@types/lodash-es": "^4.17.12",
|
|
@@ -71,13 +71,15 @@ const lazyUrl = computed(() => {
|
|
|
71
71
|
}
|
|
72
72
|
if (props.userId && props.userId.length > 0) {
|
|
73
73
|
const path = '/ace-app-service/avatar/' + props.userId
|
|
74
|
-
|
|
74
|
+
const win = window.rawWindow? window.rawWindow: window
|
|
75
|
+
return win.appDescriptor.env.isDevMode()
|
|
75
76
|
? new URL("/ace" + path, location.origin).toString() + "?t=" + token.value.toString() //开发模式下使用vite代理,添加ace前缀,由vite代理修改路由
|
|
76
77
|
: new URL(path, location.origin).toString() + "?t=" + token.value.toString()
|
|
77
78
|
}
|
|
78
79
|
if (props.realm && props.realm.length > 0 && props.username && props.username.length > 0) {
|
|
79
80
|
const path = '/ace-app-service/avatar/' + props.realm + '/' + props.username
|
|
80
|
-
|
|
81
|
+
const win = window.rawWindow? window.rawWindow: window
|
|
82
|
+
return win.appDescriptor.env.isDevMode()
|
|
81
83
|
? new URL("/ace" + path, location.origin).toString() + "?t=" + token.value.toString() //开发模式下使用vite代理,添加ace前缀,由vite代理修改路由
|
|
82
84
|
: new URL(path, location.origin).toString() + "?t=" + token.value.toString()
|
|
83
85
|
}
|
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="dialogVisible" class="flow-shell-wrapper">
|
|
3
|
+
<div class="flow-shell-container" v-loading="isLoading">
|
|
4
|
+
<header class="flow-shell-header">
|
|
5
|
+
<div class="header-content">
|
|
6
|
+
<div class="header-top">
|
|
7
|
+
<div class="back-button-wrapper" @click="dialogVisible = false">
|
|
8
|
+
<el-icon :size="40">
|
|
9
|
+
<ArrowLeft />
|
|
10
|
+
</el-icon>
|
|
11
|
+
</div>
|
|
12
|
+
<div>
|
|
13
|
+
<div class="title-section">
|
|
14
|
+
<h2 class="flow-title">{{ flowFormParam?.flowDefinition?.flowModel?.flowCaption || '流程详情' }}</h2>
|
|
15
|
+
<el-tag :type="flowStateTagType">{{
|
|
16
|
+
getFlowStatus(flowFormParam?.flowInstance?.state) }}</el-tag>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="header-bottom" v-if="flowFormParam?.flowInstance">
|
|
19
|
+
<div class="info-item">
|
|
20
|
+
<span class="label">发起人:</span>
|
|
21
|
+
<ja-user-info-tag :user-id="flowFormParam?.flowInstance?.initiator" show-avatar-in-tag
|
|
22
|
+
:full-name="flowFormParam?.flowInstance?.initiatorName">
|
|
23
|
+
</ja-user-info-tag>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="info-item">
|
|
26
|
+
<span class="label">发起时间:</span>
|
|
27
|
+
<el-tooltip :content="formatDate(flowFormParam?.flowInstance?.createTime)" placement="top"
|
|
28
|
+
v-if="flowFormParam?.flowInstance?.createTime">
|
|
29
|
+
<span class="value">{{ formatFriendlyTime(flowFormParam?.flowInstance?.createTime) }}</span>
|
|
30
|
+
</el-tooltip>
|
|
31
|
+
<span class="value" v-else>-</span>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="info-item" v-if="flowFormParam?.flowInstance?.workNo">
|
|
34
|
+
<span class="label">工作文号:</span>
|
|
35
|
+
<span class="value">{{ flowFormParam?.flowInstance?.workNo }}</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</header>
|
|
42
|
+
|
|
43
|
+
<!-- 主体内容区 -->
|
|
44
|
+
<main class="flow-shell-main">
|
|
45
|
+
<!-- 左侧内容区 -->
|
|
46
|
+
<section class="main-content">
|
|
47
|
+
<div class="content-wrapper">
|
|
48
|
+
<div v-if="error" class="error-tip">
|
|
49
|
+
<el-result icon="error" title="加载失败" :sub-title="error">
|
|
50
|
+
<template #extra>
|
|
51
|
+
<el-button type="primary" @click="loadFlowFormParam">重试</el-button>
|
|
52
|
+
</template>
|
|
53
|
+
</el-result>
|
|
54
|
+
</div>
|
|
55
|
+
<div v-else-if="flowFormParam">
|
|
56
|
+
<slot name="default" :flowParam="flowFormParam"></slot>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="no-form-tip" v-else>
|
|
59
|
+
<el-empty description="暂无表单内容" />
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
|
|
64
|
+
<!-- 右侧辅助面板 -->
|
|
65
|
+
<aside class="side-panel">
|
|
66
|
+
<div class="side-panel-header">
|
|
67
|
+
<h3>办理历史</h3>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="side-panel-content">
|
|
70
|
+
<el-timeline v-if="sortedTasks.length > 0">
|
|
71
|
+
<el-timeline-item v-for="(task, index) in sortedTasks" :key="index"
|
|
72
|
+
:timestamp="formatFriendlyTime(task.finishTime)" placement="top">
|
|
73
|
+
<el-card>
|
|
74
|
+
<div class="task-info">
|
|
75
|
+
<div class="handler-info">
|
|
76
|
+
<span class="handler-name">{{ task.handlerName || '未知' }}</span>
|
|
77
|
+
<el-tooltip :content="formatDate(task.finishTime)" placement="top">
|
|
78
|
+
<span class="task-status">{{ getTaskStatus(task.state) }}</span>
|
|
79
|
+
</el-tooltip>
|
|
80
|
+
</div>
|
|
81
|
+
<div class="task-comment" v-if="task.comment">
|
|
82
|
+
<span class="comment-label">意见:</span>
|
|
83
|
+
<span class="comment-content">{{ task.comment }}</span>
|
|
84
|
+
</div>
|
|
85
|
+
<div class="task-comment" v-else>
|
|
86
|
+
<span class="comment-label">意见:</span>
|
|
87
|
+
<span class="comment-content empty">无</span>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</el-card>
|
|
91
|
+
</el-timeline-item>
|
|
92
|
+
</el-timeline>
|
|
93
|
+
<div v-else class="no-history-tip">
|
|
94
|
+
<el-empty description="暂无办理历史" :image-size="100" />
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</aside>
|
|
98
|
+
</main>
|
|
99
|
+
|
|
100
|
+
<!-- 底部工具栏 -->
|
|
101
|
+
<footer class="flow-shell-footer">
|
|
102
|
+
<ja-button @click="handleSave" shortcut="Ctrl+S" tooltip="保存" :loading="saving"
|
|
103
|
+
:disabled="saving">保存</ja-button>
|
|
104
|
+
<ja-button @click="handleForward" type="danger" shortcut="Ctrl+F" v-if="showForwardButton"
|
|
105
|
+
:tooltip="'保存并' + (flowFormParam?.taskInstance ? '结束当前工作步骤办理' : '发起工作')" :loading="saving"
|
|
106
|
+
:disabled="saving">{{
|
|
107
|
+
flowFormParam?.taskInstance ? "办理结束" : "发起工作" }}</ja-button>
|
|
108
|
+
</footer>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
112
|
+
|
|
113
|
+
<script setup lang="ts" generic="T extends Record<string, any>">
|
|
114
|
+
import { ref, watch, computed, nextTick } from 'vue'
|
|
115
|
+
import { useTaskQueryApi, useFlowDefinitionApi, type FlowFormParamDto } from '@jari-ace/app-bolts'
|
|
116
|
+
import type { FlowProcessRequest, TaskInstanceDto } from '@jari-ace/app-bolts'
|
|
117
|
+
import { createAxiosWithoutCache, useLoading } from '@jari-ace/app-bolts'
|
|
118
|
+
import { ElMessage, ElTag, ElCard, ElButton, ElTimeline, ElTimelineItem, ElEmpty, ElIcon, ElResult } from 'element-plus'
|
|
119
|
+
import { JaButton } from '../button'
|
|
120
|
+
import { JaUserInfoTag } from '../userTag'
|
|
121
|
+
import { ArrowLeft } from '@element-plus/icons-vue'
|
|
122
|
+
import dayjs from 'dayjs'
|
|
123
|
+
import relativeTime from 'dayjs/plugin/relativeTime'
|
|
124
|
+
import 'dayjs/locale/zh-cn'
|
|
125
|
+
import { ElTooltip } from 'element-plus'
|
|
126
|
+
import { isVisible } from 'element-plus/es/utils/index.mjs'
|
|
127
|
+
dayjs.extend(relativeTime)
|
|
128
|
+
dayjs.locale('zh-cn')
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
const props = withDefaults(defineProps<{
|
|
132
|
+
/**
|
|
133
|
+
* 应用名称
|
|
134
|
+
*/
|
|
135
|
+
appName?: string
|
|
136
|
+
/**
|
|
137
|
+
* 流程定义Key
|
|
138
|
+
*/
|
|
139
|
+
flowKey?: string
|
|
140
|
+
/**
|
|
141
|
+
* 开始节点Key
|
|
142
|
+
*/
|
|
143
|
+
startNodeKey?: string
|
|
144
|
+
/**
|
|
145
|
+
* 任务实例ID
|
|
146
|
+
*/
|
|
147
|
+
taskId?: string
|
|
148
|
+
/**
|
|
149
|
+
* 表单数据
|
|
150
|
+
*/
|
|
151
|
+
formData: T
|
|
152
|
+
/**
|
|
153
|
+
* 保存表单数据的方法,保存成功时发起或转交工作
|
|
154
|
+
*/
|
|
155
|
+
saveAndForward: (formData: FlowProcessRequest<T>) => Promise<any>
|
|
156
|
+
}>(), {
|
|
157
|
+
appName: undefined,
|
|
158
|
+
flowKey: undefined,
|
|
159
|
+
startNodeKey: undefined,
|
|
160
|
+
taskInstanceId: undefined
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// 内部状态
|
|
164
|
+
const dialogVisible = defineModel<boolean>({
|
|
165
|
+
default: false
|
|
166
|
+
})
|
|
167
|
+
const axios = createAxiosWithoutCache()
|
|
168
|
+
const loading = useLoading(axios)
|
|
169
|
+
const localLoading = ref(false)
|
|
170
|
+
const isLoading = computed(() => loading.value || localLoading.value)
|
|
171
|
+
const saving = ref(false)
|
|
172
|
+
const error = ref('')
|
|
173
|
+
const flowFormParam = ref<FlowFormParamDto | undefined>(undefined)
|
|
174
|
+
const taskQueryApi = useTaskQueryApi(axios)
|
|
175
|
+
const flowDefinitionApi = useFlowDefinitionApi(axios)
|
|
176
|
+
const emits = defineEmits<{
|
|
177
|
+
(e: 'open'): void
|
|
178
|
+
(e: 'closed'): void
|
|
179
|
+
}>();
|
|
180
|
+
|
|
181
|
+
const flowStateTagType = computed(() => {
|
|
182
|
+
switch (flowFormParam.value?.flowInstance?.state) {
|
|
183
|
+
case 0:
|
|
184
|
+
return 'warning'
|
|
185
|
+
case 1:
|
|
186
|
+
return 'success'
|
|
187
|
+
case 2:
|
|
188
|
+
return 'danger'
|
|
189
|
+
default:
|
|
190
|
+
return 'info'
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const showForwardButton = computed(() => {
|
|
195
|
+
return flowFormParam.value?.taskInstance || !flowFormParam.value?.flowInstance
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// 获取排序后的任务列表
|
|
199
|
+
const sortedTasks = computed(() => {
|
|
200
|
+
if (!flowFormParam.value?.flowInstance?.nodes) return []
|
|
201
|
+
|
|
202
|
+
let allTasks: TaskInstanceDto[] = []
|
|
203
|
+
|
|
204
|
+
// 收集所有节点的任务
|
|
205
|
+
Object.values(flowFormParam.value.flowInstance.nodes).forEach(node => {
|
|
206
|
+
allTasks = [...allTasks, ...node.tasks]
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
// 按办结时间排序,最新的在前面
|
|
210
|
+
return allTasks.sort((a, b) => {
|
|
211
|
+
const timeA = a.finishTime ? new Date(a.finishTime).getTime() : 0
|
|
212
|
+
const timeB = b.finishTime ? new Date(b.finishTime).getTime() : 0
|
|
213
|
+
return timeB - timeA
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
// 格式化日期
|
|
218
|
+
const formatDate = (dateStr?: string) => {
|
|
219
|
+
if (!dateStr) return ''
|
|
220
|
+
return dayjs(dateStr).format('YYYY-MM-DD HH:mm:ss')
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// 友好显示时间
|
|
224
|
+
const formatFriendlyTime = (dateStr?: string) => {
|
|
225
|
+
if (!dateStr) return ''
|
|
226
|
+
return dayjs(dateStr).fromNow()
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 获取流程状态文本
|
|
230
|
+
const getFlowStatus = (state?: number) => {
|
|
231
|
+
switch (state) {
|
|
232
|
+
case 0:
|
|
233
|
+
return '进行中'
|
|
234
|
+
case 1:
|
|
235
|
+
return '已完成'
|
|
236
|
+
case 2:
|
|
237
|
+
return '已中止'
|
|
238
|
+
default:
|
|
239
|
+
return '待发起'
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 获取任务状态文本
|
|
244
|
+
const getTaskStatus = (state?: number) => {
|
|
245
|
+
switch (state) {
|
|
246
|
+
case 0:
|
|
247
|
+
return '未激活'
|
|
248
|
+
case 1:
|
|
249
|
+
return '未接收'
|
|
250
|
+
case 2:
|
|
251
|
+
return '已接收'
|
|
252
|
+
case 3:
|
|
253
|
+
return '已办结'
|
|
254
|
+
default:
|
|
255
|
+
return '未知状态'
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 监听dialogVisible变化
|
|
260
|
+
watch(
|
|
261
|
+
() => dialogVisible.value,
|
|
262
|
+
async (newValue) => {
|
|
263
|
+
resetState()
|
|
264
|
+
if (newValue) {
|
|
265
|
+
emits('open')
|
|
266
|
+
// 等待下一个事件循环,确保父组件的open事件处理完成(可能包含异步loadData)
|
|
267
|
+
await nextTick()
|
|
268
|
+
loadFlowFormParam()
|
|
269
|
+
} else {
|
|
270
|
+
emits('closed')
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
// 重置状态
|
|
276
|
+
const resetState = () => {
|
|
277
|
+
error.value = ''
|
|
278
|
+
flowFormParam.value = undefined
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// 加载流程表单参数
|
|
282
|
+
const loadFlowFormParam = async () => {
|
|
283
|
+
resetState()
|
|
284
|
+
const formId = props.formData?.flowFormId;
|
|
285
|
+
// 检查参数
|
|
286
|
+
// 必须提供 taskId,或者 appName 和 flowKey
|
|
287
|
+
if (!props.taskId && !(props.appName && props.flowKey)) {
|
|
288
|
+
ElMessage.error('参数错误: 必须提供taskId或appName、flowKey和flowFormId')
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
if (props.taskId) {
|
|
294
|
+
// 优先使用Id
|
|
295
|
+
flowFormParam.value = await taskQueryApi.getTaskInstanceById(props.taskId)
|
|
296
|
+
} else if (formId) {
|
|
297
|
+
// 使用appName、flowKey、formId
|
|
298
|
+
flowFormParam.value = await taskQueryApi.getTaskByFormIdAndAppAndFlowKey(formId, props.appName!, props.flowKey!)
|
|
299
|
+
} else {
|
|
300
|
+
// 新建模式:只有 appName 和 flowKey,没有 formId
|
|
301
|
+
// 获取流程定义
|
|
302
|
+
const flowDefinition = await flowDefinitionApi.getEffectiveDefinition(props.appName!, props.flowKey!)
|
|
303
|
+
// 构造部分 flowFormParam
|
|
304
|
+
flowFormParam.value = {
|
|
305
|
+
flowDefinition: flowDefinition,
|
|
306
|
+
// 其他字段为空
|
|
307
|
+
} as FlowFormParamDto
|
|
308
|
+
}
|
|
309
|
+
} catch (e: any) {
|
|
310
|
+
ElMessage.error(e.message || '加载流程信息失败')
|
|
311
|
+
error.value = e.message
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 底部按钮处理
|
|
316
|
+
const handleSave = async () => {
|
|
317
|
+
saving.value = true
|
|
318
|
+
try {
|
|
319
|
+
await props.saveAndForward({
|
|
320
|
+
flowArgs: {
|
|
321
|
+
taskId: flowFormParam.value?.taskInstance?.id || '',
|
|
322
|
+
processRequestType: "SAVE_FORM",
|
|
323
|
+
appName: props.appName || '',
|
|
324
|
+
flowKey: props.flowKey || '',
|
|
325
|
+
startNodeKey: props.startNodeKey || '',
|
|
326
|
+
forwardTo: []
|
|
327
|
+
},
|
|
328
|
+
formCommand: props.formData as T
|
|
329
|
+
})
|
|
330
|
+
} finally {
|
|
331
|
+
saving.value = false
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const handleForward = async () => {
|
|
336
|
+
saving.value = true
|
|
337
|
+
try {
|
|
338
|
+
const p = flowFormParam.value
|
|
339
|
+
await props.saveAndForward({
|
|
340
|
+
flowArgs: {
|
|
341
|
+
taskId: p?.taskInstance?.id || '',
|
|
342
|
+
processRequestType: p?.taskInstance ? "FORWARD" : "INITIATE",
|
|
343
|
+
appName: props.appName || '',
|
|
344
|
+
flowKey: props.flowKey || '',
|
|
345
|
+
startNodeKey: props.startNodeKey || '',
|
|
346
|
+
forwardTo: []
|
|
347
|
+
},
|
|
348
|
+
formCommand: props.formData as T
|
|
349
|
+
})
|
|
350
|
+
dialogVisible.value = false
|
|
351
|
+
|
|
352
|
+
} finally {
|
|
353
|
+
saving.value = false
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
</script>
|
|
358
|
+
|
|
359
|
+
<style>
|
|
360
|
+
/* 移除旧的 dialog 样式 */
|
|
361
|
+
</style>
|
|
362
|
+
|
|
363
|
+
<style scoped>
|
|
364
|
+
.flow-shell-wrapper {
|
|
365
|
+
position: fixed;
|
|
366
|
+
top: 0;
|
|
367
|
+
left: 0;
|
|
368
|
+
width: 100%;
|
|
369
|
+
height: 100%;
|
|
370
|
+
background-color: #f5f7fa;
|
|
371
|
+
z-index: 2000;
|
|
372
|
+
display: flex;
|
|
373
|
+
flex-direction: column;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.flow-shell-container {
|
|
377
|
+
width: 100%;
|
|
378
|
+
height: 100%;
|
|
379
|
+
display: flex;
|
|
380
|
+
flex-direction: column;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* 标题区样式 */
|
|
384
|
+
.flow-shell-header {
|
|
385
|
+
background-color: #ffffff;
|
|
386
|
+
border-bottom: 1px solid #e0e0e0;
|
|
387
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
388
|
+
z-index: 10;
|
|
389
|
+
padding: 16px 12px;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.header-content {
|
|
393
|
+
width: 100%;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.header-top {
|
|
397
|
+
display: flex;
|
|
398
|
+
align-items: center;
|
|
399
|
+
margin-bottom: 12px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.back-button-wrapper {
|
|
403
|
+
display: flex;
|
|
404
|
+
align-items: center;
|
|
405
|
+
justify-content: center;
|
|
406
|
+
width: 64px;
|
|
407
|
+
height: 64px;
|
|
408
|
+
border-radius: 50%;
|
|
409
|
+
cursor: pointer;
|
|
410
|
+
transition: all 0.3s;
|
|
411
|
+
margin-right: 12px;
|
|
412
|
+
color: var(--el-color-primary-light-3);
|
|
413
|
+
/* background-color: var(--el-color-primary-light-9); */
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.back-button-wrapper:hover {
|
|
417
|
+
background-color: var(--el-color-primary-light-9);
|
|
418
|
+
color: var(--el-color-primary);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.title-section {
|
|
422
|
+
display: flex;
|
|
423
|
+
align-items: center;
|
|
424
|
+
gap: 12px;
|
|
425
|
+
flex: 1;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.flow-title {
|
|
429
|
+
margin: 0;
|
|
430
|
+
font-size: 20px;
|
|
431
|
+
font-weight: 600;
|
|
432
|
+
color: #303133;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.flow-status {
|
|
436
|
+
font-size: 12px;
|
|
437
|
+
height: 24px;
|
|
438
|
+
line-height: 24px;
|
|
439
|
+
padding: 0 12px;
|
|
440
|
+
color: #409eff;
|
|
441
|
+
border: none;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.header-bottom {
|
|
445
|
+
display: flex;
|
|
446
|
+
gap: 32px;
|
|
447
|
+
align-items: center;
|
|
448
|
+
padding-top: 8px;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.info-item {
|
|
452
|
+
display: flex;
|
|
453
|
+
align-items: center;
|
|
454
|
+
font-size: 14px;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.info-item .label {
|
|
458
|
+
color: #606266;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.info-item .value {
|
|
462
|
+
color: #303133;
|
|
463
|
+
font-weight: 500;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.info-item .dept-name {
|
|
467
|
+
color: #909399;
|
|
468
|
+
font-size: 13px;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* 主体内容区样式 */
|
|
472
|
+
.flow-shell-main {
|
|
473
|
+
flex: 1;
|
|
474
|
+
display: flex;
|
|
475
|
+
gap: 16px;
|
|
476
|
+
overflow: hidden;
|
|
477
|
+
/* 防止被内容撑开 */
|
|
478
|
+
min-height: 0;
|
|
479
|
+
/* flex子项高度计算修复 */
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* 左侧内容区 */
|
|
483
|
+
.main-content {
|
|
484
|
+
flex: 1;
|
|
485
|
+
padding: 0;
|
|
486
|
+
display: flex;
|
|
487
|
+
flex-direction: column;
|
|
488
|
+
overflow: hidden;
|
|
489
|
+
/* 确保内部滚动生效 */
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.content-wrapper {
|
|
493
|
+
background-color: #ffffff;
|
|
494
|
+
border-radius: 4px;
|
|
495
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
496
|
+
height: 100%;
|
|
497
|
+
overflow-y: auto;
|
|
498
|
+
padding: 24px;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.no-form-tip {
|
|
502
|
+
width: 100%;
|
|
503
|
+
height: 100%;
|
|
504
|
+
display: flex;
|
|
505
|
+
align-items: center;
|
|
506
|
+
justify-content: center;
|
|
507
|
+
font-size: 16px;
|
|
508
|
+
color: #909399;
|
|
509
|
+
background-color: #ffffff;
|
|
510
|
+
border-radius: 8px;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/* 右侧辅助面板 */
|
|
514
|
+
.side-panel {
|
|
515
|
+
background-color: #ffffff;
|
|
516
|
+
border-left: 1px solid #e0e0e0;
|
|
517
|
+
display: flex;
|
|
518
|
+
flex-direction: column;
|
|
519
|
+
width: 400px;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.side-panel-header {
|
|
523
|
+
height: 60px;
|
|
524
|
+
border-bottom: 1px solid #e0e0e0;
|
|
525
|
+
display: flex;
|
|
526
|
+
align-items: center;
|
|
527
|
+
padding: 0 20px;
|
|
528
|
+
background-color: #fafafa;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.side-panel-header h3 {
|
|
532
|
+
margin: 0;
|
|
533
|
+
font-size: 16px;
|
|
534
|
+
font-weight: 600;
|
|
535
|
+
color: #303133;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.side-panel-content {
|
|
539
|
+
flex: 1;
|
|
540
|
+
overflow-y: auto;
|
|
541
|
+
padding: 20px;
|
|
542
|
+
position: relative;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
.no-history-tip {
|
|
546
|
+
height: 100%;
|
|
547
|
+
display: flex;
|
|
548
|
+
align-items: center;
|
|
549
|
+
justify-content: center;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* 时间轴样式 */
|
|
553
|
+
.el-timeline {
|
|
554
|
+
padding: 0;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
.el-timeline-item {
|
|
558
|
+
margin-bottom: 20px;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
.el-timeline-item__timestamp {
|
|
562
|
+
font-size: 12px;
|
|
563
|
+
color: #909399;
|
|
564
|
+
margin-bottom: 8px;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/* 任务卡片样式 */
|
|
568
|
+
.task-info {
|
|
569
|
+
display: flex;
|
|
570
|
+
flex-direction: column;
|
|
571
|
+
gap: 12px;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.handler-info {
|
|
575
|
+
display: flex;
|
|
576
|
+
align-items: center;
|
|
577
|
+
justify-content: space-between;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.handler-name {
|
|
581
|
+
font-size: 14px;
|
|
582
|
+
font-weight: 500;
|
|
583
|
+
color: #303133;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.task-status {
|
|
587
|
+
font-size: 12px;
|
|
588
|
+
padding: 2px 8px;
|
|
589
|
+
border-radius: 10px;
|
|
590
|
+
background-color: #ecf5ff;
|
|
591
|
+
color: #409eff;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.task-comment {
|
|
595
|
+
display: flex;
|
|
596
|
+
gap: 8px;
|
|
597
|
+
align-items: flex-start;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.comment-label {
|
|
601
|
+
font-size: 14px;
|
|
602
|
+
color: #606266;
|
|
603
|
+
flex-shrink: 0;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.comment-content {
|
|
607
|
+
font-size: 14px;
|
|
608
|
+
color: #303133;
|
|
609
|
+
line-height: 1.5;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.comment-content.empty {
|
|
613
|
+
color: #909399;
|
|
614
|
+
font-style: italic;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
.flow-shell-footer {
|
|
618
|
+
background-color: #ffffff;
|
|
619
|
+
border-top: 1px solid #e0e0e0;
|
|
620
|
+
padding: 12px 24px;
|
|
621
|
+
display: flex;
|
|
622
|
+
justify-content: flex-start;
|
|
623
|
+
align-items: center;
|
|
624
|
+
gap: 12px;
|
|
625
|
+
box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.05);
|
|
626
|
+
z-index: 100;
|
|
627
|
+
}
|
|
628
|
+
</style>
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
useSystemClassificationLevels
|
|
17
17
|
} from "../../hooks/useClassificationLevels";
|
|
18
18
|
import Ace = Jari.Ace;
|
|
19
|
-
import { ElMessageBox } from "element-plus";
|
|
20
19
|
import "@uppy/core/css/style.min.css";
|
|
21
20
|
import "@uppy/dashboard/css/style.min.css";
|
|
22
21
|
import "@uppy/audio/css/style.min.css";
|
|
@@ -33,8 +32,8 @@ import Dashboard from "@uppy/dashboard";
|
|
|
33
32
|
import ImageEditor from "@uppy/image-editor";
|
|
34
33
|
import prettyBytes from "pretty-bytes";
|
|
35
34
|
import PdfViewerModal from "./pdf-viewer/PdfViewerModal.vue";
|
|
36
|
-
|
|
37
35
|
import {
|
|
36
|
+
ElMessageBox,
|
|
38
37
|
ElTable,
|
|
39
38
|
ElTableColumn,
|
|
40
39
|
ElButton,
|