diff --git a/clinical-web/src/views/workbench/signing/components/SigningTaskDetail.vue b/clinical-web/src/views/workbench/signing/components/SigningTaskDetail.vue
index 067343b..100c8a8 100644
--- a/clinical-web/src/views/workbench/signing/components/SigningTaskDetail.vue
+++ b/clinical-web/src/views/workbench/signing/components/SigningTaskDetail.vue
@@ -1,5 +1,5 @@
操作留痕
-
- -
+
+
正在加载操作留痕…
+
+ 操作留痕加载失败,请稍后刷新重试
+
+ 暂无操作留痕
+
+
+ -
- {{ event.text }}
+
+ {{ event.text }}
+
+ 第 {{ event.attemptNo }} 次
+ ·
+ {{ event.reason }}
+
+
@@ -62,6 +47,16 @@ const events = computed(() => {
font-size: 12px;
}
+.audit-state {
+ padding: 8px 0 1px;
+ color: var(--mut);
+ font-size: 12px;
+}
+
+.audit-state--error {
+ color: var(--err);
+}
+
.audit-list {
display: flex;
flex-direction: column;
@@ -83,4 +78,15 @@ const events = computed(() => {
flex-shrink: 0;
color: var(--mut);
}
+
+.audit-event-content {
+ display: inline-flex;
+ gap: 4px;
+ flex-wrap: wrap;
+}
+
+.audit-event-content small {
+ color: var(--mut);
+ font-size: 11px;
+}
diff --git a/clinical-web/src/views/workbench/signing/index.vue b/clinical-web/src/views/workbench/signing/index.vue
index 2c5300b..eaa5fed 100644
--- a/clinical-web/src/views/workbench/signing/index.vue
+++ b/clinical-web/src/views/workbench/signing/index.vue
@@ -6,8 +6,10 @@ import { useRoute } from 'vue-router'
import {
completeSigningTask,
getSigningTaskDetail,
+ getSigningTaskEvents,
getSigningTasks,
getSigningTemplates,
+ isSigningMockEnabled,
reopenSigningTask,
resendSigningSms,
updateSigningTaskMethod,
@@ -16,6 +18,7 @@ import {
import type {
SigningDateRange,
SigningMethod,
+ SigningTaskEvent,
SigningTaskRecord,
SigningTaskStatus,
SigningTemplate,
@@ -43,6 +46,7 @@ const STATUS_VALUES: SigningTaskStatus[] = [
'rejected',
'expired',
'void',
+ 'failed',
]
const DATE_RANGE_VALUES: SigningDateRange[] = ['today', 'yesterday', '3d', '7d', 'all']
@@ -53,6 +57,7 @@ const statusLabels: Record = {
rejected: '已拒签',
expired: '已超时',
void: '已作废',
+ failed: '处理失败',
}
const filter = reactive({
@@ -70,9 +75,12 @@ const tasks = ref([])
const total = ref(0)
const selectedTaskId = ref(null)
const selectedTask = ref(null)
+const taskEvents = ref([])
const templates = ref([])
const loading = ref(true)
const detailLoading = ref(false)
+const eventsLoading = ref(false)
+const eventsError = ref(false)
const newDialogVisible = ref(false)
const signatureDialogVisible = ref(false)
const onlineDialogVisible = ref(false)
@@ -121,6 +129,11 @@ const documentOptions = computed(() => [
...templates.value.map((template) => ({ label: template.name, value: template.id })),
])
+const signingApiOptions = computed(() => ({
+ campus: appStore.selectedCampus,
+ templates: templates.value,
+}))
+
function getQueryString(value: unknown) {
return typeof value === 'string' ? value : ''
}
@@ -154,26 +167,47 @@ async function loadTaskDetail(id: string | null) {
if (!id) {
selectedTask.value = null
+ taskEvents.value = []
detailLoading.value = false
+ eventsLoading.value = false
+ eventsError.value = false
return
}
detailLoading.value = true
+ eventsLoading.value = true
+ eventsError.value = false
+ taskEvents.value = []
try {
- const detail = await getSigningTaskDetail(id)
+ const [detailResult, eventsResult] = await Promise.allSettled([
+ getSigningTaskDetail(id, signingApiOptions.value),
+ getSigningTaskEvents(id),
+ ])
if (requestId === detailRequestId) {
- selectedTask.value = detail
+ if (detailResult.status === 'rejected') {
+ throw detailResult.reason
+ }
+
+ selectedTask.value = detailResult.value
+
+ if (eventsResult.status === 'fulfilled') {
+ taskEvents.value = eventsResult.value
+ } else {
+ eventsError.value = true
+ }
}
} catch {
if (requestId === detailRequestId) {
selectedTask.value = null
+ taskEvents.value = []
ElMessage.error('签署任务详情加载失败,请稍后重试')
}
} finally {
if (requestId === detailRequestId) {
detailLoading.value = false
+ eventsLoading.value = false
}
}
}
@@ -183,11 +217,14 @@ async function loadTasks(preferredTaskId?: string) {
loading.value = true
try {
- const response = await getSigningTasks({
- ...filter,
- page: 1,
- pageSize: 50,
- })
+ const response = await getSigningTasks(
+ {
+ ...filter,
+ page: 1,
+ pageSize: 50,
+ },
+ signingApiOptions.value,
+ )
if (requestId !== listRequestId) {
return
@@ -249,11 +286,21 @@ async function handleTaskAction(action: SigningTaskAction) {
}
if (action === 'pad-sign') {
+ if (!isSigningMockEnabled) {
+ ElMessage.info('手写板设备签署接口待接入')
+ return
+ }
+
signatureDialogVisible.value = true
return
}
if (action === 'online-sign') {
+ if (!isSigningMockEnabled) {
+ ElMessage.info('线上签署页面接口待接入')
+ return
+ }
+
onlineDialogVisible.value = true
return
}
@@ -280,6 +327,11 @@ async function handleTaskAction(action: SigningTaskAction) {
try {
if (action === 'switch-method') {
+ if (!isSigningMockEnabled) {
+ ElMessage.info('当前后端未提供切换签署方式接口,请作废后重新创建任务')
+ return
+ }
+
const method: SigningMethod = task.method === 'pad' ? 'sms' : 'pad'
await refreshTask(
await updateSigningTaskMethod(task.id, method),
@@ -289,12 +341,24 @@ async function handleTaskAction(action: SigningTaskAction) {
}
if (action === 'resend-sms') {
- await refreshTask(await resendSigningSms(task.id), '短信已重新发送')
+ await refreshTask(
+ await resendSigningSms(task.id, {
+ ...signingApiOptions.value,
+ expectedRowVersion: task.rowVersion,
+ }),
+ '短信已重新发送',
+ )
return
}
if (action === 'reopen') {
- await refreshTask(await reopenSigningTask(task.id), '签署任务已重新发起')
+ await refreshTask(
+ await reopenSigningTask(task.id, {
+ ...signingApiOptions.value,
+ expectedRowVersion: task.rowVersion,
+ }),
+ '签署任务已重新发起',
+ )
}
} catch {
ElMessage.error('任务操作失败,请稍后重试')
@@ -339,7 +403,13 @@ async function confirmVoidTask(reason: string) {
}
try {
- await refreshTask(await voidSigningTask(task.id, reason), '签署任务已作废')
+ await refreshTask(
+ await voidSigningTask(task.id, reason, {
+ ...signingApiOptions.value,
+ expectedRowVersion: task.rowVersion,
+ }),
+ '签署任务已作废',
+ )
voidDialogVisible.value = false
} catch {
ElMessage.error('任务作废失败,请稍后重试')
@@ -350,6 +420,11 @@ async function handleOnlineResend() {
await handleTaskAction('resend-sms')
}
+async function initializePage() {
+ await loadTemplates()
+ await loadTasks()
+}
+
async function handleTaskCreated(task: SigningTaskRecord) {
await loadTasks(task.id)
}
@@ -375,7 +450,7 @@ watch(
onMounted(() => {
syncFilterFromRoute()
- void Promise.all([loadTemplates(), loadTasks()])
+ void initializePage()
})
@@ -412,7 +487,15 @@ onMounted(() => {
:loading="loading"
@select="selectTask"
/>
-
+