AttachmentPage.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <script setup lang="ts">
  2. import { computed } from 'vue'
  3. const props = defineProps<{
  4. title: string
  5. attachmentNo: string | number
  6. selectedData?: any
  7. isTextMode?: boolean
  8. }>()
  9. const emit = defineEmits<{
  10. (e: 'select'): void
  11. (e: 'delete'): void
  12. }>()
  13. const hasData = computed(() => {
  14. if (!props.selectedData) return false
  15. if (Array.isArray(props.selectedData)) return props.selectedData.length > 0
  16. if (typeof props.selectedData === 'object') return Object.keys(props.selectedData).length > 0
  17. return !!props.selectedData
  18. })
  19. </script>
  20. <template>
  21. <div class="attachment-page" :class="{ 'is-filled': hasData }">
  22. <div class="attachment-header">
  23. <div class="attachment-title">
  24. 附件{{ attachmentNo }}:{{ title }}
  25. </div>
  26. <div v-if="!isTextMode" class="attachment-actions">
  27. <el-button
  28. type="primary"
  29. size="small"
  30. plain
  31. @click="emit('select')"
  32. >
  33. 从列表中选择
  34. </el-button>
  35. <el-button
  36. v-if="hasData && !isTextMode"
  37. type="danger"
  38. size="small"
  39. plain
  40. @click="emit('delete')"
  41. >
  42. 删除
  43. </el-button>
  44. </div>
  45. </div>
  46. <div v-if="hasData" class="attachment-content">
  47. <div class="attachment-body">
  48. <slot :data="selectedData"></slot>
  49. </div>
  50. </div>
  51. <div v-else class="attachment-empty">
  52. <el-empty :description="isTextMode ? '' : '请点击上方按钮从列表中选择附件数据'" />
  53. </div>
  54. </div>
  55. </template>
  56. <style scoped lang="scss">
  57. .attachment-page {
  58. width: 210mm;
  59. min-height: 297mm;
  60. margin: 4mm auto;
  61. padding: 10mm 14mm;
  62. background: #fff;
  63. box-shadow: 0 0 8px rgba(0, 0, 0, 0.12);
  64. box-sizing: border-box;
  65. &.is-filled {
  66. padding: 0;
  67. background: transparent;
  68. box-shadow: none;
  69. min-height: auto;
  70. }
  71. }
  72. .attachment-header {
  73. display: flex;
  74. justify-content: space-between;
  75. align-items: center;
  76. padding-bottom: 8px;
  77. border-bottom: 1.5px solid #333;
  78. margin-bottom: 16px;
  79. }
  80. .attachment-title {
  81. font-size: 18px;
  82. font-weight: bold;
  83. color: #222;
  84. }
  85. .attachment-actions {
  86. display: flex;
  87. gap: 8px;
  88. }
  89. .attachment-content {
  90. font-size: 14px;
  91. line-height: 1.9;
  92. color: #333;
  93. }
  94. .attachment-body {
  95. padding: 4px 0;
  96. }
  97. .attachment-empty {
  98. margin-top: 40px;
  99. }
  100. @media print {
  101. .attachment-page {
  102. width: 100% !important;
  103. min-height: auto !important;
  104. height: auto !important;
  105. margin: 0 !important;
  106. padding: 10mm 0mm !important;
  107. box-shadow: none !important;
  108. box-sizing: border-box !important;
  109. page-break-after: always;
  110. break-after: page;
  111. }
  112. /* 保留内边距,避免内容溢出可打印区域;不要在这里清 0 */
  113. .attachment-page.is-filled {
  114. background: transparent !important;
  115. box-shadow: none !important;
  116. }
  117. .attachment-page:last-child {
  118. page-break-after: auto;
  119. break-after: auto;
  120. }
  121. }
  122. </style>