|
|
@@ -5,349 +5,375 @@
|
|
|
<!-- 头部信息 -->
|
|
|
<div class="card-header">
|
|
|
<h2 class="header-title">床头卡信息</h2>
|
|
|
+ <div class="header-room">{{ patientData.roomName || 'F301-1' }}</div>
|
|
|
<img src="../../assets/imgs/logo_card.png" alt="颐年医养" class="header-logo" />
|
|
|
</div>
|
|
|
|
|
|
- <!-- 左侧床号信息 -->
|
|
|
- <div class="left-section">
|
|
|
- <div class="room-number">{{ patientData.roomName }}</div>
|
|
|
- <div class="bed-info">
|
|
|
- <span class="bed-letter">{{ patientData.bedName }}</span>
|
|
|
- <span class="bed-text">床</span>
|
|
|
+ <div class="card-main">
|
|
|
+ <!-- 左侧床号信息 -->
|
|
|
+ <div class="left-section">
|
|
|
+ <div class="bed-info">
|
|
|
+ <span class="bed-letter">{{ patientData.bedName || '' }}</span>
|
|
|
+ <span class="bed-text">床</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 二维码 -->
|
|
|
+ <div class="qrcode-container">
|
|
|
+ <Qrcode :text="qrCodeContent" :width="120" :logo="logoUrl" tag="canvas" />
|
|
|
+ <div class="qrcode-text">长者二维码</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 二维码 -->
|
|
|
- <div class="qrcode-container">
|
|
|
- <Qrcode
|
|
|
- :text="qrCodeContent"
|
|
|
- :width="120"
|
|
|
- :logo="logoUrl"
|
|
|
- tag="canvas"
|
|
|
- />
|
|
|
- <div class="qrcode-text">长者二维码</div>
|
|
|
+ <!-- 右侧信息表格 -->
|
|
|
+ <div class="right-section">
|
|
|
+ <table class="info-table">
|
|
|
+ <!-- 基本信息行 -->
|
|
|
+ <tr>
|
|
|
+ <td class="table-label">姓名</td>
|
|
|
+ <td class="table-data">{{ patientData.elderName || '--' }}</td>
|
|
|
+ <td class="table-label">性别</td>
|
|
|
+ <td class="table-data">{{ patientData.elderSex || '--' }}</td>
|
|
|
+ <td class="table-label">生日</td>
|
|
|
+ <td class="table-data">{{ patientData.birthday || '--' }}</td>
|
|
|
+ <td class="table-label">入住时间</td>
|
|
|
+ <td class="table-data">{{ patientData.checkInTime || '--' }}</td>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ <!-- 护理等级 / 照护要点 / 过敏史 -->
|
|
|
+ <tr>
|
|
|
+ <td class="table-label">护理等级</td>
|
|
|
+ <td class="table-data">{{ patientData.careLevel || '--' }}</td>
|
|
|
+ <td class="table-label">照护要点</td>
|
|
|
+ <td class="table-data" colspan="3">{{ patientData.carePoints || '--' }}</td>
|
|
|
+ <td class="table-label">过敏史</td>
|
|
|
+ <td class="table-data">{{ patientData.allergiesText || '--' }}</td>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ <!-- 既往病史 / 用药史 -->
|
|
|
+ <tr>
|
|
|
+ <td class="table-label">既往病史</td>
|
|
|
+ <td class="table-data" colspan="3">{{ patientData.medicalHistory || '--' }}</td>
|
|
|
+ <td class="table-label">用药史</td>
|
|
|
+ <td class="table-data" colspan="3">{{ patientData.medicationHistory || '--' }}</td>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ <!-- 饮食要点 -->
|
|
|
+ <tr>
|
|
|
+ <td class="table-label">饮食要点</td>
|
|
|
+ <td class="table-data diet-cell" colspan="7">
|
|
|
+ <div v-if="hasDietGuidelines" class="diet-list">
|
|
|
+ <div
|
|
|
+ v-for="item in dietTypes"
|
|
|
+ :key="item.value"
|
|
|
+ class="diet-item"
|
|
|
+ :class="{ active: isDietActive(item.label) }"
|
|
|
+ >
|
|
|
+ <span v-if="isDietActive(item.label)" class="diet-check">√</span>
|
|
|
+ <span class="diet-name">{{ item.label }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-else class="diet-empty">--</div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ <!-- 九防注意事项 -->
|
|
|
+ <tr>
|
|
|
+ <td class="table-label prevention-title">
|
|
|
+ <div class="vertical-text">九防注意事项</div>
|
|
|
+ </td>
|
|
|
+ <td class="table-data prevention-cell" colspan="7">
|
|
|
+ <div class="prevention-grid">
|
|
|
+ <div
|
|
|
+ v-for="(item, index) in preventionItems"
|
|
|
+ :key="item.key"
|
|
|
+ class="prevention-item"
|
|
|
+ :class="[`prevention-pos-${index + 1}`]"
|
|
|
+ >
|
|
|
+ <!-- <div class="risk-badge" v-if="patientData[item.field]">
|
|
|
+ <span class="risk-star">★</span>
|
|
|
+ <span class="risk-text">{{ getRiskText(patientData[item.field]) }}</span>
|
|
|
+ </div> -->
|
|
|
+ <img
|
|
|
+ v-if="patientData[item.field]"
|
|
|
+ :src="getPreventionImage(item.field, patientData[item.field])"
|
|
|
+ :alt="item.name"
|
|
|
+ class="placeholder-image"
|
|
|
+ />
|
|
|
+ <div v-else class="prevention-image placeholder-image">
|
|
|
+ <span>{{ item.name }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="prevention-name">{{ item.name }}</div>-->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+
|
|
|
+ <!-- 责任人员 -->
|
|
|
+ <tr>
|
|
|
+ <td class="table-label">责任护理员</td>
|
|
|
+ <td class="table-data" colspan="2">{{
|
|
|
+ patientData.responsibleStaff?.nurseAide || '--'
|
|
|
+ }}</td>
|
|
|
+ <td class="table-label">责任护士</td>
|
|
|
+ <td class="table-data" colspan="2">{{
|
|
|
+ patientData.responsibleStaff?.nurse || '--'
|
|
|
+ }}</td>
|
|
|
+ <td class="table-label">主管医生</td>
|
|
|
+ <td class="table-data">{{ patientData.responsibleStaff?.doctor || '--' }}</td>
|
|
|
+ </tr>
|
|
|
+ </table>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 右侧信息表格 -->
|
|
|
- <div class="right-section">
|
|
|
- <table class="info-table">
|
|
|
- <!-- 基本信息行 -->
|
|
|
- <tr>
|
|
|
- <td class="table-label" style="border-top: 1px solid #000;border-left: 1px solid #000;">姓名</td>
|
|
|
- <td class="table-data" style="border-top: 1px solid #000;">{{ patientData.elderName || '--' }}</td>
|
|
|
- <td class="table-label" style="border-top: 1px solid #000;">性别</td>
|
|
|
- <td class="table-data" style="border-top: 1px solid #000;">{{ patientData.elderSex || '--' }}</td>
|
|
|
- <td class="table-label" style="border-top: 1px solid #000;">生日</td>
|
|
|
- <td class="table-data" style="border-top: 1px solid #000;">{{ patientData.birthday || '--' }}</td>
|
|
|
- <td class="table-label" style="border-top: 1px solid #000;">入住时间</td>
|
|
|
- <td class="table-data" style="border-top: 1px solid #000;">{{ patientData.checkInTime || '--' }}</td>
|
|
|
- </tr>
|
|
|
-
|
|
|
- <!-- 护理信息行 -->
|
|
|
- <tr>
|
|
|
- <td class="table-label" style="border-left: 1px solid #000;">护理等级</td>
|
|
|
- <td class="table-data">{{ patientData.careLevel || '--' }}</td>
|
|
|
- <td class="table-label">血型</td>
|
|
|
- <td class="table-data" colspan="5">{{ patientData.bloodTypeText || '--' }}</td>
|
|
|
-
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td class="table-label" style="border-left: 1px solid #000;">药物过敏</td>
|
|
|
- <td class="table-data" colspan="7">{{ patientData.drugAllergyHistoryText || '--' }}</td>
|
|
|
- </tr>
|
|
|
- <tr>
|
|
|
- <td class="table-label" style="border-left: 1px solid #000;">食物过敏</td>
|
|
|
- <td class="table-data" colspan="7">{{ patientData.historyFoodAllergiesText || '--' }}</td>
|
|
|
- </tr>
|
|
|
- <!-- 病史信息行 -->
|
|
|
- <tr>
|
|
|
- <td class="table-label" style="border-left: 1px solid #000;">既往病史</td>
|
|
|
- <td class="table-data" colspan="7">{{ patientData.medicalHistory || '--' }}</td>
|
|
|
- </tr>
|
|
|
-
|
|
|
- <!-- 饮食要点标题行 -->
|
|
|
- <tr>
|
|
|
- <td class="section-title" style="border-left: 1px solid #000;">饮食要点</td>
|
|
|
- <td class="table-data" colspan="7">{{ patientData.diet?.normal || '--' }}</td>
|
|
|
- </tr>
|
|
|
-
|
|
|
- <!-- 饮食类型行 -->
|
|
|
-<!-- <tr>-->
|
|
|
-<!-- <td class="diet-type" colspan="8" style="padding: 0;">-->
|
|
|
-<!-- <div class="diet-container">-->
|
|
|
-<!-- <div class="diet-item" style="border-left: 1px solid #000;">普 食</div>-->
|
|
|
-<!-- <div class="diet-item">软 食</div>-->
|
|
|
-<!-- <div class="diet-item">半流质</div>-->
|
|
|
-<!-- <div class="diet-item">流 质</div>-->
|
|
|
-<!-- <div class="diet-item">鼻 饲</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- </td>-->
|
|
|
-<!-- </tr>-->
|
|
|
-
|
|
|
- <!-- 饮食详情行 -->
|
|
|
-<!-- <tr>-->
|
|
|
-<!-- <td class="table-data" colspan="8" style="padding: 0;">-->
|
|
|
-<!-- <div class="diet-container">-->
|
|
|
-<!-- <div class="diet-item" style="border-left: 1px solid #000;">{{ patientData.diet?.normal || '152467' }}</div>-->
|
|
|
-<!-- <div class="diet-item">{{ patientData.diet?.soft || '152467' }}</div>-->
|
|
|
-<!-- <div class="diet-item">{{ patientData.diet?.semiLiquid || '152467' }}</div>-->
|
|
|
-<!-- <div class="diet-item">{{ patientData.diet?.liquid || '152467' }}</div>-->
|
|
|
-<!-- <div class="diet-item">{{ patientData.diet?.nasogastric || '152467' }}</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- </td>-->
|
|
|
-<!-- </tr>-->
|
|
|
-
|
|
|
- <!-- 责任人员行 -->
|
|
|
-<!-- <tr>-->
|
|
|
-<!-- <td class="table-data" colspan="8" style="padding: 0;">-->
|
|
|
-<!-- <div class="staff-container">-->
|
|
|
-<!-- <div class="staff-label" style="border-left: 1px solid #000;">-->
|
|
|
-<!-- <div style="line-height: 1.2;">责任</div>-->
|
|
|
-<!-- <div style="line-height: 1.2;">护理员</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- <div class="staff-value">{{ patientData.responsibleStaff?.nurseAide || '152467' }}</div>-->
|
|
|
-<!-- <div class="staff-label">-->
|
|
|
-<!-- <div style="line-height: 1.2;">责任</div>-->
|
|
|
-<!-- <div style="line-height: 1.2;">护士</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- <div class="staff-value">{{ patientData.responsibleStaff?.nurse || '152467' }}</div>-->
|
|
|
-<!-- <div class="staff-label">-->
|
|
|
-<!-- <div style="line-height: 1.2;">主管</div>-->
|
|
|
-<!-- <div style="line-height: 1.2;">医生</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- <div class="staff-value">{{ patientData.responsibleStaff?.doctor || '152467' }}</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- </td>-->
|
|
|
-<!-- </tr>-->
|
|
|
- </table>
|
|
|
- </div>
|
|
|
-
|
|
|
<!-- 底部装饰条 -->
|
|
|
- <div class="card-footer">
|
|
|
- <img src="../../assets/imgs/card_bottom.png" alt="颐年医养" style="width: 100%;" />
|
|
|
-
|
|
|
- </div>
|
|
|
+ <div class="card-footer"></div>
|
|
|
</div>
|
|
|
-
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, reactive, onMounted } from 'vue';
|
|
|
+import { ref, reactive, onMounted, computed } from 'vue'
|
|
|
|
|
|
// 定义全局window接口扩展
|
|
|
declare global {
|
|
|
interface Window {
|
|
|
- __GlobalZipManager?: any;
|
|
|
+ __GlobalZipManager?: any
|
|
|
}
|
|
|
}
|
|
|
-import { ElMessage } from 'element-plus';
|
|
|
-import html2canvas from 'html2canvas';
|
|
|
-import { Qrcode } from '@/components/Qrcode';
|
|
|
-import JSZip from 'jszip';
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import html2canvas from 'html2canvas'
|
|
|
+import { Qrcode } from '@/components/Qrcode'
|
|
|
+import JSZip from 'jszip'
|
|
|
// Props定义
|
|
|
const props = defineProps<{
|
|
|
- roomNumber?: string;
|
|
|
- bedLetter?: string;
|
|
|
- showLogo?: boolean;
|
|
|
- qrcodeUrl?: string;
|
|
|
-}>();
|
|
|
+ roomNumber?: string
|
|
|
+ bedLetter?: string
|
|
|
+ showLogo?: boolean
|
|
|
+ qrcodeUrl?: string
|
|
|
+}>()
|
|
|
|
|
|
// 默认值
|
|
|
-const qrCodeContent = ref('');
|
|
|
-//const logoUrl = ref('@/assets/imgs/logo.png');
|
|
|
-const logoUrl = ref('/logo.png');
|
|
|
+const qrCodeContent = ref('')
|
|
|
+const logoUrl = ref('/logo.png')
|
|
|
+
|
|
|
+// 饮食类型
|
|
|
+const dietTypes = [
|
|
|
+ { value: '1', label: '普食' },
|
|
|
+ { value: '2', label: '软食' },
|
|
|
+ { value: '3', label: '半流质' },
|
|
|
+ { value: '4', label: '流质' },
|
|
|
+ { value: '5', label: '鼻饲' }
|
|
|
+]
|
|
|
+
|
|
|
+// 九防项目配置
|
|
|
+const preventionItems = [
|
|
|
+ { key: 'asphyxiation', name: '防噎食', field: 'asphyxiationByChoking' },
|
|
|
+ { key: 'pressureSores', name: '防压疮', field: 'pressureSores' },
|
|
|
+ { key: 'bedFall', name: '防坠床', field: 'fallPreventionMeasures' },
|
|
|
+ { key: 'selfHarm', name: '防他伤和自伤', field: 'commitSuicide' },
|
|
|
+ { key: 'foodDrug', name: '防误食', field: 'assessSimpleMentalState' },
|
|
|
+ { key: 'scald', name: '防烫伤', field: 'empyrosis' },
|
|
|
+ { key: 'fall', name: '防跌倒', field: 'fallDown' },
|
|
|
+ { key: 'wandering', name: '防走失', field: 'wanderAway' },
|
|
|
+ { key: 'entertainment', name: '防文娱活动意外', field: 'antiEntertainment' }
|
|
|
+]
|
|
|
+
|
|
|
+// 判断饮食类型是否激活
|
|
|
+const hasDietGuidelines = computed(() => {
|
|
|
+ return !!(patientData.dietaryGuidelines && patientData.dietaryGuidelines.trim())
|
|
|
+})
|
|
|
+
|
|
|
+const isDietActive = (label: string) => {
|
|
|
+ const value = patientData.dietaryGuidelines
|
|
|
+ // 1. 如果是空值,直接返回 false
|
|
|
+ if (!value) return false
|
|
|
+
|
|
|
+ // 2. 如果是字符串(例如 '半流质'),直接做全等判断
|
|
|
+ if (typeof value === 'string') {
|
|
|
+ return value === label
|
|
|
+ }
|
|
|
+
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+// 风险等级文本
|
|
|
+const getRiskText = (value: string) => {
|
|
|
+ const map: Record<string, string> = {
|
|
|
+ high: '高风险',
|
|
|
+ medium: '中风险',
|
|
|
+ low: '低风险',
|
|
|
+ none: '无风险'
|
|
|
+ }
|
|
|
+ return map[value] || value || ''
|
|
|
+}
|
|
|
+
|
|
|
+// 根据风险等级获取九防图片地址
|
|
|
+const getPreventionImage = (field: string, level: string) => {
|
|
|
+ const levelMap: Record<string, string> = {
|
|
|
+ low: '01',
|
|
|
+ medium: '02',
|
|
|
+ high: '03'
|
|
|
+ }
|
|
|
+ const suffix = levelMap[level] || '01'
|
|
|
+ return new URL(`../../assets/jiufang/${field}-${suffix}.png`, import.meta.url).href
|
|
|
+}
|
|
|
+
|
|
|
// 患者数据
|
|
|
const patientData = reactive({
|
|
|
- roomName:'',
|
|
|
- bedName:'',
|
|
|
+ roomName: '',
|
|
|
+ bedName: '',
|
|
|
elderName: '',
|
|
|
elderSex: '',
|
|
|
birthday: '',
|
|
|
checkInTime: '',
|
|
|
careLevel: '',
|
|
|
carePoints: '',
|
|
|
- drugAllergyHistoryText: '',
|
|
|
- historyFoodAllergiesText: '',
|
|
|
- bloodTypeText: '',
|
|
|
+ allergiesText: '',
|
|
|
medicalHistory: '',
|
|
|
medicationHistory: '',
|
|
|
- diet: {
|
|
|
- normal: '',
|
|
|
- soft: '',
|
|
|
- semiLiquid: '',
|
|
|
- liquid: '',
|
|
|
- nasogastric: ''
|
|
|
- },
|
|
|
+ dietaryGuidelines: '',
|
|
|
responsibleStaff: {
|
|
|
nurseAide: '',
|
|
|
nurse: '',
|
|
|
doctor: ''
|
|
|
},
|
|
|
- qr:{
|
|
|
- eId:'',
|
|
|
- tId:''
|
|
|
+ asphyxiationByChoking: '',
|
|
|
+ pressureSores: '',
|
|
|
+ fallPreventionMeasures: '',
|
|
|
+ assessSimpleMentalState: '',
|
|
|
+ empyrosis: '',
|
|
|
+ fallDown: '',
|
|
|
+ wanderAway: '',
|
|
|
+ antiEntertainment: '',
|
|
|
+ commitSuicide: '',
|
|
|
+ qr: {
|
|
|
+ eId: '',
|
|
|
+ tId: ''
|
|
|
}
|
|
|
-});
|
|
|
+})
|
|
|
|
|
|
// 使用全局变量方式实现真正的全局单例管理
|
|
|
-// 检查全局window对象是否已经有了ZipManager实例
|
|
|
if (!(window as any).__GlobalZipManager) {
|
|
|
- // 定义全局单例管理器
|
|
|
- (window as any).__GlobalZipManager = {
|
|
|
+ ;(window as any).__GlobalZipManager = {
|
|
|
instance: null as JSZip | null,
|
|
|
count: 0,
|
|
|
|
|
|
- getZip: function(): JSZip {
|
|
|
+ getZip: function (): JSZip {
|
|
|
if (!this.instance) {
|
|
|
- this.instance = new JSZip();
|
|
|
- this.count = 0;
|
|
|
- console.log('创建了新的全局JSZip单例实例');
|
|
|
+ this.instance = new JSZip()
|
|
|
+ this.count = 0
|
|
|
+ console.log('创建了新的全局JSZip单例实例')
|
|
|
}
|
|
|
- return this.instance;
|
|
|
+ return this.instance
|
|
|
},
|
|
|
|
|
|
- incrementCount: function(): void {
|
|
|
- this.count++;
|
|
|
+ incrementCount: function (): void {
|
|
|
+ this.count++
|
|
|
},
|
|
|
|
|
|
- getCount: function(): number {
|
|
|
- return this.count;
|
|
|
+ getCount: function (): number {
|
|
|
+ return this.count
|
|
|
},
|
|
|
|
|
|
- reset: function(): void {
|
|
|
- this.instance = null;
|
|
|
- this.count = 0;
|
|
|
- console.log('已重置全局JSZip单例实例');
|
|
|
+ reset: function (): void {
|
|
|
+ this.instance = null
|
|
|
+ this.count = 0
|
|
|
+ console.log('已重置全局JSZip单例实例')
|
|
|
},
|
|
|
|
|
|
- // 获取当前文件列表
|
|
|
- getFileList: function(): string[] {
|
|
|
- if (!this.instance) return [];
|
|
|
- return Object.keys(this.instance.files);
|
|
|
+ getFileList: function (): string[] {
|
|
|
+ if (!this.instance) return []
|
|
|
+ return Object.keys(this.instance.files)
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// 获取全局单例管理器
|
|
|
-const GlobalZipManager = (window as any).__GlobalZipManager;
|
|
|
-
|
|
|
-// 使用ref记录已添加的文件数量(仅用于UI显示,如果需要)
|
|
|
-const fileCount = ref(0);
|
|
|
-
|
|
|
-
|
|
|
-onMounted(()=>{
|
|
|
+const GlobalZipManager = (window as any).__GlobalZipManager
|
|
|
+const fileCount = ref(0)
|
|
|
|
|
|
-
|
|
|
-})
|
|
|
+onMounted(() => {})
|
|
|
|
|
|
// 导出床头卡
|
|
|
const exportAsImage = async (type: number) => {
|
|
|
- try {
|
|
|
- // 获取要截图的元素
|
|
|
- const element = document.querySelector('.bed-card');
|
|
|
- if (!element) return;
|
|
|
-
|
|
|
- // 生成 canvas
|
|
|
- const canvas = await html2canvas(element as HTMLElement, {
|
|
|
- scale: 2, // 提高清晰度
|
|
|
- useCORS: true, // 支持跨域图片
|
|
|
- backgroundColor: '#ffffff',
|
|
|
- logging: false, // 关闭日志
|
|
|
- allowTaint: true, // 允许跨域图片
|
|
|
- foreignObjectRendering: false, // 禁用外部对象渲染,避免边框问题
|
|
|
- imageTimeout: 0, // 图片加载超时时间
|
|
|
- removeContainer: true, // 清理临时容器
|
|
|
- scrollX: 0,
|
|
|
- scrollY: 0,
|
|
|
- width: element.scrollWidth,
|
|
|
- height: element.scrollHeight
|
|
|
- });
|
|
|
-
|
|
|
- // 获取文件名
|
|
|
- const fileName = `${patientData.elderName}${patientData.bedName}床头卡.png`;
|
|
|
-
|
|
|
- // 将canvas转换为base64
|
|
|
- const imageBase64 = canvas.toDataURL('image/png', 1.0);
|
|
|
-
|
|
|
- // 提取base64数据部分(去除data:image/png;base64,前缀)
|
|
|
- const base64Data = imageBase64.split(',')[1];
|
|
|
-
|
|
|
- if (type === 2) {
|
|
|
- // 类型为2时,添加到临时zip文件
|
|
|
- const zipInstance = GlobalZipManager.getZip();
|
|
|
- zipInstance.file(fileName, base64Data, { base64: true });
|
|
|
- GlobalZipManager.incrementCount();
|
|
|
- fileCount.value = GlobalZipManager.getCount();
|
|
|
- // 获取并显示当前压缩包中的文件列表
|
|
|
- //const fileNames = GlobalZipManager.getFileList();
|
|
|
- // console.log(`已添加${fileName}到临时压缩包,当前共${GlobalZipManager.getCount()}个文件,文件列表:${fileNames.join(', ')}`);
|
|
|
- } else if (type === 3) {
|
|
|
- // 类型为3时,添加文件并下载压缩包
|
|
|
- // 即使只有一个文件(第一次调用就是type=3),也要正常工作
|
|
|
- const zipInstance = GlobalZipManager.getZip();
|
|
|
- zipInstance.file(fileName, base64Data, { base64: true });
|
|
|
- GlobalZipManager.incrementCount();
|
|
|
- fileCount.value = GlobalZipManager.getCount();
|
|
|
- // 获取并显示当前压缩包中的文件列表
|
|
|
- const fileNames = GlobalZipManager.getFileList();
|
|
|
- // console.log(`添加最后一个文件${fileName}到压缩包,压缩包中共有${fileNames.length}个文件,文件列表:${fileNames.join(', ')}`);
|
|
|
-
|
|
|
- // 生成压缩包
|
|
|
- const content = await zipInstance.generateAsync({ type: 'blob' });
|
|
|
- //console.log(`压缩包生成完成,大小:${(content.size / 1024).toFixed(2)}KB`);
|
|
|
-
|
|
|
- // 创建下载链接
|
|
|
- const link = document.createElement('a');
|
|
|
- link.href = URL.createObjectURL(content);
|
|
|
- link.download = `床头卡压缩包_${new Date().getTime()}.zip`;
|
|
|
- link.click();
|
|
|
-
|
|
|
- // 清理临时数据
|
|
|
- GlobalZipManager.reset();
|
|
|
- fileCount.value = 0;
|
|
|
-
|
|
|
- ElMessage.success(`床头卡压缩包导出成功,共包含${fileNames.length}个文件`);
|
|
|
+ try {
|
|
|
+ const element = document.querySelector('.bed-card')
|
|
|
+ if (!element) return
|
|
|
+
|
|
|
+ const canvas = await html2canvas(element as HTMLElement, {
|
|
|
+ scale: 2,
|
|
|
+ useCORS: true,
|
|
|
+ backgroundColor: '#ffffff',
|
|
|
+ logging: false,
|
|
|
+ allowTaint: true,
|
|
|
+ foreignObjectRendering: false,
|
|
|
+ imageTimeout: 0,
|
|
|
+ removeContainer: true,
|
|
|
+ scrollX: 0,
|
|
|
+ scrollY: 0,
|
|
|
+ width: element.scrollWidth,
|
|
|
+ height: element.scrollHeight
|
|
|
+ })
|
|
|
+
|
|
|
+ const fileName = `${patientData.elderName}${patientData.bedName}床头卡.png`
|
|
|
+ const imageBase64 = canvas.toDataURL('image/png', 1.0)
|
|
|
+ const base64Data = imageBase64.split(',')[1]
|
|
|
+
|
|
|
+ if (type === 2) {
|
|
|
+ const zipInstance = GlobalZipManager.getZip()
|
|
|
+ zipInstance.file(fileName, base64Data, { base64: true })
|
|
|
+ GlobalZipManager.incrementCount()
|
|
|
+ fileCount.value = GlobalZipManager.getCount()
|
|
|
+ } else if (type === 3) {
|
|
|
+ const zipInstance = GlobalZipManager.getZip()
|
|
|
+ zipInstance.file(fileName, base64Data, { base64: true })
|
|
|
+ GlobalZipManager.incrementCount()
|
|
|
+ fileCount.value = GlobalZipManager.getCount()
|
|
|
+ const fileNames = GlobalZipManager.getFileList()
|
|
|
+ const content = await zipInstance.generateAsync({ type: 'blob' })
|
|
|
+ const link = document.createElement('a')
|
|
|
+ link.href = URL.createObjectURL(content)
|
|
|
+ link.download = `床头卡压缩包_${new Date().getTime()}.zip`
|
|
|
+ link.click()
|
|
|
+ GlobalZipManager.reset()
|
|
|
+ fileCount.value = 0
|
|
|
+ ElMessage.success(`床头卡压缩包导出成功,共包含${fileNames.length}个文件`)
|
|
|
} else {
|
|
|
- // 其他类型,直接下载单个文件
|
|
|
- const link = document.createElement('a');
|
|
|
- link.href = imageBase64;
|
|
|
- link.download = fileName;
|
|
|
- link.click();
|
|
|
-
|
|
|
- ElMessage.success('床头卡导出成功');
|
|
|
+ const link = document.createElement('a')
|
|
|
+ link.href = imageBase64
|
|
|
+ link.download = fileName
|
|
|
+ link.click()
|
|
|
+ ElMessage.success('床头卡导出成功')
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- console.error('导出失败:', error);
|
|
|
- ElMessage.error('导出失败,请稍后重试');
|
|
|
- // 出错时清理临时数据
|
|
|
- if (type === 2 || type === 3) {
|
|
|
- GlobalZipManager.reset();
|
|
|
- fileCount.value = 0;
|
|
|
- }
|
|
|
+ console.error('导出失败:', error)
|
|
|
+ ElMessage.error('导出失败,请稍后重试')
|
|
|
+ if (type === 2 || type === 3) {
|
|
|
+ GlobalZipManager.reset()
|
|
|
+ fileCount.value = 0
|
|
|
+ }
|
|
|
}
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
// 更新患者数据的方法
|
|
|
const updatePatientData = (data: any) => {
|
|
|
- qrCodeContent.value = 'https://callback.ynims.com/qrcode/elderlyId?=' + data.qr?.eId + '&tenantId=' + data.qr?.tId
|
|
|
- Object.assign(patientData, data);
|
|
|
+ qrCodeContent.value =
|
|
|
+ 'https://callback.ynims.com/qrcode/elderlyId?=' + data.qr?.eId + '&tenantId=' + data.qr?.tId
|
|
|
+ Object.assign(patientData, data)
|
|
|
}
|
|
|
|
|
|
// 重置临时zip数据
|
|
|
const resetTempZip = () => {
|
|
|
- GlobalZipManager.reset();
|
|
|
- fileCount.value = 0;
|
|
|
- console.log('已重置临时zip数据');
|
|
|
-};
|
|
|
-
|
|
|
+ GlobalZipManager.reset()
|
|
|
+ fileCount.value = 0
|
|
|
+ console.log('已重置临时zip数据')
|
|
|
+}
|
|
|
|
|
|
// 暴露方法给父组件
|
|
|
defineExpose({
|
|
|
updatePatientData,
|
|
|
exportAsImage,
|
|
|
resetTempZip
|
|
|
-});
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
@@ -355,11 +381,11 @@ defineExpose({
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
- padding: 20px;
|
|
|
+ padding: 12px;
|
|
|
}
|
|
|
|
|
|
.bed-card {
|
|
|
- min-width: 850px;
|
|
|
+ min-width: 900px;
|
|
|
background-color: white;
|
|
|
border: 1px solid #e0e0e0;
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
@@ -368,9 +394,9 @@ defineExpose({
|
|
|
}
|
|
|
|
|
|
.card-header {
|
|
|
- background-color: #4CAF50;
|
|
|
+ background-color: #e78d35;
|
|
|
color: white;
|
|
|
- padding: 15px 20px;
|
|
|
+ padding: 8px 20px;
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
|
@@ -380,32 +406,50 @@ defineExpose({
|
|
|
margin: 0;
|
|
|
font-size: 20px;
|
|
|
font-weight: bold;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.header-room {
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: bold;
|
|
|
+ text-align: center;
|
|
|
+ flex: 1;
|
|
|
}
|
|
|
|
|
|
.header-logo {
|
|
|
- height: 30px;
|
|
|
+ height: 60px;
|
|
|
+ flex: 1;
|
|
|
+ text-align: right;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+.card-main {
|
|
|
+ display: flex;
|
|
|
+ min-height: 480px;
|
|
|
}
|
|
|
|
|
|
.left-section {
|
|
|
- width: 200px;
|
|
|
- float: left;
|
|
|
- padding: 10px 6px;
|
|
|
+ width: 150px;
|
|
|
+ padding: 20px 10px;
|
|
|
text-align: center;
|
|
|
border-right: 1px solid #e0e0e0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
|
|
|
.room-number {
|
|
|
font-size: 60px;
|
|
|
font-weight: bold;
|
|
|
- color: #FF6B00;
|
|
|
+ color: #ff6b00;
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
.bed-info {
|
|
|
font-size: 36px;
|
|
|
font-weight: bold;
|
|
|
- color: #FF6B00;
|
|
|
- margin-bottom: 10px;
|
|
|
+ color: #ff6b00;
|
|
|
+ margin-bottom: 20px;
|
|
|
}
|
|
|
|
|
|
.bed-letter {
|
|
|
@@ -416,70 +460,49 @@ defineExpose({
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
|
|
|
-.qrcode {
|
|
|
- width: 100px;
|
|
|
- height: 100px;
|
|
|
- border: 1px solid #e0e0e0;
|
|
|
-}
|
|
|
-
|
|
|
.qrcode-text {
|
|
|
- margin-top: 2px;
|
|
|
+ margin-top: 8px;
|
|
|
font-size: 14px;
|
|
|
color: #666;
|
|
|
}
|
|
|
|
|
|
.right-section {
|
|
|
- overflow: hidden;
|
|
|
- padding: 20px;
|
|
|
+ flex: 1;
|
|
|
+ padding: 0;
|
|
|
}
|
|
|
|
|
|
.info-table {
|
|
|
width: 100%;
|
|
|
- border-collapse: separate;
|
|
|
+ border-collapse: collapse;
|
|
|
font-size: 14px;
|
|
|
- border-spacing: 0;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
.info-table td {
|
|
|
- border-right: 1px solid #000;
|
|
|
- border-bottom: 1px solid #000;
|
|
|
+ border: 1px solid #999;
|
|
|
padding: 10px;
|
|
|
text-align: center;
|
|
|
-}
|
|
|
-
|
|
|
-.info-table .no-right-border {
|
|
|
- border-right: none;
|
|
|
-}
|
|
|
-
|
|
|
-.info-table .no-bottom-border {
|
|
|
- border-bottom: none;
|
|
|
+ vertical-align: middle;
|
|
|
}
|
|
|
|
|
|
.table-label {
|
|
|
font-weight: bold;
|
|
|
background-color: #f5f5f5;
|
|
|
- text-align: right;
|
|
|
+ width: 80px;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.table-data {
|
|
|
text-align: left;
|
|
|
+ color: #333;
|
|
|
}
|
|
|
|
|
|
-.section-title {
|
|
|
- background-color: #e8e8e8;
|
|
|
- font-weight: bold;
|
|
|
- font-size: 16px;
|
|
|
- text-align: center;
|
|
|
+.diet-cell {
|
|
|
+ padding: 0 !important;
|
|
|
}
|
|
|
|
|
|
-.diet-type {
|
|
|
- background-color: #f0f0f0;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
-.diet-container {
|
|
|
+.diet-list {
|
|
|
display: flex;
|
|
|
- width: 100%;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
@@ -489,76 +512,170 @@ defineExpose({
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
padding: 10px;
|
|
|
+ border-right: 1px solid #999;
|
|
|
position: relative;
|
|
|
+ min-height: 44px;
|
|
|
}
|
|
|
|
|
|
-.diet-item:not(:last-child)::after {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- right: 0;
|
|
|
- top: 0;
|
|
|
- height: 100%;
|
|
|
- width: 1px;
|
|
|
- background-color: #000;
|
|
|
+.diet-item:last-child {
|
|
|
+ border-right: none;
|
|
|
+}
|
|
|
+
|
|
|
+.diet-item.active {
|
|
|
+ background-color: #ffffff;
|
|
|
+ color: #ff6b00;
|
|
|
+}
|
|
|
+
|
|
|
+.diet-name {
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.diet-check {
|
|
|
+ margin-right: 6px;
|
|
|
+ color: #e78d35;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 16px;
|
|
|
}
|
|
|
|
|
|
-.staff-container {
|
|
|
+.diet-empty {
|
|
|
+ padding: 10px;
|
|
|
+ color: #999;
|
|
|
+ text-align: left;
|
|
|
+ min-height: 44px;
|
|
|
display: flex;
|
|
|
- width: 100%;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.prevention-title {
|
|
|
+ width: 40px;
|
|
|
+ padding: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.vertical-text {
|
|
|
+ writing-mode: vertical-rl;
|
|
|
+ text-orientation: upright;
|
|
|
+ letter-spacing: 4px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin: 0 auto;
|
|
|
+}
|
|
|
+
|
|
|
+.prevention-cell {
|
|
|
+ padding: 0 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.prevention-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(5, 1fr);
|
|
|
+ grid-template-rows: repeat(2, 1fr);
|
|
|
height: 100%;
|
|
|
+ min-height: 180px;
|
|
|
}
|
|
|
|
|
|
-.staff-label {
|
|
|
- flex: 1;
|
|
|
+.prevention-item {
|
|
|
+ border-right: 1px solid #999;
|
|
|
+ border-bottom: 1px solid #999;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- padding: 8px;
|
|
|
- font-weight: bold;
|
|
|
- background-color: #f5f5f5;
|
|
|
+ padding: 6px;
|
|
|
position: relative;
|
|
|
}
|
|
|
|
|
|
-.staff-label:not(:last-child)::after {
|
|
|
- content: '';
|
|
|
+.prevention-item:nth-child(9) {
|
|
|
+ border-right: none;
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.prevention-item:nth-child(n + 6):nth-child(-n + 8) {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.prevention-pos-1 {
|
|
|
+ grid-column: 1;
|
|
|
+ grid-row: 1;
|
|
|
+}
|
|
|
+.prevention-pos-2 {
|
|
|
+ grid-column: 2;
|
|
|
+ grid-row: 1;
|
|
|
+}
|
|
|
+.prevention-pos-3 {
|
|
|
+ grid-column: 3;
|
|
|
+ grid-row: 1;
|
|
|
+}
|
|
|
+.prevention-pos-4 {
|
|
|
+ grid-column: 4;
|
|
|
+ grid-row: 1;
|
|
|
+}
|
|
|
+.prevention-pos-5 {
|
|
|
+ grid-column: 1;
|
|
|
+ grid-row: 2;
|
|
|
+}
|
|
|
+.prevention-pos-6 {
|
|
|
+ grid-column: 2;
|
|
|
+ grid-row: 2;
|
|
|
+}
|
|
|
+.prevention-pos-7 {
|
|
|
+ grid-column: 3;
|
|
|
+ grid-row: 2;
|
|
|
+}
|
|
|
+.prevention-pos-8 {
|
|
|
+ grid-column: 4;
|
|
|
+ grid-row: 2;
|
|
|
+}
|
|
|
+.prevention-pos-9 {
|
|
|
+ grid-column: 5;
|
|
|
+ grid-row: 1 / 3;
|
|
|
+ background-color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.risk-badge {
|
|
|
position: absolute;
|
|
|
- right: 0;
|
|
|
- top: 0;
|
|
|
- height: 100%;
|
|
|
- width: 1px;
|
|
|
- background-color: #000;
|
|
|
+ top: 4px;
|
|
|
+ left: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 11px;
|
|
|
+ color: #e78d35;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.risk-star {
|
|
|
+ margin-right: 2px;
|
|
|
}
|
|
|
|
|
|
-.staff-value {
|
|
|
- flex: 2;
|
|
|
+.placeholder-image {
|
|
|
+ width: 90px;
|
|
|
+ object-fit: contain;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- padding: 8px;
|
|
|
- position: relative;
|
|
|
}
|
|
|
|
|
|
-.staff-value:not(:last-child)::after {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- right: 0;
|
|
|
- top: 0;
|
|
|
- height: 100%;
|
|
|
- width: 1px;
|
|
|
- background-color: #000;
|
|
|
+.placeholder-image span {
|
|
|
+ font-size: 11px;
|
|
|
+ color: #999;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.prevention-name {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #333;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 1.2;
|
|
|
}
|
|
|
|
|
|
.card-footer {
|
|
|
- height: 30px;
|
|
|
- background: linear-gradient(45deg, #FF6B00 0%, #4CAF50 100%);
|
|
|
+ height: 8px;
|
|
|
+ background: linear-gradient(90deg, #e78d35 0%, #4caf50 100%);
|
|
|
clear: both;
|
|
|
}
|
|
|
|
|
|
.export-btn {
|
|
|
margin-top: 20px;
|
|
|
padding: 10px 30px;
|
|
|
- background-color: #4CAF50;
|
|
|
+ background-color: #4caf50;
|
|
|
color: white;
|
|
|
border: none;
|
|
|
border-radius: 4px;
|