| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098 |
- <script setup lang="ts">
- import { reactive, ref, computed, nextTick } from 'vue'
- import ContractBody from './components/ContractBody.vue'
- import AttachmentPage from './components/AttachmentPage.vue'
- import AttachmentSelector from './components/AttachmentSelector.vue'
- import RiskDisclosureBody from './components/RiskDisclosureBody.vue'
- import CheckInRegistrationBody from './components/CheckInRegistrationBody.vue'
- import CheckInInformationBody from './components/CheckInInformationBody.vue'
- import ElderSafetyCommitmentBody from './components/ElderSafetyCommitmentBody.vue'
- import OutingConfirmationBody from './components/OutingConfirmationBody.vue'
- import SignatureProxyApplicationBody from './components/SignatureProxyApplicationBody.vue'
- import PowerOfAttorneyBody from './components/PowerOfAttorneyBody.vue'
- import DelegationAgentConfirmationBody from './components/DelegationAgentConfirmationBody.vue'
- import ServiceChargingStandardsBody from './components/ServiceChargingStandardsBody.vue'
- import RoomFacilitiesEquipmentBody from './components/RoomFacilitiesEquipmentBody.vue'
- import ExplanationExaminationReportBody from './components/ExplanationExaminationReportBody.vue'
- import DocumentAttachmentBody from './components/DocumentAttachmentBody.vue'
- import FirstServiceProjectConfirmationBody from './components/FirstServiceProjectConfirmationBody.vue'
- import ChangeConfirmationFormBody from './components/ChangeConfirmationFormBody.vue'
- import {
- riskDisclosure_getById,
- checkInRegistration_getById,
- elderSafetyCommitment_getById,
- outingConfirmation_getById,
- signatureProxyApplication_getById,
- powerOfAttorney_getById,
- delegationAgentConfirmation_getById,
- serviceChargingStandards_getById,
- roomFacilitiesEquipment_getById,
- explanationExaminationReport_getById,
- partyBIdentificationDocument_getById,
- guardianPartyB_getById,
- registrationCertificateCivilAffairs_getById,
- comprehensiveAssessmentCapabilities_getById,
- firstServiceProjectConfirmation_getById,
- changeConfirmationForm_getById
- } from '@/api/elderly/contracts'
- const attachmentDetailMap: Record<string, (id: number | string) => Promise<any>> = {
- attach_1: riskDisclosure_getById,
- attach_2: checkInRegistration_getById,
- attach_4: elderSafetyCommitment_getById,
- attach_5: outingConfirmation_getById,
- attach_6: signatureProxyApplication_getById,
- attach_7: powerOfAttorney_getById,
- attach_8: delegationAgentConfirmation_getById,
- attach_9: serviceChargingStandards_getById,
- attach_10: roomFacilitiesEquipment_getById,
- attach_11: explanationExaminationReport_getById,
- attach_12: partyBIdentificationDocument_getById,
- attach_13: guardianPartyB_getById,
- attach_14: registrationCertificateCivilAffairs_getById,
- attach_15: comprehensiveAssessmentCapabilities_getById,
- attach_16: firstServiceProjectConfirmation_getById,
- attach_17: changeConfirmationForm_getById
- }
- const message = useMessage()
- const visible = ref(false)
- const formLoading = ref(false)
- const isTextMode = ref(false)
- const isPrint = ref(false)
- const contractBodyRef = ref<any>(null)
- const recordRow = ref<any>(null)
- const attachmentList = [
- { no: 1, title: '知情同意书' },
- { no: 2, title: '入住登记表' },
- { no: 3, title: '入住须知' },
- { no: 4, title: '长者安全承诺书' },
- { no: 5, title: '长者外出情况确认书' },
- { no: 6, title: '签名代理申请' },
- { no: 7, title: '授权委托书' },
- { no: 8, title: '委托代理人确认表' },
- { no: 9, title: '机构服务范围及收费标准' },
- { no: 10, title: '房间设施设备清单' },
- { no: 11, title: '体检报告项目说明' },
- { no: 12, title: '乙方有效证件身份证、户口本复印件' },
- { no: 13, title: '乙方监护人(丙方)身份证、户口本复印件' },
- { no: 14, title: '甲方登记证书及民政部门备案回执' },
- { no: 15, title: '老年人能力综合评估结果' },
- { no: 16, title: '首次服务项目确认表' },
- { no: 17, title: '变更事项确认表' }
- ]
- const attachments = reactive<Record<string, any>>(
- attachmentList.reduce(
- (acc: any, item) => {
- // 固定内容附件(3=入住须知)默认展示,不需要从列表选择
- if (item.no === 3) {
- acc[`attach_${item.no}`] = { id: '', title: item.title }
- } else {
- acc[`attach_${item.no}`] = null
- }
- return acc
- },
- {} as Record<string, any>
- )
- )
- const riskDisclosureForm = reactive<Record<string, any>>({})
- const safetyCommitmentForm = reactive<Record<string, any>>({
- elderSign: '',
- guardianSign: '',
- signDate: ''
- })
- const outingConfirmationForm = reactive<Record<string, any>>({
- elderName: '',
- outingAbility: '',
- elderSign: '',
- guardianSign: '',
- signDate: ''
- })
- const signatureProxyForm = reactive<Record<string, any>>({
- elderName: '',
- idCardNo: '',
- agentName: '',
- agentIdCardNo: '',
- applicantSign: '',
- agentSign: '',
- signDate: '',
- handlerSign: ''
- })
- const powerOfAttorneyForm = reactive<Record<string, any>>({
- principalName: '',
- principalGender: '',
- principalIdCardNo: '',
- institutionName: '',
- agentName: '',
- agentGender: '',
- agentIdCardNo: '',
- agentPhone: '',
- elderName: '',
- relationship: '',
- principalSign: '',
- agentSign: '',
- signDate: ''
- })
- const delegationAgentForm = reactive<Record<string, any>>({
- elderName: '',
- elderGender: '',
- elderAge: '',
- elderIdCardNo: '',
- elderAddress: '',
- agentName: '',
- agentGender: '',
- agentIdCardNo: '',
- agentAddress: '',
- declarerName: '',
- representedName: '',
- relationship: '',
- elderSign: '',
- agentSign: '',
- signDate: ''
- })
- const serviceChargingForm = reactive<Record<string, any>>({
- signatorySign: '',
- signDate: ''
- })
- const roomFacilitiesForm = reactive<Record<string, any>>({
- elderName: '',
- roomNo: '',
- leftItems: [],
- rightItems: [],
- blankItems: [],
- elderSign: '',
- guardianSign: '',
- signDate: ''
- })
- const examinationReportForm = reactive<Record<string, any>>({
- images: []
- })
- const identificationPartyBForm = reactive<Record<string, any>>({
- images: []
- })
- const guardianPartyBForm = reactive<Record<string, any>>({
- images: []
- })
- const registrationCertificateForm = reactive<Record<string, any>>({
- images: []
- })
- const comprehensiveAssessmentForm = reactive<Record<string, any>>({
- images: []
- })
- const firstServiceForm = reactive<Record<string, any>>({})
- const changeConfirmForm = reactive<Record<string, any>>({})
- const checkInRegistrationForm = reactive<Record<string, any>>({
- checkInNo: '',
- formDate: '',
- elderName: '',
- gender: '',
- age: '',
- photo: '',
- nationality: '',
- birthDate: '',
- nativePlace: '',
- householdPlace: '',
- nation: '',
- nationOther: '',
- politicalStatus: '',
- maritalStatus: '',
- idCardType: '',
- idCardNo: '',
- educationLevel: '',
- residentialAddress: '',
- guarantorName: '',
- guarantorRelation: '',
- guarantorPhone: '',
- guarantorIdCardType: '',
- guarantorIdCardNo: '',
- guarantorAddress: '',
- guarantorEmail: '',
- secondContactName: '',
- secondContactPhone: '',
- medicalPaymentMethod: '',
- medicalPaymentOther: '',
- incomeSource: [],
- incomeSourceOther: '',
- preResidence: '',
- preResidenceHomeType: '',
- preResidenceHomeOther: '',
- checkInReason: '',
- pastHistory: {
- hasDisease: false,
- diseases: [
- { name: '', confirmTime: '' },
- { name: '', confirmTime: '' }
- ],
- hasSurgery: false,
- surgeries: [
- { name: '', time: '' },
- { name: '', time: '' }
- ],
- hasTrauma: false,
- traumas: [
- { part: '', time: '' },
- { part: '', time: '' }
- ]
- },
- currentDiseases: [
- { name: '', confirmTime: '', currentStatus: '' },
- { name: '', confirmTime: '', currentStatus: '' }
- ],
- medicalSituation: {
- regularVisit: { none: true, reason: '', frequency: '', frequencyUnit: '' },
- hospitalization: {
- none: true,
- count: '',
- records: [
- { inTime: '', outTime: '', reason: '', hospital: '' },
- { inTime: '', outTime: '', reason: '', hospital: '' }
- ]
- },
- emergency: {
- none: true,
- count: '',
- records: [{ time: '', reason: '', hospital: '' }]
- }
- },
- discomfortSymptoms: {
- none: true,
- items: [],
- other: ''
- },
- allergyHistory: {
- drug: { none: true, detail: '' },
- food: { none: true, detail: '' },
- environment: { none: true, detail: '' }
- },
- geriatricSyndrome: {
- fall: { none: true, detail: '' },
- memoryDecline: { none: true, detail: '' },
- weightLoss: { none: true, weight: '' },
- urinaryIncontinence: { none: true, count: '' },
- sleepDisorder: { none: true, types: [], other: '' },
- pain: { none: true, part: '' },
- visionAbnormal: { none: true, types: [], degree: '' },
- hearingLoss: { none: true, detail: '' }
- },
- mentalStatus: {
- none: true,
- items: [],
- other: ''
- },
- languageExpression: [],
- languageExpressionOther: '',
- otherNotes: '',
- partyBSign: '',
- partyCSign: '',
- signDate: ''
- })
- const checkInInformationForm = ref({})
- const contractSignatureData = ref<Record<string, any>>({
- partyASign: '',
- partyALegalSign: '',
- partyADate: '',
- partyBSign: '',
- partyBDate: '',
- partyCSign: '',
- partyCDate: ''
- })
- const handleContractDataChange = (data: any) => {
- if (!data) return
- contractSignatureData.value.partyASign = data.partyASign || ''
- contractSignatureData.value.partyALegalSign = data.partyALegalSign || ''
- contractSignatureData.value.partyADate = data.partyADate || ''
- contractSignatureData.value.partyBSign = data.partyBSign || ''
- contractSignatureData.value.partyBDate = data.partyBDate || ''
- contractSignatureData.value.partyCSign = data.partyCSign || ''
- contractSignatureData.value.partyCDate = data.partyCDate || ''
- }
- const handleAttachmentsLoad = (data: Record<string, any>) => {
- console.log('收到', data)
- if (!data) return
- Object.keys(data).forEach((key) => {
- if (attachments.hasOwnProperty(key)) {
- // console.log('AAAAAAA', data[key])
- attachments[key] = data[key]
- if (key == 'attach_1') {
- Object.assign(riskDisclosureForm, data[key])
- } else if (key == 'attach_2') {
- Object.assign(checkInRegistrationForm, data[key])
- } else if (key == 'attach_4') {
- Object.assign(safetyCommitmentForm, data[key])
- } else if (key == 'attach_5') {
- Object.assign(outingConfirmationForm, data[key])
- } else if (key == 'attach_6') {
- Object.assign(signatureProxyForm, data[key])
- } else if (key == 'attach_7') {
- Object.assign(powerOfAttorneyForm, data[key])
- } else if (key == 'attach_8') {
- Object.assign(delegationAgentForm, data[key])
- } else if (key == 'attach_9') {
- Object.assign(serviceChargingForm, data[key])
- } else if (key == 'attach_10') {
- Object.assign(roomFacilitiesForm, data[key])
- } else if (key == 'attach_11') {
- Object.assign(examinationReportForm, data[key])
- } else if (key == 'attach_12') {
- Object.assign(identificationPartyBForm, data[key])
- } else if (key == 'attach_13') {
- Object.assign(guardianPartyBForm, data[key])
- } else if (key == 'attach_14') {
- Object.assign(registrationCertificateForm, data[key])
- } else if (key == 'attach_15') {
- Object.assign(comprehensiveAssessmentForm, data[key])
- } else if (key == 'attach_16') {
- Object.assign(firstServiceForm, data[key])
- } else if (key == 'attach_17') {
- Object.assign(changeConfirmForm, data[key])
- }
- }
- })
- }
- const selectedAttachments = computed(() => {
- return attachmentList.filter((a) => {
- const data = attachments[`attach_${a.no}`]
- if (!data) return false
- if (Array.isArray(data)) return data.length > 0
- if (typeof data === 'object') return Object.keys(data).length > 0
- return !!data
- })
- })
- const selectorVisible = ref<{
- show: boolean
- current: string
- title: string
- list: any[]
- }>({
- show: false,
- current: '',
- title: '',
- list: []
- })
- const type_c = ref(1)
- const open = (row?: any, type = 1) => {
- recordRow.value = row || null
- type_c.value = type
- isTextMode.value = type_c.value != 1
- formLoading.value = true
- isPrint.value = false
- attachmentList.forEach((it) => {
- // 固定内容附件(3=入住须知)默认展示,不需要从列表选择
- if (it.no === 3) {
- attachments[`attach_${it.no}`] = { title: it.title }
- } else {
- attachments[`attach_${it.no}`] = null
- }
- })
- visible.value = true
- setTimeout(() => {
- formLoading.value = false
- }, 100)
- }
- const close = () => {
- visible.value = false
- }
- defineExpose({ open, close })
- const emit = defineEmits(['refreshTree'])
- const handleSave = async () => {
- formLoading.value = true
- try {
- if (contractBodyRef.value) {
- await contractBodyRef.value.saveContract()
- }
- message.success('保存成功')
- visible.value = false
- emit('refreshTree')
- } finally {
- setTimeout(() => {
- formLoading.value = false
- }, 500)
- }
- }
- const handleClose = () => {
- visible.value = false
- }
- const handlePrint = async () => {
- isPrint.value = true
- isTextMode.value = true
- await nextTick()
- await new Promise((resolve) => setTimeout(resolve, 1500))
- window.print()
- setTimeout(() => {
- isPrint.value = false
- isTextMode.value = false
- }, 500)
- }
- const toggleTextMode = () => {
- isTextMode.value = !isTextMode.value
- }
- const openAttachmentSelector = (attach: any) => {
- selectorVisible.value = {
- show: true,
- current: `attach_${attach.no}`,
- title: attach.title,
- list: []
- }
- }
- const handleAttachmentDelete = (attach: any) => {
- const key = `attach_${attach.no}`
- // 固定内容附件(3=入住须知)删除后恢复默认展示
- if (attach.no === 3) {
- attachments[key] = { title: attach.title }
- } else {
- attachments[key] = null
- }
- message.success(`已删除:${attach.title}`)
- }
- const handleAttachmentSelect = async (row: any) => {
- const key = selectorVisible.value.current
- console.log('KEY值:', key, row, attachments)
- if (key) {
- const getDetail = attachmentDetailMap[key]
- let fullData = row
- if (getDetail && row.id) {
- try {
- const detail = await getDetail(row.id)
- if (detail && detail.content) {
- fullData = detail.content
- const dataJson = JSON.parse(fullData)
- // 将id添加到数据中,方便后续操作
- dataJson.id = row.id
- fullData = JSON.stringify(dataJson)
- }
- } catch (error) {
- console.error(`获取附件详情失败: ${key}`, error)
- }
- }
- let data = undefined
- try {
- attachments[key] = fullData
- data = JSON.parse(fullData)
- } catch (error) {}
- if (key === 'attach_1' && data) {
- Object.assign(riskDisclosureForm, data)
- } else if (key === 'attach_2') {
- Object.assign(checkInRegistrationForm, data)
- } else if (key === 'attach_3') {
- Object.assign(safetyCommitmentForm, data)
- } else if (key === 'attach_5') {
- Object.assign(outingConfirmationForm, data)
- } else if (key == 'attach_6') {
- Object.assign(signatureProxyForm, data)
- } else if (key == 'attach_7') {
- Object.assign(powerOfAttorneyForm, data)
- } else if (key == 'attach_8') {
- Object.assign(delegationAgentForm, data)
- } else if (key == 'attach_9') {
- Object.assign(serviceChargingForm, data)
- } else if (key == 'attach_10') {
- Object.assign(roomFacilitiesForm, data)
- } else if (key == 'attach_11') {
- Object.assign(examinationReportForm, data)
- } else if (key == 'attach_12') {
- Object.assign(identificationPartyBForm, data)
- } else if (key == 'attach_13') {
- Object.assign(guardianPartyBForm, data)
- } else if (key == 'attach_14') {
- Object.assign(registrationCertificateForm, data)
- } else if (key == 'attach_15') {
- Object.assign(comprehensiveAssessmentForm, data)
- } else if (key == 'attach_16') {
- Object.assign(firstServiceForm, data)
- } else if (key == 'attach_17') {
- Object.assign(changeConfirmForm, data)
- }
- message.success(
- `已选择:${fullData.elderName || row[activeTitleField(key)] || attachTitle(key)}`
- )
- }
- selectorVisible.value.show = false
- }
- const attachTitle = (key: string) => {
- const no = Number(key.replace('attach_', ''))
- const item = attachmentList.find((it) => it.no === no)
- return item?.title || '附件数据'
- }
- const activeTitleField = (key: string) => {
- const map: Record<string, string> = {
- attach_2: 'elderName'
- }
- return map[key] || 'title'
- }
- const handleAttachmentSelectorClose = () => {
- selectorVisible.value.show = false
- }
- const handFormData = (data: any) => {
- console.log('收到:', data)
- }
- const renderAttachmentContent = (key: string) => {
- const data = attachments[key]
- if (!data) return null
- return data.title || '已选择数据'
- }
- </script>
- <template>
- <el-drawer
- v-model="visible"
- title="电子合同"
- size="70vw"
- direction="rtl"
- class="contract-manage-drawer"
- >
- <div class="drawer-content">
- <div class="content-toolbar" v-if="!isPrint">
- <el-tag type="info" size="large">颐年集团养老服务合同</el-tag>
- <div class="toolbar-right">
- <el-tooltip
- :content="isTextMode ? '切换为编辑模式(输入框)' : '切换为文本模式(打印预览)'"
- placement="top"
- >
- <el-button
- v-show="type_c == 1"
- :type="isTextMode ? 'success' : 'default'"
- size="small"
- @click="toggleTextMode"
- >
- {{ isTextMode ? '文本模式' : '编辑模式' }}
- </el-button>
- </el-tooltip>
- <el-button
- v-show="type_c == 1"
- type="primary"
- :loading="formLoading"
- size="small"
- @click="handleSave"
- >保存</el-button
- >
- <el-button size="small" @click="handleClose">关闭</el-button>
- <el-tooltip
- placement="bottom"
- content="打印时目标打印机选择「Microsoft Print to PDF」;导出时目标打印机选择「另存为 PDF」"
- >
- <el-button type="success" size="small" @click="handlePrint">打印/导出</el-button>
- </el-tooltip>
- </div>
- </div>
- <div class="content-body">
- <!-- ============ 合同主体 ============ -->
- <div class="section-divider">
- <span>合同主体</span>
- </div>
- <ContractBody
- ref="contractBodyRef"
- :record-row="recordRow"
- :is-text-mode="isTextMode"
- v-model="contractSignatureData"
- :attachment-ids="attachments"
- @update:form-data="handFormData"
- @update:data="handleContractDataChange"
- @update:attachments="handleAttachmentsLoad"
- />
- <!-- ============ 16个附件 ============ -->
- <div class="section-divider" style="margin-top: 30px">
- <span>附件清单</span>
- </div>
- <AttachmentPage
- v-for="attach in attachmentList"
- :key="attach.no"
- :attachment-no="attach.no"
- :title="attach.title"
- :selected-data="attachments[`attach_${attach.no}`]"
- :is-text-mode="isTextMode"
- @select="openAttachmentSelector(attach)"
- @delete="handleAttachmentDelete(attach)"
- >
- <template #default="{ data }">
- <div v-if="attach.no === 1" class="attachment-content">
- <RiskDisclosureBody v-model="riskDisclosureForm" :is-text-mode="isTextMode" />
- </div>
- <div v-else-if="attach.no === 2" class="attachment-content">
- <CheckInRegistrationBody
- v-model="checkInRegistrationForm"
- :is-text-mode="true"
- :elder-id="recordRow?.elderId"
- />
- </div>
- <div v-else-if="attach.no === 3" class="attachment-content">
- <CheckInInformationBody
- v-model="checkInInformationForm"
- :is-text-mode="true"
- :elder-id="recordRow?.elderId"
- />
- </div>
- <div v-else-if="attach.no === 4" class="attachment-content">
- <ElderSafetyCommitmentBody v-model="safetyCommitmentForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 5" class="attachment-content">
- <OutingConfirmationBody v-model="outingConfirmationForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 6" class="attachment-content">
- <SignatureProxyApplicationBody v-model="signatureProxyForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 7" class="attachment-content">
- <PowerOfAttorneyBody v-model="powerOfAttorneyForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 8" class="attachment-content">
- <DelegationAgentConfirmationBody v-model="delegationAgentForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 9" class="attachment-content">
- <ServiceChargingStandardsBody v-model="serviceChargingForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 10" class="attachment-content">
- <RoomFacilitiesEquipmentBody v-model="roomFacilitiesForm" :is-text-mode="true" />
- </div>
- <div v-else-if="attach.no === 11" class="attachment-content">
- <ExplanationExaminationReportBody
- v-model="examinationReportForm"
- :is-text-mode="true"
- />
- </div>
- <div v-else-if="attach.no === 12" class="attachment-content">
- <DocumentAttachmentBody
- v-model="identificationPartyBForm"
- :is-text-mode="true"
- title="乙方有效证件"
- description="乙方:有效身份证件复印件(正反面复印)及户口本复印件(户主页和本人页)"
- />
- </div>
- <div v-else-if="attach.no === 13" class="attachment-content">
- <DocumentAttachmentBody
- v-model="guardianPartyBForm"
- :is-text-mode="true"
- title="乙方监护人(丙方)身份证、户口本复印件"
- description="丙方:(系自然人的)有效身份证件复印件(正反面复印)及户口本复印件(户主页和本人页);(系单位的)的有效注册登登记材料复印件(加盖公章)、法定代表人/负责人及联系人的身份证件复印件(身份证件需正反面复印)"
- />
- </div>
- <div v-else-if="attach.no === 14" class="attachment-content">
- <DocumentAttachmentBody
- v-model="registrationCertificateForm"
- :is-text-mode="true"
- description="甲方登记证书及民政部门备案回执"
- />
- </div>
- <div v-else-if="attach.no === 15" class="attachment-content">
- <DocumentAttachmentBody
- v-model="comprehensiveAssessmentForm"
- :is-text-mode="true"
- title="老年人能力综合评估结果"
- />
- </div>
- <div v-else-if="attach.no === 16" class="attachment-content">
- <FirstServiceProjectConfirmationBody
- v-model="firstServiceForm"
- :is-text-mode="true"
- />
- </div>
- <div v-else-if="attach.no === 17" class="attachment-content">
- <ChangeConfirmationFormBody v-model="changeConfirmForm" :is-text-mode="true" />
- </div>
- <div v-else class="attachment-body">
- <p><strong>日期:</strong>{{ data?.createTime || '-' }}</p>
- <p style="color: #999; font-size: 13px">
- (此处为附件内容占位,实际各附件将由对应列表页提供完整内容排版)
- </p>
- </div>
- </template>
- </AttachmentPage>
- </div>
- </div>
- </el-drawer>
- <AttachmentSelector
- v-model:visible="selectorVisible.show"
- :title="selectorVisible.title"
- :current="selectorVisible.current"
- :elder-id="recordRow?.elderId"
- :list="selectorVisible.list"
- @select="handleAttachmentSelect"
- @update:visible="handleAttachmentSelectorClose"
- />
- <!-- ========== 打印容器:Teleport 到 body,确保是 body 直接子元素 ========== -->
- <Teleport to="body">
- <div v-if="isPrint" class="print-container">
- <!-- 合同主体 -->
- <ContractBody
- :record-row="recordRow"
- :is-text-mode="true"
- v-model="contractSignatureData"
- :attachment-ids="attachments"
- />
- <!-- 已选的附件 -->
- <template v-if="selectedAttachments.length > 0">
- <div v-for="attach in selectedAttachments" :key="attach.no" class="print-attachment">
- <!-- 附件1:知情同意书,使用 RiskDisclosureBody -->
- <RiskDisclosureBody
- v-if="attach.no === 1"
- v-model="riskDisclosureForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 附件2:入住登记表,使用 CheckInRegistrationBody -->
- <CheckInRegistrationBody
- v-else-if="attach.no === 2"
- v-model="checkInRegistrationForm"
- class="mgb"
- :is-text-mode="true"
- :elder-id="recordRow?.elderId"
- />
- <!-- 附件3:入住须知,使用 CheckInInformationBody -->
- <CheckInInformationBody v-else-if="attach.no === 3" class="mgb" :is-text-mode="true" />
- <!-- 附件4:长者安全承诺书,使用 ElderSafetyCommitmentBody -->
- <ElderSafetyCommitmentBody
- v-else-if="attach.no === 4"
- class="mgb"
- v-model="safetyCommitmentForm"
- :is-text-mode="true"
- />
- <!-- 附件5:长者外出情况确认书,使用 OutingConfirmationBody -->
- <OutingConfirmationBody
- v-else-if="attach.no === 5"
- class="mgb"
- v-model="outingConfirmationForm"
- :is-text-mode="true"
- />
- <!-- 附件6:签名代理申请,使用 SignatureProxyApplicationBody -->
- <SignatureProxyApplicationBody
- v-else-if="attach.no === 6"
- class="mgb"
- v-model="signatureProxyForm"
- :is-text-mode="true"
- />
- <!-- 附件7:授权委托书,使用 PowerOfAttorneyBody -->
- <PowerOfAttorneyBody
- v-else-if="attach.no === 7"
- v-model="powerOfAttorneyForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 附件8:委托代理人确认表,使用 DelegationAgentConfirmationBody -->
- <DelegationAgentConfirmationBody
- v-else-if="attach.no === 8"
- class="mgb"
- v-model="delegationAgentForm"
- :is-text-mode="true"
- />
- <!-- 附件9:机构服务范围及收费标准,使用 ServiceChargingStandardsBody -->
- <ServiceChargingStandardsBody
- v-else-if="attach.no === 9"
- v-model="serviceChargingForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 附件10:标准房间物品配备,使用 RoomFacilitiesEquipmentBody -->
- <RoomFacilitiesEquipmentBody
- v-else-if="attach.no === 10"
- v-model="roomFacilitiesForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 附件11:体检报告项目说明,使用 ExplanationExaminationReportBody -->
- <ExplanationExaminationReportBody
- v-else-if="attach.no === 11"
- v-model="examinationReportForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 附件12:乙方有效证件,使用 DocumentAttachmentBody -->
- <DocumentAttachmentBody
- v-else-if="attach.no === 12"
- v-model="identificationPartyBForm"
- class="mgb"
- :is-text-mode="true"
- title="乙方有效证件"
- description="乙方:有效身份证件复印件(正反面复印)及户口本复印件(户主页和本人页)"
- />
- <!-- 附件13:乙方监护人(丙方)身份证、户口本复印件,使用 DocumentAttachmentBody -->
- <DocumentAttachmentBody
- v-else-if="attach.no === 13"
- v-model="guardianPartyBForm"
- class="mgb"
- :is-text-mode="true"
- title="乙方监护人(丙方)身份证、户口本复印件"
- description="丙方:(系自然人的)有效身份证件复印件(正反面复印)及户口本复印件(户主页和本人页);(系单位的)的有效注册登登记材料复印件(加盖公章)、法定代表人/负责人及联系人的身份证件复印件(身份证件需正反面复印)"
- />
- <!-- 附件14:甲方登记证书及民政部门备案回执,使用 DocumentAttachmentBody -->
- <DocumentAttachmentBody
- v-else-if="attach.no === 14"
- v-model="registrationCertificateForm"
- class="mgb"
- :is-text-mode="true"
- description="甲方登记证书及民政部门备案回执"
- />
- <!-- 附件15:老年人能力综合评估结果,使用 DocumentAttachmentBody -->
- <DocumentAttachmentBody
- v-else-if="attach.no === 15"
- v-model="comprehensiveAssessmentForm"
- class="mgb"
- :is-text-mode="true"
- title="老年人能力综合评估结果"
- />
- <!-- 附件16:首次服务项目确认表,使用 FirstServiceProjectConfirmationBody -->
- <FirstServiceProjectConfirmationBody
- v-else-if="attach.no === 16"
- v-model="firstServiceForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 附件17:变更事项确认表,使用 ChangeConfirmationFormBody -->
- <ChangeConfirmationFormBody
- v-else-if="attach.no === 17"
- v-model="changeConfirmForm"
- class="mgb"
- :is-text-mode="true"
- />
- <!-- 其他附件:展示标题和信息 -->
- <div v-else class="a4-page">
- <div class="print-attachment-header">
- <div class="print-attachment-title">附件{{ attach.no }}:{{ attach.title }}</div>
- </div>
- <div class="print-attachment-info">
- <p><strong>名称:</strong>{{ renderAttachmentContent(`attach_${attach.no}`) }}</p>
- <p><strong>版本:</strong>{{ attachments[`attach_${attach.no}`]?.version || '-' }}</p>
- <p
- ><strong>日期:</strong
- >{{ attachments[`attach_${attach.no}`]?.createTime || '-' }}</p
- >
- </div>
- </div>
- </div>
- </template>
- </div>
- </Teleport>
- </template>
- <style lang="scss">
- .contract-manage-drawer {
- .el-drawer__header {
- margin-bottom: 0 !important;
- padding: 14px 20px;
- }
- .el-drawer__body {
- padding: 0 !important;
- display: flex;
- flex-direction: column;
- height: 100%;
- overflow: hidden;
- }
- }
- /* ========== 打印容器(屏幕上隐藏,仅在 html2pdf 导出时临时显示,或在 @media print 时显示) ========== */
- .print-container {
- display: none;
- }
- /* ========== 打印样式核心逻辑:只显示 Teleport 到 body 的 print-container ========== */
- @media print {
- html,
- body {
- background: #fff !important;
- margin: 0 !important;
- padding: 0 !important;
- overflow: visible !important;
- }
- /* 1. body 的所有直接子元素都隐藏,除了 print-container */
- body > *:not(.print-container) {
- display: none !important;
- }
- /* 2. 打印容器本身显示出来 */
- body > .print-container {
- display: block !important;
- }
- /* 3. A4 页:保留屏幕内边距(10mm 14mm),由 @page margin 控制物理边距
- 各组件打印样式已统一为 width:100%,不会再溢出 */
- .print-container .a4-page {
- width: 100% !important;
- margin: 0 !important;
- padding: 10mm 14mm !important;
- background: #fff !important;
- box-shadow: none !important;
- box-sizing: border-box !important;
- page-break-after: auto;
- break-after: auto;
- }
- .print-container .print-attachment .mgb {
- padding-bottom: 30px !important;
- }
- /* 封面页保留完整 A4 高度并强制分页(可打印区域 265mm,@page margin 16mm) */
- .print-container .a4-page.cover-a4 {
- min-height: 265mm !important;
- page-break-after: always;
- break-after: page;
- }
- /* 其他页自适应高度,内容连续流动 */
- .print-container .a4-page:not(.cover-a4) {
- min-height: auto !important;
- page-break-after: auto;
- break-after: auto;
- }
- /* 4. 防止标题、列表项、签名区被分页切断 */
- .print-container .section-title,
- .print-container .sub-title {
- break-after: avoid-page;
- page-break-after: avoid;
- }
- .print-container .num-list li,
- .print-container .signature-group {
- break-inside: avoid-page;
- page-break-inside: avoid;
- }
- @page {
- size: 210mm 297mm;
- margin: 16mm;
- }
- }
- </style>
- <style scoped lang="scss">
- .drawer-content {
- display: flex;
- flex-direction: column;
- height: 100%;
- min-height: 0;
- }
- .content-toolbar {
- flex-shrink: 0;
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 10px 16px;
- background: #f8f9fb;
- border-bottom: 1px solid #e4e7ed;
- }
- .toolbar-right {
- display: flex;
- gap: 8px;
- }
- .section-divider {
- width: 210mm;
- margin: 0 auto 8px;
- text-align: center;
- padding: 8px 0;
- font-size: 15px;
- font-weight: bold;
- color: #666;
- border-top: 1px dashed #ccc;
- position: relative;
- }
- .section-divider span {
- display: inline-block;
- padding: 4px 14px;
- background: #fff;
- border-radius: 4px;
- border: 1px solid #e4e7ed;
- }
- .content-body {
- flex: 1;
- overflow-y: auto;
- padding: 16px 0;
- background: #f5f5f5;
- }
- .content-footer {
- flex-shrink: 0;
- display: flex;
- justify-content: flex-end;
- gap: 12px;
- padding: 12px 20px;
- border-top: 1px solid #ebeef5;
- background: #fafafa;
- }
- .attachment-body {
- padding: 10px 0;
- }
- .attachment-body p {
- margin: 4px 0;
- line-height: 1.8;
- }
- /* 打印模式下其他附件标题样式 */
- .print-attachment-header {
- padding-bottom: 10px;
- border-bottom: 1.5px solid #333;
- margin-bottom: 16px;
- }
- .print-attachment-title {
- font-size: 18px;
- font-weight: bold;
- color: #222;
- }
- .print-attachment-info {
- font-size: 14px;
- line-height: 1.9;
- color: #333;
- }
- .print-attachment-info p {
- margin: 6px 0;
- }
- </style>
|