feat(documents): 接入文档库真实接口
This commit is contained in:
@@ -3,7 +3,7 @@ VITE_API_BASE_URL=/api
|
||||
|
||||
# Mock 开关:按业务模块(对齐侧边栏菜单)独立控制,取值只认 true / false。
|
||||
# 留空或注释掉即使用该模块的缺省值,缺省值以 src/utils/mock-flags.ts 为准,
|
||||
# 目前是「签署工作台 + 文档库走演示数据,其余模块走真实接口」。
|
||||
# 目前只有签署工作台缺省走演示数据;文档库及其余已接入模块缺省走真实接口。
|
||||
#
|
||||
# 建议在本地 .env.*.local 里显式声明这两个开关,而不是依赖缺省值:
|
||||
# 缺省值只保证「不改代码时的默认行为」,缺省值一旦调整,
|
||||
@@ -11,7 +11,7 @@ VITE_API_BASE_URL=/api
|
||||
# 「接口报错」或「数据不对」,排查成本很高。
|
||||
# VITE_MOCK_WORKBENCH_HOME=false
|
||||
# VITE_MOCK_SIGNING=true
|
||||
# VITE_MOCK_DOCUMENTS=true
|
||||
# VITE_MOCK_DOCUMENTS=false
|
||||
# VITE_MOCK_DOCUMENT_PERMISSIONS=false
|
||||
# VITE_MOCK_REPORTS=false
|
||||
# VITE_MOCK_USERS=false
|
||||
|
||||
@@ -90,11 +90,11 @@ TanStack Vue Query、PDF 预览、报表图表、自动化测试和签字板适
|
||||
|
||||
- 列表读 `GET /api/v1/templates`(自动翻完所有页),再把扁平的模板列表组织成页面需要的「科室 → 分类 → 文书」树;
|
||||
- 正文不在列表接口里(`TemplateResponseDto` 只给 `templateContentSha256`,不给正文),预览、编辑、发起签署前都要再取一次版本详情 `GET /api/v1/templates/{id}/versions/{versionId}` 拿 `contentHtml`。取不到正文时页面如实报错,不展示空壳模板;
|
||||
- 新建走「建模板 + 建首版」两步,编辑走「建新版本 + 更新模板」;模板没有 DELETE 接口,页面上的「删除」实际是归档动作(`POST .../versions/{versionId}/archive`),保留历史留痕链。
|
||||
- 新建走「建模板 + 建首版」两步,编辑走「建新版本 + 更新模板」;版本号由后端按并发安全序号生成。列表和详情分别使用最新维护版本与当前发布版本指针,审核编辑不会误操作旧发布版,发起签署也不会误用待审核草稿。模板没有 DELETE 接口,页面上的「删除」实际是归档动作(`POST .../versions/{versionId}/archive`),保留历史留痕链。
|
||||
|
||||
签署工作台的真实模式同样依赖正文:`GET /api/v1/templates/available-versions` 只返回 `contentSha256`,签署端用这个哈希当缓存键去换回正文快照(同一哈希命中同一份正文,版本更新后哈希变化即自动失效),避免版本更新后仍按旧正文签署。取不到正文时任务详情如实提示并给出占位版式,不退化成「看起来像真文书」的假纸样。
|
||||
|
||||
自测与演示:开启 `VITE_MOCK_DOCUMENTS` / `VITE_MOCK_SIGNING`(两者缺省即为开启)时,文档库和签署任务的演示数据会镜像到 localStorage(见 `utils/mock-storage.ts`),刷新页面后仍可继续,不必每次重建文书、重发签署;文档库页头的「重置演示数据」可清空这些本地数据回到初始状态(该按钮只在演示模式下出现)。持久化只针对演示数据,不涉及登录态与真实患者信息。本地建议在 `.env.development.local` 里显式写出这两个开关,不要依赖缺省值。
|
||||
自测与演示:显式开启 `VITE_MOCK_DOCUMENTS=true` 或 `VITE_MOCK_SIGNING=true` 时,文档库和签署任务的演示数据会镜像到 localStorage(见 `utils/mock-storage.ts`),刷新页面后仍可继续,不必每次重建文书、重发签署;文档库页头的「重置演示数据」可清空这些本地数据回到初始状态(该按钮只在演示模式下出现)。文档库缺省使用真实接口,签署工作台暂时缺省使用演示数据;持久化只针对演示数据,不涉及登录态与真实患者信息。本地建议在 `.env.development.local` 里显式写出开关,不要依赖缺省值。
|
||||
|
||||
## 当前路由结构
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
DocumentRecord,
|
||||
TemplateResponseDto,
|
||||
TemplateVersionResponseDto,
|
||||
UpdateTemplateRequest,
|
||||
} from './types'
|
||||
|
||||
const useMockData = mockFlags.documents
|
||||
@@ -89,8 +90,9 @@ function normalizeDocumentStatus(status: BackendTemplateStatus | null | undefine
|
||||
}
|
||||
|
||||
function mapDocument(dto: TemplateResponseDto): DocumentRecord {
|
||||
const versionId = dto.currentVersionId ?? undefined
|
||||
const version = dto.versionSequence ? `v${dto.versionSequence}` : '—'
|
||||
const versionId = dto.latestVersionId ?? dto.currentVersionId ?? undefined
|
||||
const version = dto.latestVersionNo ?? (dto.versionSequence ? `v${dto.versionSequence}` : '—')
|
||||
const backendStatus = dto.latestVersionStatus ?? dto.status
|
||||
|
||||
return {
|
||||
id: dto.id,
|
||||
@@ -98,11 +100,12 @@ function mapDocument(dto: TemplateResponseDto): DocumentRecord {
|
||||
code: dto.templateCode,
|
||||
category: dto.category ?? '未分类',
|
||||
version: String(version),
|
||||
status: normalizeDocumentStatus(dto.status),
|
||||
backendStatus: dto.status ?? undefined,
|
||||
status: normalizeDocumentStatus(backendStatus),
|
||||
backendStatus: backendStatus ?? undefined,
|
||||
updatedBy: dto.updatedBy ?? dto.createdBy ?? '—',
|
||||
updatedAt: formatTemplateDateTime(dto.updatedAt ?? dto.createdAt),
|
||||
versionId,
|
||||
currentVersionId: dto.currentVersionId ?? undefined,
|
||||
departmentId: dto.departmentId,
|
||||
departmentName: dto.departmentId ? undefined : '全院通用',
|
||||
campusId: dto.campusId,
|
||||
@@ -143,21 +146,21 @@ export function buildSignatureFieldsPayload(contentHtml: string): unknown[] {
|
||||
|
||||
/**
|
||||
* 读取模板当前版本的正文。
|
||||
* 模板列表接口只给 currentVersionId 与哈希,不给正文,
|
||||
* 模板列表接口只给版本指针与哈希,不给正文,
|
||||
* 因此展示/编辑正文必须再取一次版本详情——这是文档库能否接入的关键一步。
|
||||
*/
|
||||
export async function getTemplateContent(templateId: string): Promise<string> {
|
||||
export async function getTemplateContent(templateId: string, versionId?: string): Promise<string> {
|
||||
if (useMockData) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const template = await getDocumentDetail(templateId)
|
||||
const resolvedVersionId = versionId ?? (await getDocumentDetail(templateId))?.versionId
|
||||
|
||||
if (!template?.versionId) {
|
||||
if (!resolvedVersionId) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const version = await getTemplateVersionDetail(templateId, template.versionId)
|
||||
const version = await getTemplateVersionDetail(templateId, resolvedVersionId)
|
||||
return readVersionContentHtml(version)
|
||||
}
|
||||
|
||||
@@ -235,7 +238,10 @@ async function findContentByVersionId(templateVersionId: string): Promise<string
|
||||
: []
|
||||
|
||||
const candidates = [firstPage, ...remainingPages].flatMap((page) => page.records)
|
||||
const matched = candidates.find((template) => template.versionId === templateVersionId)
|
||||
const matched = candidates.find(
|
||||
(template) =>
|
||||
template.versionId === templateVersionId || template.currentVersionId === templateVersionId,
|
||||
)
|
||||
|
||||
if (!matched) {
|
||||
return ''
|
||||
@@ -376,7 +382,7 @@ export async function createTemplate(payload: CreateTemplateRequest): Promise<Do
|
||||
|
||||
export async function updateTemplate(
|
||||
id: string,
|
||||
payload: Partial<CreateTemplateRequest>,
|
||||
payload: UpdateTemplateRequest,
|
||||
): Promise<DocumentRecord> {
|
||||
if (useMockData) {
|
||||
throw new Error('演示模式下请在文档库页面直接编辑文书')
|
||||
@@ -506,7 +512,7 @@ export async function createTemplateWithContent(
|
||||
signatureFields: buildSignatureFieldsPayload(version.contentHtml),
|
||||
})
|
||||
|
||||
// 版本创建后模板的 currentVersionId/versionSequence 才更新,重新取一次拿到准确版本号
|
||||
// 版本创建后模板的 latestVersionId/versionSequence 才更新,重新取一次拿到准确版本号
|
||||
const detail = await getDocumentDetail(template.id)
|
||||
return detail ?? template
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ export interface DocumentRecord {
|
||||
description?: string
|
||||
contentHtml?: string
|
||||
contentSha256?: string
|
||||
/** 当前已发布版本;发起签署必须使用它,不能误用最新草稿版本。 */
|
||||
currentVersionId?: string
|
||||
}
|
||||
|
||||
export type DocumentListResponse = PageResult<DocumentRecord>
|
||||
@@ -51,6 +53,9 @@ export interface TemplateResponseDto {
|
||||
category?: string | null
|
||||
status?: BackendTemplateStatus | null
|
||||
currentVersionId?: string | null
|
||||
latestVersionId?: string | null
|
||||
latestVersionNo?: string | null
|
||||
latestVersionStatus?: BackendTemplateStatus | null
|
||||
versionSequence?: number | null
|
||||
createdAt?: string | null
|
||||
createdBy?: string | null
|
||||
@@ -93,6 +98,12 @@ export interface CreateTemplateRequest {
|
||||
category?: string
|
||||
}
|
||||
|
||||
export interface UpdateTemplateRequest {
|
||||
name: string
|
||||
description?: string
|
||||
category?: string
|
||||
}
|
||||
|
||||
export interface CreateTemplateVersionRequest {
|
||||
versionNo?: string
|
||||
contentHtml: string
|
||||
|
||||
@@ -32,7 +32,7 @@ export const mockFlags = {
|
||||
/** 签署工作台:签署任务、签署产物,以及仅用于签署留痕的审计日志 */
|
||||
signing: resolveMockFlag(import.meta.env.VITE_MOCK_SIGNING, true),
|
||||
/** 文档库管理:文书库与文书模板接口 */
|
||||
documents: resolveMockFlag(import.meta.env.VITE_MOCK_DOCUMENTS, true),
|
||||
documents: resolveMockFlag(import.meta.env.VITE_MOCK_DOCUMENTS, false),
|
||||
/** 文档权限:模板权限配置与权限矩阵 */
|
||||
documentPermissions: resolveMockFlag(import.meta.env.VITE_MOCK_DOCUMENT_PERMISSIONS, false),
|
||||
/** 报表分析 */
|
||||
|
||||
@@ -10,6 +10,7 @@ const props = defineProps<{
|
||||
template: DocumentTemplate
|
||||
canEdit: boolean
|
||||
canInitiate: boolean
|
||||
canWorkflow: (action: TemplateVersionAction) => boolean
|
||||
canRemove: boolean
|
||||
/** 演示模式下「删除」是真删;真实模式下语义是下架(模板无 DELETE 接口,走归档) */
|
||||
isMock: boolean
|
||||
@@ -31,9 +32,7 @@ const statusTone = computed(() => readStatusTone(props.template))
|
||||
|
||||
/** 只有已发布 / 待复审的模板可以发起签署;草稿与已归档不可用 */
|
||||
const canInitiateTemplate = computed(
|
||||
() =>
|
||||
props.canInitiate &&
|
||||
(props.template.status === 'published' || props.template.status === 'review'),
|
||||
() => props.canInitiate && Boolean(props.template.currentVersionId || props.isMock),
|
||||
)
|
||||
|
||||
const initiateTitle = computed(() =>
|
||||
@@ -64,6 +63,8 @@ const primaryAction = computed<{ key: TemplateVersionAction; label: string } | n
|
||||
return { key: 'submit-review', label: '重新提交' }
|
||||
case 'DISABLED':
|
||||
return { key: 'publish', label: '重新启用' }
|
||||
case 'APPROVED':
|
||||
return { key: 'publish', label: '发布' }
|
||||
default:
|
||||
return null
|
||||
}
|
||||
@@ -75,21 +76,21 @@ const primaryAction = computed<{ key: TemplateVersionAction; label: string } | n
|
||||
* 「驳回」不能只做成主动作的反面:审核通过和驳回是审核人的一对选择,
|
||||
* 必须同时可见,否则待审核的文书就只能通过、不能打回。
|
||||
*/
|
||||
const secondaryActions = computed<
|
||||
{ key: TemplateVersionAction; label: string; title: string }[]
|
||||
>(() => {
|
||||
if (props.template.backendStatus === 'PENDING_REVIEW') {
|
||||
return [
|
||||
{
|
||||
key: 'reject',
|
||||
label: '驳回',
|
||||
title: '驳回后需填写原因,科室按意见修改并重新提交',
|
||||
},
|
||||
]
|
||||
}
|
||||
const secondaryActions = computed<{ key: TemplateVersionAction; label: string; title: string }[]>(
|
||||
() => {
|
||||
if (props.template.backendStatus === 'PENDING_REVIEW' && props.canWorkflow('reject')) {
|
||||
return [
|
||||
{
|
||||
key: 'reject',
|
||||
label: '驳回',
|
||||
title: '驳回后需填写原因,科室按意见修改并重新提交',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return []
|
||||
})
|
||||
return []
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
* 本次交付暂不包含「版本历史」与「删除 / 下架」入口,先隐藏对应按钮。
|
||||
@@ -136,10 +137,9 @@ const removeTitle = computed(() => (props.isMock ? '删除此文书' : '下架
|
||||
版本
|
||||
</button>
|
||||
<button
|
||||
v-if="canInitiate"
|
||||
v-if="canInitiateTemplate"
|
||||
type="button"
|
||||
class="card-button primary"
|
||||
:disabled="!canInitiateTemplate"
|
||||
:title="initiateTitle"
|
||||
@click="emit('initiate', template)"
|
||||
>
|
||||
@@ -147,7 +147,7 @@ const removeTitle = computed(() => (props.isMock ? '删除此文书' : '下架
|
||||
</button>
|
||||
<!-- 还不能签署时,把「当前该做的下一步」放在同一位置,避免按钮越堆越多 -->
|
||||
<button
|
||||
v-else-if="primaryAction"
|
||||
v-if="primaryAction && canWorkflow(primaryAction.key)"
|
||||
type="button"
|
||||
class="card-button primary"
|
||||
:title="`${primaryAction.label}后才能发起签署`"
|
||||
|
||||
@@ -19,6 +19,7 @@ const props = defineProps<{
|
||||
template: DocumentTemplate | null
|
||||
campuses: CampusRecord[]
|
||||
departments: DepartmentRecord[]
|
||||
isMock: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -52,7 +53,7 @@ const form = reactive<TemplateEditorForm>({
|
||||
campusId: props.campuses[0]?.id ?? '',
|
||||
departmentId: '',
|
||||
category: '知情同意书',
|
||||
versionNo: 'v1.0.0',
|
||||
versionNo: 'v1',
|
||||
contentHtml: '',
|
||||
})
|
||||
|
||||
@@ -80,7 +81,7 @@ watch(
|
||||
campusId: template?.campusId ?? props.campuses[0]?.id ?? '',
|
||||
departmentId: template?.departmentId ?? '',
|
||||
category: template?.category ?? '知情同意书',
|
||||
versionNo: template?.version ?? 'v1.0.0',
|
||||
versionNo: template?.version ?? 'v1',
|
||||
contentHtml: template?.contentHtml ?? '',
|
||||
})
|
||||
valueHtml.value = template?.contentHtml || '<p><br></p>'
|
||||
@@ -224,11 +225,21 @@ function save() {
|
||||
</label>
|
||||
<label class="meta-field">
|
||||
<span>文书编号</span>
|
||||
<input v-model="form.templateCode" type="text" placeholder="如 TPL-XXX-001" />
|
||||
<input
|
||||
v-model="form.templateCode"
|
||||
type="text"
|
||||
placeholder="如 TPL-XXX-001"
|
||||
:disabled="Boolean(template)"
|
||||
:title="template ? '文书编号创建后不可修改' : undefined"
|
||||
/>
|
||||
</label>
|
||||
<label class="meta-field">
|
||||
<span>所属院区</span>
|
||||
<select v-model="form.campusId" @change="handleCampusChange">
|
||||
<select
|
||||
v-model="form.campusId"
|
||||
:disabled="Boolean(template)"
|
||||
@change="handleCampusChange"
|
||||
>
|
||||
<option v-for="campus in campuses" :key="campus.id" :value="campus.id">
|
||||
{{ campus.name }}
|
||||
</option>
|
||||
@@ -236,7 +247,7 @@ function save() {
|
||||
</label>
|
||||
<label class="meta-field">
|
||||
<span>所属科室</span>
|
||||
<select v-model="form.departmentId">
|
||||
<select v-model="form.departmentId" :disabled="Boolean(template)">
|
||||
<option value="">全院通用</option>
|
||||
<option
|
||||
v-for="department in availableDepartments"
|
||||
@@ -253,7 +264,8 @@ function save() {
|
||||
</label>
|
||||
<label class="meta-field">
|
||||
<span>版本号</span>
|
||||
<input v-model="form.versionNo" type="text" />
|
||||
<input v-if="isMock" v-model="form.versionNo" type="text" />
|
||||
<span v-else class="auto-version">由系统按 vN 自动生成</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ import {
|
||||
deleteTemplate,
|
||||
getDocuments,
|
||||
getTemplateContent,
|
||||
getTemplateVersionDetail,
|
||||
getTemplateVersions,
|
||||
readVersionContentHtml,
|
||||
updateTemplate,
|
||||
updateTemplateContent,
|
||||
updateTemplateVersionStatus,
|
||||
@@ -18,6 +20,7 @@ import { getCampuses, getDepartments } from '@/api/management/organization'
|
||||
import type {
|
||||
CampusRecord,
|
||||
CreateTemplateRequest,
|
||||
CreateTemplateVersionRequest,
|
||||
DocumentRecord,
|
||||
DepartmentRecord,
|
||||
TemplateVersionResponseDto,
|
||||
@@ -56,8 +59,8 @@ import type {
|
||||
/**
|
||||
* 文档库数据来源。
|
||||
*
|
||||
* - 演示模式(VITE_MOCK_DOCUMENTS 开启,缺省开启):读本地演示文书库,可随意增删改;
|
||||
* - 真实模式:读模板接口。列表只给模板元数据(含 currentVersionId),
|
||||
* - 演示模式(显式开启 VITE_MOCK_DOCUMENTS):读本地演示文书库,可随意增删改;
|
||||
* - 真实模式:读模板接口。列表只给模板元数据(含发布/最新版本指针),
|
||||
* 正文要再取一次版本详情——这是接入时最容易被忽略的一步,
|
||||
* 缺了它文档库会显示一堆没有正文、无法预览的"空壳模板"。
|
||||
*
|
||||
@@ -78,7 +81,8 @@ const canCreateTemplate = computed(
|
||||
const canEditTemplate = computed(
|
||||
() =>
|
||||
!loginStore.isReadOnly &&
|
||||
(useMockLibrary || loginStore.hasWritePermission('sign:template:version:create')),
|
||||
(useMockLibrary ||
|
||||
loginStore.hasWritePermission(['sign:template:update', 'sign:template:version:create'])),
|
||||
)
|
||||
const canArchiveTemplate = computed(
|
||||
() =>
|
||||
@@ -89,6 +93,22 @@ const canInitiateSigning = computed(
|
||||
() =>
|
||||
!loginStore.isReadOnly && (useMockLibrary || loginStore.hasWritePermission('sign:task:create')),
|
||||
)
|
||||
|
||||
const workflowPermissions: Record<TemplateVersionAction, string> = {
|
||||
'submit-review': 'sign:template:review:submit',
|
||||
reject: 'sign:template:review:reject',
|
||||
approve: 'sign:template:review:approve',
|
||||
publish: 'sign:template:publish',
|
||||
disable: 'sign:template:disable',
|
||||
archive: 'sign:template:archive',
|
||||
}
|
||||
|
||||
function canRunTemplateWorkflow(action: TemplateVersionAction) {
|
||||
return (
|
||||
!loginStore.isReadOnly &&
|
||||
(useMockLibrary || loginStore.hasWritePermission(workflowPermissions[action]))
|
||||
)
|
||||
}
|
||||
/** 真实模式下的加载状态:区分"正在加载"与"确实没有模板" */
|
||||
const libraryLoading = ref(false)
|
||||
const libraryError = ref('')
|
||||
@@ -177,8 +197,7 @@ const filteredTemplates = computed(() => {
|
||||
|
||||
return allTemplates.value.filter((template) => {
|
||||
const matchesDepartment = !filters.department || template.departmentKey === filters.department
|
||||
const matchesStatus =
|
||||
filters.status === 'all' || readBackendStatus(template) === filters.status
|
||||
const matchesStatus = filters.status === 'all' || readBackendStatus(template) === filters.status
|
||||
const matchesKeyword =
|
||||
!keyword ||
|
||||
[template.name, template.code, template.department].join(' ').toLowerCase().includes(keyword)
|
||||
@@ -364,7 +383,7 @@ async function handlePreview(template: DocumentTemplate) {
|
||||
previewError.value = false
|
||||
|
||||
try {
|
||||
const contentHtml = await getTemplateContent(template.id)
|
||||
const contentHtml = await getTemplateContent(template.id, template.versionId)
|
||||
|
||||
// 用户在等待期间可能已经切到别的文书,回填前确认仍是同一份
|
||||
if (selectedTemplate.value?.id === template.id) {
|
||||
@@ -422,7 +441,7 @@ async function showEditMessage(template: DocumentTemplate) {
|
||||
wordEditorLoading.value = true
|
||||
|
||||
try {
|
||||
const contentHtml = await getTemplateContent(template.id)
|
||||
const contentHtml = await getTemplateContent(template.id, template.versionId)
|
||||
|
||||
if (!contentHtml) {
|
||||
ElMessage.error('未能取到该文书的正文内容,请确认模板版本内容接口可访问')
|
||||
@@ -512,9 +531,11 @@ function toCreatePayload(form: TemplateEditorForm): CreateTemplateRequest {
|
||||
}
|
||||
}
|
||||
|
||||
function toVersionPayload(form: TemplateEditorForm) {
|
||||
function toVersionPayload(
|
||||
form: TemplateEditorForm,
|
||||
): Omit<CreateTemplateVersionRequest, 'signatureFields'> {
|
||||
return {
|
||||
versionNo: form.versionNo,
|
||||
...(useMockLibrary && form.versionNo ? { versionNo: form.versionNo } : {}),
|
||||
contentHtml: form.contentHtml,
|
||||
}
|
||||
}
|
||||
@@ -537,6 +558,8 @@ async function saveTemplate(form: TemplateEditorForm) {
|
||||
return
|
||||
}
|
||||
|
||||
let versionCreated = false
|
||||
|
||||
try {
|
||||
let savedId = form.id
|
||||
|
||||
@@ -545,6 +568,7 @@ async function saveTemplate(form: TemplateEditorForm) {
|
||||
// 新版本的状态由后端决定,前端不在这里「顺带发布」——发布是需要留痕的正式动作,
|
||||
// 要由人显式触发(见 handleWorkflow),否则「谁把这份文书放行到可签署」无从追溯。
|
||||
await updateTemplateContent(form.id, toVersionPayload(form))
|
||||
versionCreated = true
|
||||
await updateTemplate(form.id, {
|
||||
name: form.name,
|
||||
description: form.description,
|
||||
@@ -573,7 +597,11 @@ async function saveTemplate(form: TemplateEditorForm) {
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
ElMessage.error(form.id ? '文书更新失败,请稍后重试' : '文书创建失败,请稍后重试')
|
||||
if (form.id && versionCreated) {
|
||||
ElMessage.error('新版本已保存,但文书名称、说明或分类更新失败;请刷新后重试基本信息')
|
||||
} else {
|
||||
ElMessage.error(form.id ? '文书更新失败,请稍后重试' : '文书创建失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,6 +655,11 @@ async function handleWorkflow(template: DocumentTemplate, action: TemplateVersio
|
||||
return
|
||||
}
|
||||
|
||||
if (!canRunTemplateWorkflow(action)) {
|
||||
ElMessage.warning(`当前账号没有${workflowActionLabels[action]}权限`)
|
||||
return
|
||||
}
|
||||
|
||||
const label = workflowActionLabels[action]
|
||||
let reason: string | undefined
|
||||
|
||||
@@ -777,10 +810,23 @@ async function removeTemplate(template: DocumentTemplate) {
|
||||
* 与模板无关的空文书。因此这里在缺正文时先取回,取不到就拒绝发起。
|
||||
*/
|
||||
async function toSigningTemplate(template: DocumentTemplate): Promise<SigningTemplate | null> {
|
||||
let contentHtml = template.contentHtml
|
||||
if (!useMockLibrary && !template.currentVersionId) {
|
||||
ElMessage.error('该文书还没有已发布版本,无法发起签署')
|
||||
return null
|
||||
}
|
||||
|
||||
if (!useMockLibrary && !contentHtml) {
|
||||
contentHtml = await getTemplateContent(template.id)
|
||||
let contentHtml = template.contentHtml
|
||||
let versionNo = template.version
|
||||
let contentSha256 = template.contentSha256
|
||||
const signingVersionId = useMockLibrary
|
||||
? (template.versionId ?? template.id)
|
||||
: template.currentVersionId!
|
||||
|
||||
if (!useMockLibrary) {
|
||||
const version = await getTemplateVersionDetail(template.id, signingVersionId)
|
||||
contentHtml = readVersionContentHtml(version)
|
||||
versionNo = version?.versionNo ?? versionNo
|
||||
contentSha256 = version?.contentSha256 ?? contentSha256
|
||||
|
||||
if (!contentHtml) {
|
||||
ElMessage.error('未能取到该文书的正文内容,无法发起签署')
|
||||
@@ -790,10 +836,10 @@ async function toSigningTemplate(template: DocumentTemplate): Promise<SigningTem
|
||||
|
||||
return {
|
||||
id: template.id,
|
||||
versionId: template.versionId ?? template.id,
|
||||
versionId: signingVersionId,
|
||||
name: template.name,
|
||||
code: template.code ?? '',
|
||||
version: template.version,
|
||||
version: versionNo,
|
||||
department: template.department,
|
||||
departmentId: template.departmentId,
|
||||
campusId: template.campusId ?? undefined,
|
||||
@@ -801,7 +847,7 @@ async function toSigningTemplate(template: DocumentTemplate): Promise<SigningTem
|
||||
description: template.description ?? '',
|
||||
supportedMethods: ['pad', 'sms'],
|
||||
contentHtml,
|
||||
contentSha256: template.contentSha256,
|
||||
contentSha256,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,6 +976,7 @@ onMounted(() => {
|
||||
:template="template"
|
||||
:can-edit="canEditTemplate"
|
||||
:can-initiate="canInitiateSigning"
|
||||
:can-workflow="canRunTemplateWorkflow"
|
||||
:can-remove="canArchiveTemplate"
|
||||
:is-mock="useMockLibrary"
|
||||
@preview="handlePreview"
|
||||
@@ -978,6 +1025,7 @@ onMounted(() => {
|
||||
:template="wordEditingTemplate"
|
||||
:campuses="campuses"
|
||||
:departments="departments"
|
||||
:is-mock="useMockLibrary"
|
||||
@close="wordEditorVisible = false"
|
||||
@save="saveTemplate"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user