| | |
| | | <div class="col row1-col2"> |
| | | <Card |
| | | title="治疗模式" |
| | | :icon="zlmsImg" |
| | | :icon="tslImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row1-col2-row1" |
| | | header-class-name="mihi-header" |
| | |
| | | <div class="col row1-col3"> |
| | | <Card |
| | | title="置换总量" |
| | | :icon="zlmsImg" |
| | | :icon="zlztImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row1-col3-row1" |
| | | header-class-name="mihi-header" |
| | |
| | | </Card> |
| | | <Card |
| | | title="透析时长" |
| | | :icon="zlmsImg" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row1-col3-row2" |
| | | header-class-name="mihi-header" |
| | |
| | | <div class="col row1-col4"> |
| | | <Card |
| | | title="透析器" |
| | | :icon="zlmsImg" |
| | | :icon="txqImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row1-col4-row1" |
| | | header-class-name="mihi-header" |
| | |
| | | </Card> |
| | | <Card |
| | | title="抗凝剂" |
| | | :icon="zlmsImg" |
| | | :icon="tslImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row1-col4-row2" |
| | | header-class-name="mihi-header" |
| | |
| | | </Card> |
| | | <Card |
| | | title="处方备注" |
| | | :icon="zlmsImg" |
| | | :icon="maibo2Img" |
| | | background-color="#ffffff" |
| | | class="mini-card row1-col5-row2" |
| | | header-class-name="mihi-header" |
| | |
| | | <div class="row2-col1-row1"> |
| | | <Card |
| | | title="处方血流量" |
| | | :icon="zlmsImg" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row2-col1-row1-col1" |
| | | header-class-name="mihi-header" |
| | |
| | | </Card> |
| | | <Card |
| | | title="处方钠" |
| | | :icon="zlmsImg" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row2-col1-row1-col2" |
| | | header-class-name="mihi-header" |
| | |
| | | <div class="row2-col1-row2"> |
| | | <Card |
| | | title="透析液流量" |
| | | :icon="zlmsImg" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row2-col1-row2-col1" |
| | | header-class-name="mihi-header" |
| | |
| | | </Card> |
| | | <Card |
| | | title="透析液种类" |
| | | :icon="zlmsImg" |
| | | :icon="cljdImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row2-col1-row2-col2" |
| | | header-class-name="mihi-header" |
| | |
| | | </div> |
| | | <Card |
| | | title="治疗状态" |
| | | :icon="zlmsImg" |
| | | :icon="zlztImg" |
| | | background-color="#ffffff" |
| | | class="mini-card row2-col1-row3" |
| | | header-class-name="mihi-header" |
| | |
| | | <div class="col row2-col2"> |
| | | <Card |
| | | title="参考指标" |
| | | :icon="zlmsImg" |
| | | :icon="tizhongImg" |
| | | background-color="#ffffff" |
| | | class="reference-indicators" |
| | | header-class-name="mihi-header" |
| | |
| | | class="btn" |
| | | /> |
| | | </div> |
| | | <!-- 定时任务 --> |
| | | <ScheduledTaskDialog ref="scheduledTaskDialogRef" /> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup name="SignedIn"> |
| | | import { computed, onMounted, ref } from "vue"; |
| | | import { computed, defineAsyncComponent, onMounted, ref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import "dayjs/locale/zh-cn"; |
| | | dayjs.locale("zh-cn"); |
| | |
| | | import txqImg from "@/img/txq.png"; |
| | | import tizhongImg from "@/img/tizhong.png"; |
| | | import yizhuImg from "@/img/yizhu.png"; |
| | | import maibo2Img from "@/img/maibo2.png"; |
| | | |
| | | import { |
| | | getItemName, |
| | |
| | | } from "@/store/type/bedsideAuxiliaryScreen.type"; |
| | | // @ts-ignore |
| | | import BlockBotttom from "../components/BlockBotttom.vue"; |
| | | import { ElMessage } from "element-plus/es"; |
| | | import { ElMessage } from "element-plus"; |
| | | const ScheduledTaskDialog = defineAsyncComponent( |
| | | () => import("../components/ScheduledTask.vue") |
| | | ); |
| | | |
| | | interface Props { |
| | | height: number; |
| | |
| | | const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore(); |
| | | |
| | | const bloodPressureRectangularChart = ref<HTMLElement | null>(null); |
| | | const scheduledTaskDialogRef = ref<any>(null); |
| | | |
| | | |
| | | const pageData = computed(() => { |
| | | return Object.assign(bedsideAuxiliaryScreenStore.deviceData.signedIn, { |
| | |
| | | }); |
| | | |
| | | /** 点击定时任务 */ |
| | | const onScheduledTasksClick = () => {}; |
| | | const onScheduledTasksClick = () => { |
| | | if ( |
| | | !bedsideAuxiliaryScreenStore.deviceCode || |
| | | !bedsideAuxiliaryScreenStore.deviceData.deviceCode |
| | | ) |
| | | return ElMessage.warning("未初始化或正在进行初始化操作中"); |
| | | scheduledTaskDialogRef.value?.openDialog(); |
| | | }; |
| | | |
| | | const onCallBumberClick = () => { |
| | | ElMessage({ |
| | |
| | | type: "warning", |
| | | }); |
| | | }; |
| | | const genderBloodPressureRectangularChart = ( |
| | | datas: 四点血压图数据[] | null |
| | | ) => { |
| | | if (bloodPressureRectangularChart.value) { |
| | | const benchmarkData = { |
| | | width: 386, |
| | | height: 280, |
| | | }; |
| | | // 获取容器实际宽高 |
| | | const containerWidth = bloodPressureRectangularChart.value.offsetWidth * 0.9; |
| | | const containerHeight = bloodPressureRectangularChart.value.offsetHeight * 0.9; |
| | | // 等比例缩放因子 |
| | | const scale = Math.min( |
| | | containerWidth / benchmarkData.width, |
| | | containerHeight / benchmarkData.height |
| | | ); |
| | | |
| | | // 拿到 canvas |
| | | let canvas = bloodPressureRectangularChart.value.querySelector("canvas"); |
| | | if (!canvas) { |
| | | canvas = document.createElement("canvas"); |
| | | bloodPressureRectangularChart.value.appendChild(canvas); |
| | | } |
| | | const genderBloodPressureRectangularChart = (datas: 四点血压图数据[] | null) => { |
| | | if (!bloodPressureRectangularChart.value) return; |
| | | |
| | | // 设置 canvas 尺寸 |
| | | canvas.width = containerWidth; |
| | | canvas.height = containerHeight; |
| | | canvas.style.width = `${canvas.width}px`; |
| | | canvas.style.height = `${canvas.height}px`; |
| | | const benchmarkData = { width: 386, height: 280 }; |
| | | |
| | | const ctx = canvas.getContext("2d"); |
| | | if (!ctx) return; |
| | | // 获取容器宽高(90% 缩放) |
| | | const containerWidth = bloodPressureRectangularChart.value.offsetWidth * 0.9; |
| | | const containerHeight = bloodPressureRectangularChart.value.offsetHeight * 0.9; |
| | | |
| | | // 清除画布 |
| | | ctx.clearRect(0, 0, canvas.width, canvas.height); |
| | | // 获取设备像素比 |
| | | const dpr = window.devicePixelRatio || 1; |
| | | |
| | | // 按缩放因子缩放绘制环境 |
| | | ctx.save(); |
| | | // ctx.scale(scale, scale); |
| | | // 等比例缩放因子(保持比例) |
| | | const scale = Math.min( |
| | | containerWidth / benchmarkData.width, |
| | | containerHeight / benchmarkData.height |
| | | ); |
| | | |
| | | // 设置字体样式 |
| | | ctx.font = `12px Arial`; |
| | | ctx.textAlign = "center"; |
| | | // 计算实际画布 CSS 尺寸 |
| | | const cssWidth = benchmarkData.width * scale; |
| | | const cssHeight = benchmarkData.height * scale; |
| | | |
| | | // 处理数据 |
| | | const measurements = [ |
| | | { systolic: 143, diastolic: 74 }, |
| | | { systolic: 136, diastolic: 71 }, |
| | | { systolic: 139, diastolic: 73 }, |
| | | { systolic: 139, diastolic: 73 }, |
| | | ]; |
| | | |
| | | measurements[0].systolic = datas[0]?.血压1_透前收缩压 ?? null; |
| | | measurements[0].diastolic = datas[0]?.血压1_透前舒张压 ?? null; |
| | | measurements[1].systolic = datas[0]?.血压2_前半程最低收缩压 ?? null; |
| | | measurements[1].diastolic = datas[0]?.血压2_前半程最低舒张压 ?? null; |
| | | measurements[2].systolic = datas[0]?.血压3_后半程最低收缩压 ?? null; |
| | | measurements[2].diastolic = datas[0]?.血压3_后半程最低舒张压 ?? null; |
| | | measurements[3].systolic = datas[0]?.血压4_透后收缩压 ?? null; |
| | | measurements[3].diastolic = datas[0]?.血压4_透后舒张压 ?? null; |
| | | |
| | | const chartHeight = canvas.height; |
| | | const chartWidth = canvas.width; |
| | | |
| | | // 限所在位置 200 |
| | | const upperLimitY = chartHeight * 0.5; |
| | | ctx.beginPath(); |
| | | ctx.moveTo(0, upperLimitY); |
| | | ctx.lineTo(chartWidth, upperLimitY); |
| | | ctx.strokeStyle = "red"; |
| | | ctx.lineWidth = 1; |
| | | ctx.stroke(); |
| | | |
| | | // 下限所在位置 140 |
| | | const lowerLimitY = chartHeight * (1 - 0.2857); |
| | | console.log("lowerLimitY:", lowerLimitY); |
| | | ctx.beginPath(); |
| | | ctx.moveTo(0, lowerLimitY); |
| | | ctx.lineTo(chartWidth, lowerLimitY); |
| | | ctx.strokeStyle = "blue"; |
| | | ctx.lineWidth = 1; |
| | | ctx.stroke(); |
| | | |
| | | // 绘制收缩压折线图 |
| | | const measurementWidth = canvas.width / (measurements.length + 1); |
| | | |
| | | // 收缩压线 |
| | | let systolicEnd = { x: null, y: null }; |
| | | ctx.beginPath(); |
| | | ctx.moveTo( |
| | | measurementWidth, |
| | | chartHeight - measurements[0].systolic * scale |
| | | ); |
| | | for (let i = 1; i < measurements.length; i++) { |
| | | const x = (i + 1) * measurementWidth; |
| | | ctx.lineTo(x, chartHeight - measurements[i].systolic * scale); |
| | | if (i === measurements.length - 1) { |
| | | systolicEnd.x = x; |
| | | systolicEnd.y = chartHeight - measurements[i].systolic * scale; |
| | | } |
| | | } |
| | | ctx.strokeStyle = "black"; |
| | | ctx.lineWidth = 1; |
| | | ctx.stroke(); |
| | | |
| | | // 舒张压线 |
| | | let diastolicEnd = { x: null, y: null }; |
| | | ctx.beginPath(); |
| | | ctx.moveTo( |
| | | measurementWidth, |
| | | chartHeight - measurements[0].diastolic * scale |
| | | ); |
| | | for (let i = 1; i < measurements.length; i++) { |
| | | const x = (i + 1) * measurementWidth; |
| | | ctx.lineTo(x, chartHeight - measurements[i].diastolic * scale); |
| | | if (i === measurements.length - 1) { |
| | | diastolicEnd.x = x; |
| | | diastolicEnd.y = chartHeight - measurements[i].diastolic * scale; |
| | | } |
| | | } |
| | | |
| | | // 连接收缩压和舒张压的起始点和结束点 |
| | | ctx.moveTo( |
| | | measurementWidth, |
| | | chartHeight - measurements[0].systolic * scale |
| | | ); |
| | | ctx.lineTo( |
| | | measurementWidth, |
| | | chartHeight - measurements[0].diastolic * scale |
| | | ); |
| | | ctx.moveTo(systolicEnd.x, systolicEnd.y); |
| | | ctx.lineTo(diastolicEnd.x, diastolicEnd.y); |
| | | |
| | | ctx.strokeStyle = "black"; |
| | | ctx.lineWidth = 1; |
| | | ctx.stroke(); |
| | | |
| | | const baseFontSize = 24; |
| | | ctx.font = `${baseFontSize * scale}px Arial`; |
| | | ctx.textAlign = "center"; |
| | | ctx.textBaseline = "middle"; |
| | | ctx.fillStyle = "black"; |
| | | |
| | | measurements.forEach((m, i) => { |
| | | const x = (i + 1) * measurementWidth; |
| | | ctx.fillText( |
| | | m.systolic.toString(), |
| | | x, |
| | | chartHeight - m.systolic * scale - 5 |
| | | ); |
| | | ctx.fillText( |
| | | m.diastolic.toString(), |
| | | x, |
| | | chartHeight - m.diastolic * scale + 10 |
| | | ); |
| | | }); |
| | | |
| | | // 绘制圆柱体 |
| | | const 计算脱水量刻度 = 100 / datas[0]?.超滤总量; |
| | | const cylinderX = canvas.width * 0.9; // 圆柱体中心X坐标 |
| | | const cylinderY = canvas.height; // 圆柱体中心Y坐标 |
| | | const cylinderRadius = 6 * scale; // 圆柱体半径 |
| | | const cylinderHeight = 计算脱水量刻度 * datas[0]?.超滤总量 * scale || 0; // 圆柱体高度 |
| | | const 超滤总量 = datas[0]?.超滤总量 + "" || "0 L"; // 超滤总量 |
| | | const 脱水百分比 = datas[0]?.脱水百分比 || 0; // 脱水百分比 |
| | | const 透后体重减干体重的差值 = datas[0]?.透后体重减干体重的差值 || 0; // 透后体重减干体重的差值 |
| | | drawCylinder( |
| | | ctx, |
| | | canvas.height, |
| | | scale, |
| | | cylinderX, |
| | | cylinderY, |
| | | cylinderRadius, |
| | | cylinderHeight, |
| | | 超滤总量, |
| | | 脱水百分比, |
| | | 透后体重减干体重的差值 |
| | | ); |
| | | // 获取 canvas |
| | | let canvas = bloodPressureRectangularChart.value.querySelector("canvas"); |
| | | if (!canvas) { |
| | | canvas = document.createElement("canvas"); |
| | | bloodPressureRectangularChart.value.appendChild(canvas); |
| | | } |
| | | |
| | | // 物理像素 |
| | | canvas.width = cssWidth * dpr; |
| | | canvas.height = cssHeight * dpr; |
| | | canvas.style.width = `${cssWidth}px`; |
| | | canvas.style.height = `${cssHeight}px`; |
| | | |
| | | const ctx = canvas.getContext("2d"); |
| | | if (!ctx) return; |
| | | |
| | | // 先清除画布(按物理像素) |
| | | ctx.clearRect(0, 0, canvas.width, canvas.height); |
| | | |
| | | // 缩放到实际坐标系(dpr & scale) |
| | | ctx.save(); |
| | | ctx.scale(dpr * scale, dpr * scale); |
| | | |
| | | // 基准坐标系:benchmarkData.width × benchmarkData.height |
| | | const chartWidth = benchmarkData.width; |
| | | const chartHeight = benchmarkData.height; |
| | | |
| | | // ========== 绘制基线 ========== |
| | | const upperLimitY = chartHeight * 0.5; // 200 |
| | | ctx.beginPath(); |
| | | ctx.moveTo(0, upperLimitY); |
| | | ctx.lineTo(chartWidth, upperLimitY); |
| | | ctx.strokeStyle = "red"; |
| | | ctx.lineWidth = 1; |
| | | ctx.stroke(); |
| | | |
| | | const lowerLimitY = chartHeight * (1 - 0.2857); // 140 |
| | | ctx.beginPath(); |
| | | ctx.moveTo(0, lowerLimitY); |
| | | ctx.lineTo(chartWidth, lowerLimitY); |
| | | ctx.strokeStyle = "blue"; |
| | | ctx.lineWidth = 1; |
| | | ctx.stroke(); |
| | | |
| | | // ========== 血压数据 ========== |
| | | const measurements = [ |
| | | { systolic: datas?.[0]?.血压1_透前收缩压 ?? 0, diastolic: datas?.[0]?.血压1_透前舒张压 ?? 0 }, |
| | | { systolic: datas?.[0]?.血压2_前半程最低收缩压 ?? 0, diastolic: datas?.[0]?.血压2_前半程最低舒张压 ?? 0 }, |
| | | { systolic: datas?.[0]?.血压3_后半程最低收缩压 ?? 0, diastolic: datas?.[0]?.血压3_后半程最低舒张压 ?? 0 }, |
| | | { systolic: datas?.[0]?.血压4_透后收缩压 ?? 0, diastolic: datas?.[0]?.血压4_透后舒张压 ?? 0 }, |
| | | ]; |
| | | |
| | | const measurementWidth = chartWidth / (measurements.length + 1); |
| | | |
| | | // 收缩压线 |
| | | let systolicEnd = { x: 0, y: 0 }; |
| | | ctx.beginPath(); |
| | | ctx.moveTo(measurementWidth, chartHeight - measurements[0].systolic); |
| | | for (let i = 1; i < measurements.length; i++) { |
| | | const x = (i + 1) * measurementWidth; |
| | | ctx.lineTo(x, chartHeight - measurements[i].systolic); |
| | | if (i === measurements.length - 1) { |
| | | systolicEnd = { x, y: chartHeight - measurements[i].systolic }; |
| | | } |
| | | } |
| | | ctx.strokeStyle = "black"; |
| | | ctx.stroke(); |
| | | |
| | | // 舒张压线 |
| | | let diastolicEnd = { x: 0, y: 0 }; |
| | | ctx.beginPath(); |
| | | ctx.moveTo(measurementWidth, chartHeight - measurements[0].diastolic); |
| | | for (let i = 1; i < measurements.length; i++) { |
| | | const x = (i + 1) * measurementWidth; |
| | | ctx.lineTo(x, chartHeight - measurements[i].diastolic); |
| | | if (i === measurements.length - 1) { |
| | | diastolicEnd = { x, y: chartHeight - measurements[i].diastolic }; |
| | | } |
| | | } |
| | | ctx.strokeStyle = "black"; |
| | | ctx.stroke(); |
| | | |
| | | // 连接起始 & 结束 |
| | | ctx.beginPath(); |
| | | ctx.moveTo(measurementWidth, chartHeight - measurements[0].systolic); |
| | | ctx.lineTo(measurementWidth, chartHeight - measurements[0].diastolic); |
| | | ctx.moveTo(systolicEnd.x, systolicEnd.y); |
| | | ctx.lineTo(diastolicEnd.x, diastolicEnd.y); |
| | | ctx.stroke(); |
| | | |
| | | // ========== 文本 ========== |
| | | const baseFontSize = 24; |
| | | ctx.font = `${baseFontSize}px Arial`; |
| | | ctx.textAlign = "center"; |
| | | ctx.textBaseline = "middle"; |
| | | ctx.fillStyle = "black"; |
| | | |
| | | measurements.forEach((m, i) => { |
| | | const x = (i + 1) * measurementWidth; |
| | | ctx.fillText(m.systolic.toString(), x, chartHeight - m.systolic - 5); |
| | | ctx.fillText(m.diastolic.toString(), x, chartHeight - m.diastolic + 10); |
| | | }); |
| | | |
| | | // ========== 圆柱体 ========== |
| | | const 计算脱水量刻度 = 100 / (datas?.[0]?.超滤总量 || 1); |
| | | const cylinderX = chartWidth * 0.9; |
| | | const cylinderY = chartHeight; |
| | | const cylinderRadius = 6; |
| | | const cylinderHeight = 计算脱水量刻度 * (datas?.[0]?.超滤总量 || 0); |
| | | |
| | | drawCylinder( |
| | | ctx, |
| | | chartHeight, |
| | | 1, // 因为已经 scale 过了 |
| | | cylinderX, |
| | | cylinderY, |
| | | cylinderRadius, |
| | | cylinderHeight, |
| | | datas?.[0]?.超滤总量?.toString() ?? "0 L", |
| | | datas?.[0]?.脱水百分比 ?? 0, |
| | | datas?.[0]?.透后体重减干体重的差值 ?? 0 |
| | | ); |
| | | |
| | | ctx.restore(); // 恢复 |
| | | }; |
| | | |
| | | |
| | | |
| | | const drawCylinder = ( |
| | | ctx: CanvasRenderingContext2D, |
| | |
| | | .dialyzer { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 600; |
| | | font-size: 11px; |
| | | font-size: 9px; |
| | | color: #333333; |
| | | text-align: center; |
| | | font-style: normal; |
| | |
| | | } |
| | | .item-box { |
| | | height: 100%; |
| | | overflow-y: auto !important; |
| | | } |
| | | :deep(.mini-header) { |
| | | flex: 0 0 4px !important; |