fix(signing): 发起签署弹窗移除签署人与文书填写项采集
This commit is contained in:
@@ -49,18 +49,10 @@ const {
|
|||||||
selectMethod,
|
selectMethod,
|
||||||
selectTemplate,
|
selectTemplate,
|
||||||
selectVisit,
|
selectVisit,
|
||||||
selectedTemplate,
|
|
||||||
selectedTemplateId,
|
selectedTemplateId,
|
||||||
selectedVisit,
|
selectedVisit,
|
||||||
selectedVisitId,
|
selectedVisitId,
|
||||||
smsDestination,
|
smsDestination,
|
||||||
staffAnswers,
|
|
||||||
manualFormFields,
|
|
||||||
signerType,
|
|
||||||
signerName,
|
|
||||||
signerRelation,
|
|
||||||
staffAnswerHasOption,
|
|
||||||
toggleStaffAnswerOption,
|
|
||||||
submit: submitForm,
|
submit: submitForm,
|
||||||
submitting,
|
submitting,
|
||||||
suggestionOpen,
|
suggestionOpen,
|
||||||
@@ -478,79 +470,6 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section v-if="selectedTemplate" class="form-section signing-context-section">
|
|
||||||
<header class="section-header">
|
|
||||||
<span class="section-index">E</span>
|
|
||||||
<strong>签署人和文书填写项</strong>
|
|
||||||
<span class="section-hint">按已选模板采集,提交后固化到签署任务</span>
|
|
||||||
</header>
|
|
||||||
<div class="section-body signing-context-grid">
|
|
||||||
<fieldset class="signer-choice">
|
|
||||||
<legend>实际签署人</legend>
|
|
||||||
<label>
|
|
||||||
<input v-model="signerType" type="radio" value="SELF" />
|
|
||||||
患者本人
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input v-model="signerType" type="radio" value="FAMILY" />
|
|
||||||
家属代签
|
|
||||||
</label>
|
|
||||||
<template v-if="signerType === 'FAMILY'">
|
|
||||||
<input v-model="signerName" maxlength="255" placeholder="代签人姓名" />
|
|
||||||
<input v-model="signerRelation" maxlength="64" placeholder="与患者关系" />
|
|
||||||
</template>
|
|
||||||
<p v-if="errors.signer" class="field-error">{{ errors.signer }}</p>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div v-if="manualFormFields.length" class="staff-answer-fields">
|
|
||||||
<label v-for="field in manualFormFields" :key="field.id" class="staff-answer-field">
|
|
||||||
<span>{{ field.label }}<b v-if="field.required"> *</b></span>
|
|
||||||
<select
|
|
||||||
v-if="field.kind === 'choice'"
|
|
||||||
v-model="staffAnswers[field.id]"
|
|
||||||
:required="field.required"
|
|
||||||
>
|
|
||||||
<option value="">请选择</option>
|
|
||||||
<option v-for="option in field.options ?? []" :key="option" :value="option">
|
|
||||||
{{ option }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<span
|
|
||||||
v-else-if="field.kind === 'checkbox' && field.options?.length"
|
|
||||||
class="staff-answer-options"
|
|
||||||
>
|
|
||||||
<label v-for="option in field.options" :key="option">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
:checked="staffAnswerHasOption(field.id, option)"
|
|
||||||
@change="
|
|
||||||
toggleStaffAnswerOption(
|
|
||||||
field.id,
|
|
||||||
option,
|
|
||||||
($event.target as HTMLInputElement).checked,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
{{ option }}
|
|
||||||
</label>
|
|
||||||
</span>
|
|
||||||
<input
|
|
||||||
v-else
|
|
||||||
v-model="staffAnswers[field.id]"
|
|
||||||
:type="field.kind === 'date' ? 'date' : 'text'"
|
|
||||||
:required="field.required"
|
|
||||||
maxlength="4000"
|
|
||||||
:placeholder="`填写${field.label}`"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<p v-if="errors.staffAnswers" class="field-error">{{ errors.staffAnswers }}</p>
|
|
||||||
</div>
|
|
||||||
<p v-else class="section-empty">
|
|
||||||
当前模板没有需要医护端填写的正文项;患者签名和签署日期将在签署环节生成。
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="dialog-footer">
|
<footer class="dialog-footer">
|
||||||
@@ -985,80 +904,6 @@ watch(
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-hint {
|
|
||||||
margin-left: auto;
|
|
||||||
color: var(--mut);
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signing-context-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: minmax(220px, 0.7fr) minmax(0, 1.3fr);
|
|
||||||
gap: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signer-choice {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 10px;
|
|
||||||
align-content: start;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signer-choice legend,
|
|
||||||
.staff-answer-field > span:first-child {
|
|
||||||
color: var(--mut);
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signer-choice label,
|
|
||||||
.staff-answer-options label {
|
|
||||||
display: inline-flex;
|
|
||||||
gap: 5px;
|
|
||||||
align-items: center;
|
|
||||||
color: var(--ink);
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signer-choice > input,
|
|
||||||
.staff-answer-field > input,
|
|
||||||
.staff-answer-field > select {
|
|
||||||
min-width: 0;
|
|
||||||
padding: 7px 9px;
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.staff-answer-fields {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.staff-answer-field {
|
|
||||||
display: grid;
|
|
||||||
gap: 5px;
|
|
||||||
min-width: 0;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.staff-answer-field b {
|
|
||||||
color: var(--err);
|
|
||||||
}
|
|
||||||
|
|
||||||
.staff-answer-options {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signing-context-grid > .section-empty,
|
|
||||||
.staff-answer-fields > .field-error {
|
|
||||||
grid-column: 1 / -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* C + D 并排 */
|
/* C + D 并排 */
|
||||||
|
|
||||||
.document-method-grid {
|
.document-method-grid {
|
||||||
@@ -1469,10 +1314,6 @@ watch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1100px) {
|
@media (max-width: 1100px) {
|
||||||
.signing-context-grid,
|
|
||||||
.staff-answer-fields {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
.document-method-grid {
|
.document-method-grid {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { computed, reactive, ref, toValue, watch, type MaybeRefOrGetter } from 'vue'
|
import { computed, reactive, ref, toValue, type MaybeRefOrGetter } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
import { sendSigningSms } from '@/api/workbench/deliveries'
|
import { sendSigningSms } from '@/api/workbench/deliveries'
|
||||||
@@ -15,7 +15,6 @@ import type {
|
|||||||
PatientProfile,
|
PatientProfile,
|
||||||
PatientVisit,
|
PatientVisit,
|
||||||
SigningMethod,
|
SigningMethod,
|
||||||
SigningFormField,
|
|
||||||
SigningTaskRecord,
|
SigningTaskRecord,
|
||||||
SigningTemplate,
|
SigningTemplate,
|
||||||
WorkbenchCampus,
|
WorkbenchCampus,
|
||||||
@@ -70,10 +69,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
const selectedVisitId = ref('')
|
const selectedVisitId = ref('')
|
||||||
const method = ref<SigningMethod>('pad')
|
const method = ref<SigningMethod>('pad')
|
||||||
const smsDestination = ref('')
|
const smsDestination = ref('')
|
||||||
const staffAnswers = reactive<Record<string, string>>({})
|
|
||||||
const signerType = ref<'SELF' | 'FAMILY'>('SELF')
|
|
||||||
const signerName = ref('')
|
|
||||||
const signerRelation = ref('')
|
|
||||||
const loadingTemplates = ref(false)
|
const loadingTemplates = ref(false)
|
||||||
const locating = ref(false)
|
const locating = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
@@ -93,8 +88,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
visit: '',
|
visit: '',
|
||||||
document: '',
|
document: '',
|
||||||
sms: '',
|
sms: '',
|
||||||
staffAnswers: '',
|
|
||||||
signer: '',
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 演示候选患者(真实模式为空数组,候选下拉自然不出现) */
|
/** 演示候选患者(真实模式为空数组,候选下拉自然不出现) */
|
||||||
@@ -108,30 +101,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
() => templates.value.find((template) => template.id === selectedTemplateId.value) ?? null,
|
() => templates.value.find((template) => template.id === selectedTemplateId.value) ?? null,
|
||||||
)
|
)
|
||||||
|
|
||||||
const manualFormFields = computed(() => {
|
|
||||||
const systemFields = new Set([
|
|
||||||
'patient',
|
|
||||||
'sex',
|
|
||||||
'age',
|
|
||||||
'visit',
|
|
||||||
'phone',
|
|
||||||
'doctor',
|
|
||||||
'signedDate',
|
|
||||||
])
|
|
||||||
return (selectedTemplate.value?.formFields ?? []).filter(
|
|
||||||
(field) =>
|
|
||||||
field.kind !== 'signature' &&
|
|
||||||
field.kind !== 'checkbox' &&
|
|
||||||
field.kind !== 'choice' &&
|
|
||||||
!systemFields.has(field.id),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(selectedTemplateId, () => {
|
|
||||||
Object.keys(staffAnswers).forEach((key) => delete staffAnswers[key])
|
|
||||||
errors.staffAnswers = ''
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 关联处方:随选中就诊带出(仅演示数据) */
|
/** 关联处方:随选中就诊带出(仅演示数据) */
|
||||||
const prescription = computed<LinkedPrescription | null>(() =>
|
const prescription = computed<LinkedPrescription | null>(() =>
|
||||||
isSigningMockEnabled ? buildLinkedPrescription(selectedVisit.value) : null,
|
isSigningMockEnabled ? buildLinkedPrescription(selectedVisit.value) : null,
|
||||||
@@ -340,8 +309,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
errors.visit = ''
|
errors.visit = ''
|
||||||
errors.document = ''
|
errors.document = ''
|
||||||
errors.sms = ''
|
errors.sms = ''
|
||||||
errors.staffAnswers = ''
|
|
||||||
errors.signer = ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
@@ -355,10 +322,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
selectedVisitId.value = ''
|
selectedVisitId.value = ''
|
||||||
method.value = initialTemplate?.supportedMethods[0] ?? 'pad'
|
method.value = initialTemplate?.supportedMethods[0] ?? 'pad'
|
||||||
smsDestination.value = ''
|
smsDestination.value = ''
|
||||||
Object.keys(staffAnswers).forEach((key) => delete staffAnswers[key])
|
|
||||||
signerType.value = 'SELF'
|
|
||||||
signerName.value = ''
|
|
||||||
signerRelation.value = ''
|
|
||||||
phonePlain.value = false
|
phonePlain.value = false
|
||||||
suggestionOpen.value = false
|
suggestionOpen.value = false
|
||||||
selectedDepartment.value = ''
|
selectedDepartment.value = ''
|
||||||
@@ -376,10 +339,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
selectedTemplateId.value = initialTemplate?.id ?? ''
|
selectedTemplateId.value = initialTemplate?.id ?? ''
|
||||||
method.value = initialTemplate?.supportedMethods[0] ?? method.value
|
method.value = initialTemplate?.supportedMethods[0] ?? method.value
|
||||||
smsDestination.value = ''
|
smsDestination.value = ''
|
||||||
Object.keys(staffAnswers).forEach((key) => delete staffAnswers[key])
|
|
||||||
signerType.value = 'SELF'
|
|
||||||
signerName.value = ''
|
|
||||||
signerRelation.value = ''
|
|
||||||
errors.document = ''
|
errors.document = ''
|
||||||
errors.sms = ''
|
errors.sms = ''
|
||||||
createTaskIdempotencyKey = newIdempotencyKey()
|
createTaskIdempotencyKey = newIdempotencyKey()
|
||||||
@@ -581,18 +540,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
return `${value.slice(0, 3)}****${value.slice(-4)}`
|
return `${value.slice(0, 3)}****${value.slice(-4)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleStaffAnswerOption(fieldId: string, option: string, checked: boolean) {
|
|
||||||
const selected = (staffAnswers[fieldId] ?? '').split('、').filter(Boolean)
|
|
||||||
const next = checked
|
|
||||||
? [...new Set([...selected, option])]
|
|
||||||
: selected.filter((item) => item !== option)
|
|
||||||
staffAnswers[fieldId] = next.join('、')
|
|
||||||
}
|
|
||||||
|
|
||||||
function staffAnswerHasOption(fieldId: string, option: string) {
|
|
||||||
return (staffAnswers[fieldId] ?? '').split('、').includes(option)
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate() {
|
function validate() {
|
||||||
clearErrors()
|
clearErrors()
|
||||||
let valid = true
|
let valid = true
|
||||||
@@ -624,22 +571,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const missingField = manualFormFields.value.find(
|
|
||||||
(field: SigningFormField) => field.required && !staffAnswers[field.id]?.trim(),
|
|
||||||
)
|
|
||||||
if (missingField) {
|
|
||||||
errors.staffAnswers = `请填写必填项:${missingField.label}`
|
|
||||||
valid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
signerType.value === 'FAMILY' &&
|
|
||||||
(!signerName.value.trim() || !signerRelation.value.trim())
|
|
||||||
) {
|
|
||||||
errors.signer = '家属代签必须填写签署人姓名和与患者关系'
|
|
||||||
valid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid
|
return valid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,10 +596,11 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
documentContentHtml: selectedTemplate.value.contentHtml,
|
documentContentHtml: selectedTemplate.value.contentHtml,
|
||||||
// 需科室确认由文书模板标记带出(原型 V6.9 起弹窗里不再让人选)
|
// 需科室确认由文书模板标记带出(原型 V6.9 起弹窗里不再让人选)
|
||||||
needConfirm: selectedTemplate.value.needConfirm ?? false,
|
needConfirm: selectedTemplate.value.needConfirm ?? false,
|
||||||
staffAnswers: { ...staffAnswers },
|
// 签署人固定为患者本人:发起弹窗不再采集签署人 / 代签信息,
|
||||||
signerType: signerType.value,
|
// 后端仍按这三个字段接收(接口中均为可选)。
|
||||||
signerName: signerType.value === 'FAMILY' ? signerName.value.trim() : patient.value.name,
|
signerType: 'SELF',
|
||||||
signerRelation: signerType.value === 'FAMILY' ? signerRelation.value.trim() : '本人',
|
signerName: patient.value.name,
|
||||||
|
signerRelation: '本人',
|
||||||
idempotencyKey: createTaskIdempotencyKey,
|
idempotencyKey: createTaskIdempotencyKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -726,13 +658,6 @@ export function useSigningTaskForm(options: UseSigningTaskFormOptions) {
|
|||||||
selectedVisit,
|
selectedVisit,
|
||||||
selectedVisitId,
|
selectedVisitId,
|
||||||
smsDestination,
|
smsDestination,
|
||||||
staffAnswers,
|
|
||||||
manualFormFields,
|
|
||||||
signerType,
|
|
||||||
signerName,
|
|
||||||
signerRelation,
|
|
||||||
staffAnswerHasOption,
|
|
||||||
toggleStaffAnswerOption,
|
|
||||||
submit,
|
submit,
|
||||||
submitting,
|
submitting,
|
||||||
suggestionOpen,
|
suggestionOpen,
|
||||||
|
|||||||
Reference in New Issue
Block a user