feat(signing): 接入工作台任务操作与审计
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SigningTaskRecord } from '@/api/workbench/types'
|
import type { SigningTaskEvent, SigningTaskRecord } from '@/api/workbench/types'
|
||||||
|
|
||||||
import SigningDocumentPreview from './SigningDocumentPreview.vue'
|
import SigningDocumentPreview from './SigningDocumentPreview.vue'
|
||||||
import TaskAuditTimeline from './TaskAuditTimeline.vue'
|
import TaskAuditTimeline from './TaskAuditTimeline.vue'
|
||||||
@@ -8,6 +8,10 @@ import type { SigningTaskAction } from '../types'
|
|||||||
defineProps<{
|
defineProps<{
|
||||||
task: SigningTaskRecord | null
|
task: SigningTaskRecord | null
|
||||||
loading: boolean
|
loading: boolean
|
||||||
|
auditEvents: SigningTaskEvent[]
|
||||||
|
auditLoading: boolean
|
||||||
|
auditError: boolean
|
||||||
|
allowLocalSigning: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -27,23 +31,33 @@ const emit = defineEmits<{
|
|||||||
<span class="task-action-meta">任务 {{ task.id }} · {{ task.patientName }}</span>
|
<span class="task-action-meta">任务 {{ task.id }} · {{ task.patientName }}</span>
|
||||||
|
|
||||||
<template v-if="task.status === 'pending' && task.method === 'pad'">
|
<template v-if="task.status === 'pending' && task.method === 'pad'">
|
||||||
<button type="button" class="action-button" @click="emit('action', 'pad-sign')">
|
<template v-if="allowLocalSigning">
|
||||||
✍ 手写板签署
|
<button type="button" class="action-button" @click="emit('action', 'pad-sign')">
|
||||||
</button>
|
✍ 手写板签署
|
||||||
<button
|
</button>
|
||||||
type="button"
|
<button
|
||||||
class="action-button action-button--ghost"
|
type="button"
|
||||||
@click="emit('action', 'switch-method')"
|
class="action-button action-button--ghost"
|
||||||
>
|
@click="emit('action', 'switch-method')"
|
||||||
转为短信发送
|
>
|
||||||
</button>
|
转为短信发送
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<span v-else class="action-hint">手写板设备签署接口待接入</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="task.status === 'pending' && task.method === 'sms'">
|
<template v-else-if="task.status === 'pending' && task.method === 'sms'">
|
||||||
<button type="button" class="action-button" @click="emit('action', 'online-sign')">
|
<button
|
||||||
|
v-if="allowLocalSigning"
|
||||||
|
type="button"
|
||||||
|
class="action-button"
|
||||||
|
@click="emit('action', 'online-sign')"
|
||||||
|
>
|
||||||
📱 查看线上签署
|
📱 查看线上签署
|
||||||
</button>
|
</button>
|
||||||
|
<span v-else class="action-hint">线上签署页面接口待接入</span>
|
||||||
<button
|
<button
|
||||||
|
v-if="allowLocalSigning"
|
||||||
type="button"
|
type="button"
|
||||||
class="action-button action-button--ghost"
|
class="action-button action-button--ghost"
|
||||||
@click="emit('action', 'switch-method')"
|
@click="emit('action', 'switch-method')"
|
||||||
@@ -59,7 +73,7 @@ const emit = defineEmits<{
|
|||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="task.status === 'expired'">
|
<template v-else-if="task.status === 'expired' || task.status === 'failed'">
|
||||||
<button type="button" class="action-button" @click="emit('action', 'reopen')">
|
<button type="button" class="action-button" @click="emit('action', 'reopen')">
|
||||||
↻ 重新发起
|
↻ 重新发起
|
||||||
</button>
|
</button>
|
||||||
@@ -90,7 +104,12 @@ const emit = defineEmits<{
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="task.status === 'pending' || task.status === 'expired' || task.status === 'signing'"
|
v-if="
|
||||||
|
task.status === 'pending' ||
|
||||||
|
task.status === 'expired' ||
|
||||||
|
task.status === 'signing' ||
|
||||||
|
task.status === 'failed'
|
||||||
|
"
|
||||||
type="button"
|
type="button"
|
||||||
class="action-button action-button--danger"
|
class="action-button action-button--danger"
|
||||||
@click="emit('action', 'void')"
|
@click="emit('action', 'void')"
|
||||||
@@ -100,7 +119,7 @@ const emit = defineEmits<{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SigningDocumentPreview :task="task" />
|
<SigningDocumentPreview :task="task" />
|
||||||
<TaskAuditTimeline :task="task" />
|
<TaskAuditTimeline :events="auditEvents" :loading="auditLoading" :error="auditError" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-else class="detail-empty">
|
<div v-else class="detail-empty">
|
||||||
@@ -131,6 +150,15 @@ const emit = defineEmits<{
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-hint {
|
||||||
|
padding: 8px 12px;
|
||||||
|
color: var(--mut);
|
||||||
|
font-size: 12px;
|
||||||
|
background: #f7fafb;
|
||||||
|
border: 1px dashed var(--line);
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const statusLabels: Record<SigningTaskRecord['status'], string> = {
|
|||||||
rejected: '已拒签',
|
rejected: '已拒签',
|
||||||
expired: '已超时',
|
expired: '已超时',
|
||||||
void: '已作废',
|
void: '已作废',
|
||||||
|
failed: '处理失败',
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatusClass(task: SigningTaskRecord) {
|
function getStatusClass(task: SigningTaskRecord) {
|
||||||
@@ -217,6 +218,11 @@ function getVisitClass(type: SigningTaskRecord['visitType']) {
|
|||||||
background: var(--err-l);
|
background: var(--err-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task-status--failed {
|
||||||
|
color: #a15c19;
|
||||||
|
background: #fff3df;
|
||||||
|
}
|
||||||
|
|
||||||
.task-status--void {
|
.task-status--void {
|
||||||
color: #8a9aa3;
|
color: #8a9aa3;
|
||||||
background: #eceef0;
|
background: #eceef0;
|
||||||
|
|||||||
@@ -1,49 +1,34 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import type { SigningTaskEvent } from '@/api/workbench/types'
|
||||||
|
|
||||||
import type { SigningTaskRecord } from '@/api/workbench/types'
|
defineProps<{
|
||||||
|
events: SigningTaskEvent[]
|
||||||
const props = defineProps<{
|
loading: boolean
|
||||||
task: SigningTaskRecord
|
error: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const events = computed(() => {
|
|
||||||
const result = [
|
|
||||||
{
|
|
||||||
time: props.task.updatedAt,
|
|
||||||
text: `张文静发起签署任务(${props.task.method === 'pad' ? '手写板' : '线上短信'})`,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
if (props.task.status === 'signing') {
|
|
||||||
result.push({ time: props.task.updatedAt, text: '已打开签名采集,等待患者完成签名' })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.task.signedAt) {
|
|
||||||
result.push({
|
|
||||||
time: props.task.signedAt,
|
|
||||||
text: `患者 ${props.task.patientName} 完成签名,系统自动合成并双留存`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.task.status === 'void') {
|
|
||||||
result.push({
|
|
||||||
time: props.task.updatedAt,
|
|
||||||
text: `任务已作废${props.task.voidReason ? `,原因:${props.task.voidReason}` : ''},全程可审计`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="audit-card">
|
<section class="audit-card">
|
||||||
<strong>操作留痕</strong>
|
<strong>操作留痕</strong>
|
||||||
<ol class="audit-list">
|
|
||||||
<li v-for="event in events" :key="`${event.time}-${event.text}`">
|
<div v-if="loading" class="audit-state">正在加载操作留痕…</div>
|
||||||
|
<div v-else-if="error" class="audit-state audit-state--error">
|
||||||
|
操作留痕加载失败,请稍后刷新重试
|
||||||
|
</div>
|
||||||
|
<div v-else-if="!events.length" class="audit-state">暂无操作留痕</div>
|
||||||
|
|
||||||
|
<ol v-else class="audit-list">
|
||||||
|
<li v-for="event in events" :key="event.id">
|
||||||
<time>{{ event.time }}</time>
|
<time>{{ event.time }}</time>
|
||||||
<span>{{ event.text }}</span>
|
<span class="audit-event-content">
|
||||||
|
<span>{{ event.text }}</span>
|
||||||
|
<small v-if="event.attemptNo || event.reason">
|
||||||
|
<template v-if="event.attemptNo">第 {{ event.attemptNo }} 次</template>
|
||||||
|
<template v-if="event.attemptNo && event.reason"> · </template>
|
||||||
|
<template v-if="event.reason">{{ event.reason }}</template>
|
||||||
|
</small>
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
@@ -62,6 +47,16 @@ const events = computed(() => {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audit-state {
|
||||||
|
padding: 8px 0 1px;
|
||||||
|
color: var(--mut);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audit-state--error {
|
||||||
|
color: var(--err);
|
||||||
|
}
|
||||||
|
|
||||||
.audit-list {
|
.audit-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -83,4 +78,15 @@ const events = computed(() => {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
color: var(--mut);
|
color: var(--mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audit-event-content {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 4px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audit-event-content small {
|
||||||
|
color: var(--mut);
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import { useRoute } from 'vue-router'
|
|||||||
import {
|
import {
|
||||||
completeSigningTask,
|
completeSigningTask,
|
||||||
getSigningTaskDetail,
|
getSigningTaskDetail,
|
||||||
|
getSigningTaskEvents,
|
||||||
getSigningTasks,
|
getSigningTasks,
|
||||||
getSigningTemplates,
|
getSigningTemplates,
|
||||||
|
isSigningMockEnabled,
|
||||||
reopenSigningTask,
|
reopenSigningTask,
|
||||||
resendSigningSms,
|
resendSigningSms,
|
||||||
updateSigningTaskMethod,
|
updateSigningTaskMethod,
|
||||||
@@ -16,6 +18,7 @@ import {
|
|||||||
import type {
|
import type {
|
||||||
SigningDateRange,
|
SigningDateRange,
|
||||||
SigningMethod,
|
SigningMethod,
|
||||||
|
SigningTaskEvent,
|
||||||
SigningTaskRecord,
|
SigningTaskRecord,
|
||||||
SigningTaskStatus,
|
SigningTaskStatus,
|
||||||
SigningTemplate,
|
SigningTemplate,
|
||||||
@@ -43,6 +46,7 @@ const STATUS_VALUES: SigningTaskStatus[] = [
|
|||||||
'rejected',
|
'rejected',
|
||||||
'expired',
|
'expired',
|
||||||
'void',
|
'void',
|
||||||
|
'failed',
|
||||||
]
|
]
|
||||||
const DATE_RANGE_VALUES: SigningDateRange[] = ['today', 'yesterday', '3d', '7d', 'all']
|
const DATE_RANGE_VALUES: SigningDateRange[] = ['today', 'yesterday', '3d', '7d', 'all']
|
||||||
|
|
||||||
@@ -53,6 +57,7 @@ const statusLabels: Record<SigningTaskStatus, string> = {
|
|||||||
rejected: '已拒签',
|
rejected: '已拒签',
|
||||||
expired: '已超时',
|
expired: '已超时',
|
||||||
void: '已作废',
|
void: '已作废',
|
||||||
|
failed: '处理失败',
|
||||||
}
|
}
|
||||||
|
|
||||||
const filter = reactive<SigningFilterForm>({
|
const filter = reactive<SigningFilterForm>({
|
||||||
@@ -70,9 +75,12 @@ const tasks = ref<SigningTaskRecord[]>([])
|
|||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const selectedTaskId = ref<string | null>(null)
|
const selectedTaskId = ref<string | null>(null)
|
||||||
const selectedTask = ref<SigningTaskRecord | null>(null)
|
const selectedTask = ref<SigningTaskRecord | null>(null)
|
||||||
|
const taskEvents = ref<SigningTaskEvent[]>([])
|
||||||
const templates = ref<SigningTemplate[]>([])
|
const templates = ref<SigningTemplate[]>([])
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const detailLoading = ref(false)
|
const detailLoading = ref(false)
|
||||||
|
const eventsLoading = ref(false)
|
||||||
|
const eventsError = ref(false)
|
||||||
const newDialogVisible = ref(false)
|
const newDialogVisible = ref(false)
|
||||||
const signatureDialogVisible = ref(false)
|
const signatureDialogVisible = ref(false)
|
||||||
const onlineDialogVisible = ref(false)
|
const onlineDialogVisible = ref(false)
|
||||||
@@ -121,6 +129,11 @@ const documentOptions = computed<SigningFilterOption[]>(() => [
|
|||||||
...templates.value.map((template) => ({ label: template.name, value: template.id })),
|
...templates.value.map((template) => ({ label: template.name, value: template.id })),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const signingApiOptions = computed(() => ({
|
||||||
|
campus: appStore.selectedCampus,
|
||||||
|
templates: templates.value,
|
||||||
|
}))
|
||||||
|
|
||||||
function getQueryString(value: unknown) {
|
function getQueryString(value: unknown) {
|
||||||
return typeof value === 'string' ? value : ''
|
return typeof value === 'string' ? value : ''
|
||||||
}
|
}
|
||||||
@@ -154,26 +167,47 @@ async function loadTaskDetail(id: string | null) {
|
|||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
selectedTask.value = null
|
selectedTask.value = null
|
||||||
|
taskEvents.value = []
|
||||||
detailLoading.value = false
|
detailLoading.value = false
|
||||||
|
eventsLoading.value = false
|
||||||
|
eventsError.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
detailLoading.value = true
|
detailLoading.value = true
|
||||||
|
eventsLoading.value = true
|
||||||
|
eventsError.value = false
|
||||||
|
taskEvents.value = []
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const detail = await getSigningTaskDetail(id)
|
const [detailResult, eventsResult] = await Promise.allSettled([
|
||||||
|
getSigningTaskDetail(id, signingApiOptions.value),
|
||||||
|
getSigningTaskEvents(id),
|
||||||
|
])
|
||||||
|
|
||||||
if (requestId === detailRequestId) {
|
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 {
|
} catch {
|
||||||
if (requestId === detailRequestId) {
|
if (requestId === detailRequestId) {
|
||||||
selectedTask.value = null
|
selectedTask.value = null
|
||||||
|
taskEvents.value = []
|
||||||
ElMessage.error('签署任务详情加载失败,请稍后重试')
|
ElMessage.error('签署任务详情加载失败,请稍后重试')
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (requestId === detailRequestId) {
|
if (requestId === detailRequestId) {
|
||||||
detailLoading.value = false
|
detailLoading.value = false
|
||||||
|
eventsLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,11 +217,14 @@ async function loadTasks(preferredTaskId?: string) {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await getSigningTasks({
|
const response = await getSigningTasks(
|
||||||
...filter,
|
{
|
||||||
page: 1,
|
...filter,
|
||||||
pageSize: 50,
|
page: 1,
|
||||||
})
|
pageSize: 50,
|
||||||
|
},
|
||||||
|
signingApiOptions.value,
|
||||||
|
)
|
||||||
|
|
||||||
if (requestId !== listRequestId) {
|
if (requestId !== listRequestId) {
|
||||||
return
|
return
|
||||||
@@ -249,11 +286,21 @@ async function handleTaskAction(action: SigningTaskAction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'pad-sign') {
|
if (action === 'pad-sign') {
|
||||||
|
if (!isSigningMockEnabled) {
|
||||||
|
ElMessage.info('手写板设备签署接口待接入')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
signatureDialogVisible.value = true
|
signatureDialogVisible.value = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'online-sign') {
|
if (action === 'online-sign') {
|
||||||
|
if (!isSigningMockEnabled) {
|
||||||
|
ElMessage.info('线上签署页面接口待接入')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
onlineDialogVisible.value = true
|
onlineDialogVisible.value = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -280,6 +327,11 @@ async function handleTaskAction(action: SigningTaskAction) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (action === 'switch-method') {
|
if (action === 'switch-method') {
|
||||||
|
if (!isSigningMockEnabled) {
|
||||||
|
ElMessage.info('当前后端未提供切换签署方式接口,请作废后重新创建任务')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const method: SigningMethod = task.method === 'pad' ? 'sms' : 'pad'
|
const method: SigningMethod = task.method === 'pad' ? 'sms' : 'pad'
|
||||||
await refreshTask(
|
await refreshTask(
|
||||||
await updateSigningTaskMethod(task.id, method),
|
await updateSigningTaskMethod(task.id, method),
|
||||||
@@ -289,12 +341,24 @@ async function handleTaskAction(action: SigningTaskAction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'resend-sms') {
|
if (action === 'resend-sms') {
|
||||||
await refreshTask(await resendSigningSms(task.id), '短信已重新发送')
|
await refreshTask(
|
||||||
|
await resendSigningSms(task.id, {
|
||||||
|
...signingApiOptions.value,
|
||||||
|
expectedRowVersion: task.rowVersion,
|
||||||
|
}),
|
||||||
|
'短信已重新发送',
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'reopen') {
|
if (action === 'reopen') {
|
||||||
await refreshTask(await reopenSigningTask(task.id), '签署任务已重新发起')
|
await refreshTask(
|
||||||
|
await reopenSigningTask(task.id, {
|
||||||
|
...signingApiOptions.value,
|
||||||
|
expectedRowVersion: task.rowVersion,
|
||||||
|
}),
|
||||||
|
'签署任务已重新发起',
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error('任务操作失败,请稍后重试')
|
ElMessage.error('任务操作失败,请稍后重试')
|
||||||
@@ -339,7 +403,13 @@ async function confirmVoidTask(reason: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await refreshTask(await voidSigningTask(task.id, reason), '签署任务已作废')
|
await refreshTask(
|
||||||
|
await voidSigningTask(task.id, reason, {
|
||||||
|
...signingApiOptions.value,
|
||||||
|
expectedRowVersion: task.rowVersion,
|
||||||
|
}),
|
||||||
|
'签署任务已作废',
|
||||||
|
)
|
||||||
voidDialogVisible.value = false
|
voidDialogVisible.value = false
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error('任务作废失败,请稍后重试')
|
ElMessage.error('任务作废失败,请稍后重试')
|
||||||
@@ -350,6 +420,11 @@ async function handleOnlineResend() {
|
|||||||
await handleTaskAction('resend-sms')
|
await handleTaskAction('resend-sms')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initializePage() {
|
||||||
|
await loadTemplates()
|
||||||
|
await loadTasks()
|
||||||
|
}
|
||||||
|
|
||||||
async function handleTaskCreated(task: SigningTaskRecord) {
|
async function handleTaskCreated(task: SigningTaskRecord) {
|
||||||
await loadTasks(task.id)
|
await loadTasks(task.id)
|
||||||
}
|
}
|
||||||
@@ -375,7 +450,7 @@ watch(
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
syncFilterFromRoute()
|
syncFilterFromRoute()
|
||||||
void Promise.all([loadTemplates(), loadTasks()])
|
void initializePage()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -412,7 +487,15 @@ onMounted(() => {
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
@select="selectTask"
|
@select="selectTask"
|
||||||
/>
|
/>
|
||||||
<SigningTaskDetail :task="selectedTask" :loading="detailLoading" @action="handleTaskAction" />
|
<SigningTaskDetail
|
||||||
|
:task="selectedTask"
|
||||||
|
:loading="detailLoading"
|
||||||
|
:audit-events="taskEvents"
|
||||||
|
:audit-loading="eventsLoading"
|
||||||
|
:audit-error="eventsError"
|
||||||
|
:allow-local-signing="isSigningMockEnabled"
|
||||||
|
@action="handleTaskAction"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NewSigningTaskDialog
|
<NewSigningTaskDialog
|
||||||
|
|||||||
Reference in New Issue
Block a user