feat: 提交
This commit is contained in:
@@ -123,7 +123,7 @@ async function loadOverview() {
|
||||
|
||||
function goToSigning(query: Record<string, string> = {}) {
|
||||
void router.push({
|
||||
name: 'workbench-signing',
|
||||
path: '/sign/workbench',
|
||||
query: {
|
||||
campus: selectedCampus.value,
|
||||
...query,
|
||||
@@ -133,7 +133,7 @@ function goToSigning(query: Record<string, string> = {}) {
|
||||
|
||||
function handleMetricClick(key: HomeMetricKey) {
|
||||
if (key === 'templates') {
|
||||
void router.push({ name: 'management-documents' })
|
||||
void router.push('/doc/library')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ onMounted(() => {
|
||||
:rows="rankingRows"
|
||||
:period="rankingPeriod"
|
||||
@update:period="handlePeriodChange"
|
||||
@manage="router.push({ name: 'management-documents' })"
|
||||
@manage="router.push('/doc/library')"
|
||||
/>
|
||||
</template>
|
||||
</section>
|
||||
|
||||
@@ -125,6 +125,9 @@ function value(value: string | undefined) {
|
||||
<div class="signature-box">
|
||||
<img v-if="record.signatureDataUrl" :src="record.signatureDataUrl" alt="签署人签名" />
|
||||
<span v-else-if="record.status === 'void'">任务已作废,签名不保留</span>
|
||||
<span v-else-if="record.status === 'signed' || record.status === 'confirming'">
|
||||
签名图片暂不可显示
|
||||
</span>
|
||||
<span v-else>未采集签名</span>
|
||||
</div>
|
||||
<dl>
|
||||
|
||||
@@ -3,7 +3,11 @@ import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
import { getCampuses, getDepartments } from '@/api/management/organization'
|
||||
import { downloadSigningArtifact, getSigningArtifacts } from '@/api/workbench/artifacts'
|
||||
import {
|
||||
downloadSigningArtifact,
|
||||
fetchSignatureDataUrl,
|
||||
getSigningArtifacts,
|
||||
} from '@/api/workbench/artifacts'
|
||||
import { mockCatalogCategories, mockCatalogDepartments } from '@/api/workbench/mock-catalog'
|
||||
import {
|
||||
getAllSigningRecords,
|
||||
@@ -120,7 +124,8 @@ const canView = computed(() => canRead('sign:record:view'))
|
||||
const canExport = computed(
|
||||
() => !loginStore.isReadOnly && canRead('sign:record:export'),
|
||||
)
|
||||
const canDownloadArtifact = computed(() => canRead('sign:artifact:download'))
|
||||
const canViewArtifacts = computed(() => canRead('sign:artifact:view'))
|
||||
const canDownloadArtifact = computed(() => canRead('sign:task:download'))
|
||||
|
||||
const campusOptions = computed<SigningRecordFilterOption<WorkbenchCampus | 'all'>[]>(() => [
|
||||
{ label: '全部院区', value: 'all' },
|
||||
@@ -276,9 +281,13 @@ async function openRecord(row: SigningRecordRow) {
|
||||
|
||||
const requestId = ++detailRequestId
|
||||
|
||||
const [detailResult, eventsResult] = await Promise.allSettled([
|
||||
const isSigned = row.status === 'signed' || row.status === 'confirming'
|
||||
const [detailResult, eventsResult, artifactsResult] = await Promise.allSettled([
|
||||
getSigningRecordDetail(row.id, signingApiOptions.value),
|
||||
getSigningRecordEvents(row.id),
|
||||
isSigned && canViewArtifacts.value && canDownloadArtifact.value
|
||||
? getSigningArtifacts(row.id)
|
||||
: Promise.resolve([]),
|
||||
])
|
||||
|
||||
if (requestId !== detailRequestId) {
|
||||
@@ -288,11 +297,37 @@ async function openRecord(row: SigningRecordRow) {
|
||||
if (detailResult.status === 'fulfilled' && detailResult.value) {
|
||||
// 任务接口不返回文档类别与正文,正文靠详情接口补回;
|
||||
// 类别沿用列表里带出的那一份,避免被详情里的空值覆盖
|
||||
detailRecord.value = {
|
||||
let record = {
|
||||
...row,
|
||||
...detailResult.value,
|
||||
category: detailResult.value.category || row.category,
|
||||
}
|
||||
|
||||
// 签署图片是独立的 SIGNATURE_IMAGE 产物,不在任务详情接口中。
|
||||
// 记录详情也要像签署工作台一样取回图片,否则已签任务的文书位会误显示“未签署”。
|
||||
if (isSigned && !record.signatureDataUrl && artifactsResult.status === 'fulfilled') {
|
||||
const signatureArtifact = artifactsResult.value.find(
|
||||
(artifact) => artifact.artifactType === 'SIGNATURE_IMAGE',
|
||||
)
|
||||
|
||||
if (signatureArtifact) {
|
||||
const signatureDataUrl = await fetchSignatureDataUrl(signatureArtifact)
|
||||
|
||||
if (requestId !== detailRequestId) {
|
||||
return
|
||||
}
|
||||
|
||||
if (signatureDataUrl) {
|
||||
record = {
|
||||
...record,
|
||||
signatureDataUrl,
|
||||
fieldAnswers: { ...(record.fieldAnswers ?? {}), signature: signatureDataUrl },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detailRecord.value = record
|
||||
}
|
||||
|
||||
if (eventsResult.status === 'fulfilled') {
|
||||
|
||||
@@ -270,6 +270,28 @@ defineExpose({ getDocumentElement, locateSignatureSlot })
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="task.status === 'failed' && task.method === 'pad'">
|
||||
<button
|
||||
v-if="allowLocalSigning || allowMouseSigning"
|
||||
type="button"
|
||||
class="action-button"
|
||||
:disabled="padSessionLoading"
|
||||
@click="emit('action', 'pad-sign')"
|
||||
>
|
||||
{{ padSessionLoading ? '正在创建签署会话…' : '↻ 重新签署' }}
|
||||
</button>
|
||||
<button
|
||||
v-else-if="canSignTask"
|
||||
type="button"
|
||||
class="action-button"
|
||||
:disabled="padSessionLoading"
|
||||
@click="emit('action', 'create-pad-session')"
|
||||
>
|
||||
{{ padSessionLoading ? '正在创建签署会话…' : '↻ 重新创建签署会话' }}
|
||||
</button>
|
||||
<span class="action-hint">上次生成失败;重新签署会创建新的签署会话。</span>
|
||||
</template>
|
||||
|
||||
<!-- 待科室确认:患者已签完,此刻要动的是科室那一道章(原型 confirmDept 的动作组)。
|
||||
预览与下载放在这里,是因为科室复核时要先看患者签了什么 -->
|
||||
<template v-else-if="task.status === 'confirming'">
|
||||
|
||||
@@ -163,8 +163,10 @@ const canConfirmTask = computed(() => canWrite('sign:task:confirm'))
|
||||
/** 催办:提醒科室签署员尽快复核 */
|
||||
const canRemindTask = computed(() => canWrite('sign:task:remind'))
|
||||
const canViewEvents = computed(() => canRead('sign:task:event:query'))
|
||||
const canViewArtifacts = computed(() => canRead('sign:artifact:query'))
|
||||
const canDownloadArtifacts = computed(() => canRead('sign:artifact:download'))
|
||||
// Keep these permission codes aligned with SignArtifactController: artifact:view
|
||||
// lists the index, while task:download authorizes the PNG/PDF download.
|
||||
const canViewArtifacts = computed(() => canRead('sign:artifact:view'))
|
||||
const canDownloadArtifacts = computed(() => canRead('sign:task:download'))
|
||||
|
||||
/** 需要执行签署权限的任务动作,对应后端 `sign:task:sign`。 */
|
||||
const SIGNING_ACTIONS: SigningTaskAction[] = [
|
||||
|
||||
Reference in New Issue
Block a user