feat: 提交

This commit is contained in:
xy
2026-09-29 15:50:21 +08:00
parent c4363889b1
commit 8d8fa2af47
14 changed files with 911 additions and 40 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue'
import { computed, nextTick, reactive, ref, watch } from 'vue'
import type { SigningFieldDef, SigningFieldKind } from '@/api/workbench/types'
import {
@@ -12,6 +12,8 @@ import {
} from '@/utils/signing-fields'
import DocumentPaper from '@/components/document/DocumentPaper.vue'
import SignaturePositionPreview from './SignaturePositionPreview.vue'
import type { SignaturePosition } from '@/api/management/signature-preview'
import EditorWangPane from './editors/EditorWangPane.vue'
import { DOC_TEMPLATE_PERMISSIONS } from '../permissions'
@@ -47,6 +49,7 @@ const savePermission = DOC_TEMPLATE_PERMISSIONS.edit
// 并把占位符的元素节点与渲染钩子重新注册一遍(见 utils/signing-field-node)。
interface EditorPaneHandle {
getText: () => string
getHtml: () => string | undefined
insertField: (field: SigningFieldDef) => void
/** 就地改写某个字段的占位符,返回命中的节点数;0 表示正文里已经没有它 */
updateField: (fieldId: string, patch: Partial<Omit<SigningFieldDef, 'id'>>) => number
@@ -137,6 +140,23 @@ const fieldDraft = reactive({
pdfCoordinateSystem: 'TOP_LEFT' as 'TOP_LEFT' | 'PDF_BOTTOM_LEFT',
})
const previewPosition = computed<SignaturePosition>(() => ({
page: Number(fieldDraft.pdfPage),
x: Number(fieldDraft.pdfX),
y: Number(fieldDraft.pdfY),
width: Number(fieldDraft.pdfWidth),
height: Number(fieldDraft.pdfHeight),
coordinateSystem: fieldDraft.pdfCoordinateSystem,
}))
function changePosition(position: SignaturePosition) {
fieldDraft.pdfPage = String(position.page)
fieldDraft.pdfX = String(position.x)
fieldDraft.pdfY = String(position.y)
fieldDraft.pdfWidth = String(position.width)
fieldDraft.pdfHeight = String(position.height)
fieldDraft.pdfCoordinateSystem = position.coordinateSystem
}
/** 类型下拉的取值(原型 fpKind 的 5 个选项) */
const KIND_OPTIONS = Object.entries(SIGNING_FIELD_KIND_LABELS) as Array<[SigningFieldKind, string]>
@@ -240,14 +260,14 @@ function applyFieldDraft() {
const field = selectedField.value
if (!field) {
return
return false
}
const label = fieldDraft.label.trim()
if (!label) {
setMessage('请填写填写项名称', 'warn')
return
return false
}
const options = fieldDraft.options.map((option) => option.trim()).filter(Boolean)
@@ -274,19 +294,19 @@ function applyFieldDraft() {
height <= 0
) {
setMessage('患者签名位置须填写有效页码及 PDF point 坐标', 'warn')
return
return false
}
pdfPosition = { page, x, y, width, height, coordinateSystem: fieldDraft.pdfCoordinateSystem }
}
if (isOptionKind.value && new Set(options).size !== options.length) {
setMessage('存在重复选项,请修改后重试', 'warn')
return
return false
}
if (fieldDraft.kind === 'choice' && options.length < 2) {
setMessage(`选择项「${label}」至少需要两个选项`, 'warn')
return
return false
}
// 字段键(field.id)刻意保持不变:id 是取值的归属,改叫法不该让历史取值对不上。
@@ -308,7 +328,7 @@ function applyFieldDraft() {
if (!changed) {
setMessage(`正文里已经没有「${field.label}」了,请重新选择要修改的填写项`, 'warn')
selectedFieldId.value = ''
return
return false
}
setMessage(
@@ -318,6 +338,7 @@ function applyFieldDraft() {
: ''),
'ok',
)
return true
}
function removeField() {
@@ -438,7 +459,7 @@ async function handleDocxChange(event: Event) {
}
}
function save() {
async function save() {
if (!props.template) {
return
}
@@ -456,6 +477,11 @@ function save() {
return
}
if (selectedField.value?.id === 'signature') {
if (!applyFieldDraft()) return
await nextTick()
valueHtml.value = paneRef.value?.getHtml() ?? valueHtml.value
}
const error = validate()
if (error) {
@@ -576,6 +602,15 @@ function requestClose() {
</button>
</div>
<SignaturePositionPreview
v-if="template && selectedField.id === 'signature' && fieldDraft.kind === 'signature'"
:key="template.id"
:template-id="template.id"
:content-html="valueHtml"
:position="previewPosition"
@change="changePosition"
/>
<div v-if="isOptionKind" class="fp-row">
<b class="fp-title">选项设置(支持多个)</b>
<span class="fp-hint">选项逐项展示为可勾选框;勾选类默认可多选,选择类默认单选</span>
@@ -619,6 +654,15 @@ function requestClose() {
</label>
</div>
<SignaturePositionPreview
v-if="template && selectedField.id === 'signature' && fieldDraft.kind === 'signature'"
:key="template.id"
:template-id="template.id"
:content-html="valueHtml"
:position="previewPosition"
@change="changePosition"
/>
<div v-if="isOptionKind" class="fp-row">
<span v-for="(_, index) in fieldDraft.options" :key="index" class="option-item">
<input