From b7b79d84b269641a4a8134249f6b5ec33ae6218f Mon Sep 17 00:00:00 2001
From: zhangchen <1652267879@qq.com>
Date: 星期六, 26 七月 2025 14:15:03 +0800
Subject: [PATCH] Merge branch 'ID1825-床旁副屏改版' into test
---
src/views/mobile/bedsideAuxiliaryScreen/components/TaskAlart.vue | 184 +++++++++++++
src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue | 194 +++++++++----
src/store/type/bedsideAuxiliaryScreen.type.ts | 5
src/store/type/task.type.ts | 59 ++++
src/utils/httpApi.ts | 20 +
src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue | 257 +++++++++++++-----
src/store/bedsideAuxiliaryScreen.ts | 9
src/views/mobile/bedsideAuxiliaryScreen/pages/SignedIn.vue | 2
src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue | 4
src/composables/useAudioPlayer.ts | 66 ++++
10 files changed, 663 insertions(+), 137 deletions(-)
diff --git a/src/composables/useAudioPlayer.ts b/src/composables/useAudioPlayer.ts
new file mode 100644
index 0000000..341dfbc
--- /dev/null
+++ b/src/composables/useAudioPlayer.ts
@@ -0,0 +1,66 @@
+import { ref, watch } from "vue";
+
+let currentAudio: HTMLAudioElement | null = null;
+
+export function useAudioPlayer() {
+ const source = ref<string | null>(null);
+ const isPlaying = ref(false);
+
+ // 播放音频
+ const play = (src: string) => {
+ if (!src) return;
+
+ // 如果当前正在播放其他音频,先暂停并释放
+ if (currentAudio) {
+ currentAudio.pause();
+ currentAudio = null;
+ isPlaying.value = false;
+ }
+
+ currentAudio = new Audio(src);
+ currentAudio.loop = true; // 循环播放
+ currentAudio.volume = 1.0; // 音量最大
+ currentAudio
+ .play()
+ .then(() => {
+ isPlaying.value = true;
+ })
+ .catch((err) => {
+ console.error("音频播放失败:", err);
+ });
+
+ // 监听播放完毕
+ currentAudio.onended = () => {
+ isPlaying.value = false;
+ };
+
+ source.value = src;
+ };
+
+ // 暂停播放
+ const pause = () => {
+ if (currentAudio) {
+ currentAudio.pause();
+ isPlaying.value = false;
+ }
+ };
+
+ // 停止播放(并清除资源)
+ const stop = () => {
+ if (currentAudio) {
+ currentAudio.pause();
+ currentAudio.currentTime = 0;
+ currentAudio = null;
+ isPlaying.value = false;
+ source.value = null;
+ }
+ };
+
+ return {
+ source,
+ isPlaying,
+ play,
+ pause,
+ stop,
+ };
+}
diff --git a/src/store/bedsideAuxiliaryScreen.ts b/src/store/bedsideAuxiliaryScreen.ts
index b93d6cc..1424463 100644
--- a/src/store/bedsideAuxiliaryScreen.ts
+++ b/src/store/bedsideAuxiliaryScreen.ts
@@ -134,14 +134,19 @@
const dataBody = JSON.parse(datax) as SseMsgData;
console.log("dataBody: ", dataBody);
// 倒计时提示文本
- if (dataBody.倒计时?.提醒文本) {
- const taskTime = dayjs(dataBody.倒计时?.当前服务器时间).add(dataBody.倒计时?.设定提醒倒计时, 'minute')
+ if (dataBody.倒计时?.提醒文本 && Number(dataBody.倒计时?.设定提醒倒计时 > 0)) {
+ const serverTimeRaw = dataBody.倒计时?.当前服务器时间;
+ const reminderMinutes = Number(dataBody.倒计时?.设定提醒倒计时 ?? 0);
+ const serverTimeFormatted = serverTimeRaw.replace(' ', 'T');
+
+ const taskTime = dayjs(serverTimeFormatted).add(reminderMinutes, 'second');
setSyncTask({
deviceCode: dataBody.IOT信息.设备唯一编号,
recordCode: dataBody.透析状态?.透析单编号,
taskDate: taskTime.format('YYYY-MM-DD HH:mm'),
taskName: dataBody.倒计时?.提醒文本,
overdue: false,
+ sync: true,
countdown: dataBody.倒计时?.设定提醒倒计时
})
} else {
diff --git a/src/store/type/bedsideAuxiliaryScreen.type.ts b/src/store/type/bedsideAuxiliaryScreen.type.ts
index 20b3abf..cb59066 100644
--- a/src/store/type/bedsideAuxiliaryScreen.type.ts
+++ b/src/store/type/bedsideAuxiliaryScreen.type.ts
@@ -121,6 +121,7 @@
透析结束时间: number | null;
透析处方备注: string;
最近最大脱水量透析时长: string;
+ 透析龄: number | null;
}
export interface VascularAccess {
@@ -355,6 +356,7 @@
bloodVolumeMonitoring: number | null; // 血容量监测
dialysisFluidFlowRate: number | null; // 透析液流量
ktvList: KtvItem[]; // 实时ktv计算结果列表
+ dialysisAge: number | null, // 透析龄
}
export interface MonitoringRecord {
@@ -393,6 +395,7 @@
dialysisFluidFlowRate: null,
ktvList: [],
prescriptionDialysisDuration: null, // 透析处方的时长(单位:小时)
+ dialysisAge: null,
};
};
@@ -553,6 +556,8 @@
underTreatment.ktvList =
seeMsg.透析状态?.实时ktv计算结果列表
?.realTimeKtvCalcDetailResultInfo ?? [];
+ underTreatment.dialysisAge = seeMsg.透析状态?.透析龄 ?? null;
+
result.underTreatment = underTreatment;
}
}
diff --git a/src/store/type/task.type.ts b/src/store/type/task.type.ts
index fe6fc3c..29b1b04 100644
--- a/src/store/type/task.type.ts
+++ b/src/store/type/task.type.ts
@@ -1,3 +1,11 @@
+import alertbaojin from "@/assets/alert.wav";
+import cxybaojing from "@/assets/cxy.mp3";
+import gybaojing from "@/assets/gy.mp3";
+import kclbaojing from "@/assets/kcl.mp3";
+import tdddbaojing from "@/assets/tzddd.mp3";
+import tzxllbaojing from "@/assets/tzxll.mp3";
+import cgbaojing from "@/assets/cg.mp3";
+
export interface Task {
/** 设备code */
deviceCode: string;
@@ -9,6 +17,55 @@
taskName: string;
/** 是否过期 */
overdue: boolean;
- /** 倒计时,如果存在该字段则表明是远程传过来的 */
+ /** 是否远程传过来的, 只有远程传过来的时间到了再报*/
+ sync: boolean;
+ /** 倒计时,单位秒 */
countdown?: number;
}
+
+export interface TaskItem {
+ label: string;
+ value: string;
+ backgroundColor: string;
+ promptTone: string;
+}
+
+
+export const taskOptions : TaskItem[] = [
+ {
+ label: "测血压",
+ value: "测血压",
+ backgroundColor: "#E6A23C",
+ promptTone: cxybaojing,
+ },
+ {
+ label: "开超滤",
+ value: "开超滤",
+ backgroundColor: "#E6A23C",
+ promptTone: kclbaojing,
+ },
+ {
+ label: "给药",
+ value: "给药",
+ backgroundColor: "#E6A23C",
+ promptTone: gybaojing,
+ },
+ {
+ label: "调电导度",
+ value: "调电导度",
+ backgroundColor: "#E6A23C",
+ promptTone: tdddbaojing,
+ },
+ {
+ label: "调血流量",
+ value: "调血流量",
+ backgroundColor: "#E6A23C",
+ promptTone: tzxllbaojing,
+ },
+ {
+ label: "冲管",
+ value: "冲管",
+ backgroundColor: "#E6A23C",
+ promptTone: cgbaojing,
+ },
+]
\ No newline at end of file
diff --git a/src/utils/httpApi.ts b/src/utils/httpApi.ts
index 8e9e878..4cbc6d7 100644
--- a/src/utils/httpApi.ts
+++ b/src/utils/httpApi.ts
@@ -58,4 +58,22 @@
console.error('Error setting timeout alert:', error);
throw error;
}
-};
\ No newline at end of file
+};
+
+/**
+ * 停止定时任务
+ * @param deviceCode
+ * @returns
+ */
+export const stopTimeoutAlert = async (deviceCode: string) => {
+ try {
+ const response = await axios.post(`${apiBaseUrl}/patient/hemo/med/record/stopTimeoutAlert`, { deviceCode }, {
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ }
+ });
+ return response.data;
+ } catch (error) {
+ throw error;
+ }
+}
\ No newline at end of file
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
index 25c014e..bb22b08 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
@@ -2,31 +2,56 @@
<div class="bedside-auxiliary-screen-header">
<div class="header-left">
<!-- 没有设备编号 -->
- <span v-if="pageType === 0" class="info-text">未绑定设备</span>
+ <span v-if="pageType === pageTypeEnum.NOT_INIT" class="info-text"
+ >未绑定设备</span
+ >
<template v-else>
<!-- 设备号 -->
<span class="info-text">{{
bedsideAuxiliaryScreenStore.deviceData.devicdeNo
}}</span>
<!-- 加载中 -->
- <span v-if="pageType === 1" class="info-text"
+ <span v-if="pageType === pageTypeEnum.LOADING" class="info-text"
>页面初始化中,请耐心等待!</span
>
<!-- 未排班 -->
- <span v-else-if="pageType === 2" class="info-text">当前尚未排班</span>
+ <span
+ v-else-if="pageType === pageTypeEnum.UNPLANNED_SCHEDULE"
+ class="info-text"
+ >当前尚未排班</span
+ >
<!-- 有排班 -->
<template v-else>
<span class="info-text">{{ patientInfo.patientName }}</span>
<span class="info-text">{{ patientInfo.age }}岁</span>
<span class="info-text">{{ patientInfo.gender }}</span>
<span v-if="patientInfo.patFormNumber" class="info-text">
- {{ patientInfo.patForm }}:{{ patientInfo.patFormNumber }}</span
+ {{ patientInfo.patForm }}:{{ patientInfo.patFormNumber }}</span
>
+ <span
+ v-if="
+ pageType === pageTypeEnum.DURING_DIALYSIS &&
+ patientInfo.dialysisAge
+ "
+ class="info-text"
+ >
+ 透析龄: {{ patientInfo.dialysisAge?.years }}年{{
+ patientInfo.dialysisAge?.months
+ }}月
+ </span>
</template>
- {{ taskCountdown }}
</template>
</div>
<div class="header-right">
+ <span
+ v-if="
+ bedsideAuxiliaryScreenStore.taskData &&
+ bedsideAuxiliaryScreenStore.taskData.length > 0
+ "
+ class="countdown"
+ >
+ {{ formattedCountdown }}
+ </span>
<img
:src="atRegularTimeImg"
class="btn-img"
@@ -46,6 +71,8 @@
<SettingDeviceDialog ref="settingDeviceDialogRef" />
<!-- 定时任务组件 -->
<ScheduledTaskDialog ref="scheduledTaskDialogRef" />
+ <!-- 定时任务提醒组件 -->
+ <TaskAlert ref="taskAlertRef" @close="taskAlaetClose" />
</template>
<script lang="ts" setup name="Header">
@@ -65,21 +92,27 @@
const ScheduledTaskDialog = defineAsyncComponent(
() => import("./ScheduledTask.vue")
);
+const TaskAlert = defineAsyncComponent(() => import("./TaskAlart.vue"));
+
import atRegularTimeImg from "../../../../img/dingshi.png";
import setUpImg from "../../../../img/shezhi.png";
import userImg from "../../../../img/user.png";
import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen";
-import { EPatForm } from "@/store/type/bedsideAuxiliaryScreen.type";
+import { EPatForm, EPageType } from "@/store/type/bedsideAuxiliaryScreen.type";
import { ElMessage } from "element-plus";
const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
-let timer: number;
+let timer: ReturnType<typeof setInterval> | null = null;
+const pageTypeEnum = ref(EPageType);
const settingDeviceDialogRef = ref<any>(null);
const scheduledTaskDialogRef = ref<any>(null);
-const taskCountdown = ref(""); // 定时任务倒计时文本
+const taskAlertRef = ref<any>(null);
+
+const countdown = ref(null); // 定时任务的倒计时
+const isTaskAlartIsOpen = ref(false); // 定时任务的提醒弹框是否显示
const pageType = computed(() => {
return bedsideAuxiliaryScreenStore.deviceData.pageType;
@@ -97,32 +130,100 @@
? "门诊号"
: "住院号",
patFormNumber: bedsideAuxiliaryScreenStore.deviceData.patFormNumber,
+ dialysisAge: bedsideAuxiliaryScreenStore.deviceData.underTreatment
+ .dialysisAge
+ ? convertMonths(
+ bedsideAuxiliaryScreenStore.deviceData.underTreatment.dialysisAge
+ )
+ : null,
};
});
-// watch(
-// () => bedsideAuxiliaryScreenStore.taskData,
-// (newData: Task[]) => {
-// console.log('定时任务更新了')
-// if (
-// bedsideAuxiliaryScreenStore.deviceData.deviceCode &&
-// newData.length > 0
-// ) {
-// console.log('newData: ', newData)
-// updateCountdown(newData[0].taskDate);
-// } else {
-// taskCountdown.value = "";
-// }
-// },
-// { deep: true }
-// );
+const formattedCountdown = computed(() => {
+ if (countdown.value == null || countdown.value <= 0) return "0s";
+
+ const minutes = Math.floor(countdown.value / 60);
+ const seconds = countdown.value % 60;
+
+ if (minutes > 0) {
+ return `${minutes}m ${seconds}s`;
+ } else {
+ return `${seconds}s`;
+ }
+});
+
+watch(
+ () => bedsideAuxiliaryScreenStore.taskData?.[0]?.countdown,
+ (val) => {
+ if (typeof val === "number") {
+ startCountdown(val);
+ } else {
+ clearTimer();
+ }
+ },
+ { immediate: true }
+);
+
+watch(countdown, (newVal) => {
+ if (newVal <= 0 && !isTaskAlartIsOpen.value) {
+ isTaskAlartIsOpen.value = true;
+
+ // 弹窗逻辑,替换为你自己的弹窗组件或 UI 框
+ showTaskAlart();
+ }
+});
+
+// 清除定时器函数
+function clearTimer() {
+ if (timer) {
+ clearInterval(timer);
+ timer = null;
+ }
+}
+
+// 启动新的倒计时
+function startCountdown(seconds: number) {
+ clearTimer();
+ countdown.value = seconds;
+
+ timer = setInterval(() => {
+ if (countdown.value > 0) {
+ countdown.value -= 1;
+ } else {
+ clearTimer();
+ }
+ }, 1000);
+}
+
+const convertMonths = (months: number): { years: number; months: number } => {
+ const years = Math.floor(months / 12);
+ const remainingMonths = months % 12;
+ return { years, months: remainingMonths };
+};
+
+const showTaskAlart = () => {
+ clearTimer();
+ taskAlertRef.value.openDialog(
+ bedsideAuxiliaryScreenStore.taskData?.[0]?.taskName
+ );
+};
+
+const taskAlaetClose = () => {
+ clearTimer();
+ bedsideAuxiliaryScreenStore.clearTask();
+ isTaskAlartIsOpen.value = false;
+};
const openSettingDeviceDialog = () => {
settingDeviceDialogRef.value?.openDialog();
};
const openScheduledTaskDialog = () => {
- if (!bedsideAuxiliaryScreenStore.deviceCode || !bedsideAuxiliaryScreenStore.deviceData.deviceCode) return ElMessage.warning('未初始化或正在进行初始化操作中');
+ if (
+ !bedsideAuxiliaryScreenStore.deviceCode ||
+ !bedsideAuxiliaryScreenStore.deviceData.deviceCode
+ )
+ return ElMessage.warning("未初始化或正在进行初始化操作中");
scheduledTaskDialogRef.value?.openDialog();
};
@@ -133,36 +234,8 @@
});
};
-const getCountdown = (taskDate: string) => {
- const now = dayjs();
- const target = dayjs(taskDate).second(0).millisecond(0);
-
- const diff = target.diff(now, "second");
-
- if (diff <= 0) return "";
-
- const minutes = Math.floor(diff / 60);
- const seconds = diff % 60;
-
- return `${minutes}m${seconds}s`;
-};
-
-const updateCountdown = (taskDate: string) => {
- taskCountdown.value = getCountdown(taskDate);
- timer = window.setInterval(updateCountdown, 1000);
-};
-
-onMounted(() => {
- if (
- bedsideAuxiliaryScreenStore.deviceData.deviceCode &&
- bedsideAuxiliaryScreenStore.taskData.length > 0
- ) {
- getCountdown(bedsideAuxiliaryScreenStore.taskData[0].taskDate);
- }
-});
-
onUnmounted(() => {
- timer && clearInterval(timer);
+ clearTimer();
});
</script>
@@ -181,12 +254,12 @@
.info-text {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
- font-size: 11px;
+ font-size: 9px;
color: #ffffff;
text-align: left;
font-style: normal;
&:not(:first-child) {
- margin-left: 6px;
+ margin-left: 4px;
}
}
}
@@ -207,6 +280,15 @@
transition: all 0.2s;
}
+ .countdown {
+ font-family: PingFangSC, PingFang SC;
+ font-weight: 600;
+ font-size: 9px;
+ color: #bb3e3e;
+ line-height: 15rpx;
+ text-align: left;
+ font-style: normal;
+ }
}
}
</style>
\ No newline at end of file
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
index 8111fe6..d931077 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
@@ -13,7 +13,7 @@
>
<template #header>
<div class="scheduled-task-header">
- <span class="header-title">创建定时任务</span>
+ <span class="header-title">{{ title }}</span>
<img
:src="closeImg"
class="header-close"
@@ -26,7 +26,8 @@
<div class="content-left">
<div class="content-left-date">
<TimePicker v-model="timeValue" />
- <div class="date-btn">
+ <!-- 创建的情况 -->
+ <div class="date-btn" v-if="type === 0">
<div
v-for="(item, index) in dateOptions"
:key="index"
@@ -34,6 +35,12 @@
@click="onAddMinutesClick(item)"
>
{{ item.label }}
+ </div>
+ </div>
+ <!-- 查看的情况 -->
+ <div class="countdown" v-else>
+ <div class="countdown-btn">
+ 剩余时间:{{ formattedCountdown }}
</div>
</div>
</div>
@@ -60,7 +67,11 @@
</div>
</div>
</div>
- <div class="content-right"></div>
+ <div class="content-right">
+ <div class="stop-btn" v-if="type === 1" @click="stopTask">
+ 紧急停止
+ </div>
+ </div>
</div>
<template #footer>
<div class="my-button cancel" @click="handleCancel">取消</div>
@@ -77,30 +88,18 @@
</template>
<script lang="ts" setup>
-import { computed, ref } from "vue";
+import { computed, onUnmounted, ref, watch } from "vue";
import dayjs from "dayjs";
-import { setTimeoutAlert } from "@/utils/httpApi";
+import { setTimeoutAlert, stopTimeoutAlert } from "@/utils/httpApi";
import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen";
+import { taskOptions } from "@/store/type/task.type";
+import type { TaskItem } from "@/store/type/task.type";
// @ts-ignore
import TimePicker from "./TimePicker.vue";
import closeImg from "@/img/close.png";
-import alertbaojin from "@/assets/alert.wav";
-import cxybaojing from "@/assets/cxy.mp3";
-import gybaojing from "@/assets/gy.mp3";
-import kclbaojing from "@/assets/kcl.mp3";
-import tdddbaojing from "@/assets/tzddd.mp3";
-import tzxllbaojing from "@/assets/tzxll.mp3";
-import cgbaojing from "@/assets/cg.mp3";
-import { ElMessage } from "element-plus";
-
-interface TaskItem {
- label: string;
- value: string;
- backgroundColor: string;
- promptTone: string;
-}
+import { ElMessage, ElMessageBox } from "element-plus";
interface DateItem {
label: string;
@@ -110,54 +109,12 @@
const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
const isShow = ref(false);
-
+const type = ref<0 | 1>(0); // 0 创建 | 1 查看
const taskName = ref(""); // 任务名称
const isInpDisabled = ref(false); // 输入框是否禁用
-
const timeValue = ref("");
-
const detaCheck = ref<number | null>(); // 这个是判断时间按钮的
-
const loading = ref(false);
-
-const taskOptions = ref<TaskItem[]>([
- {
- label: "测血压",
- value: "测血压",
- backgroundColor: "#E6A23C",
- promptTone: cxybaojing,
- },
- {
- label: "开超滤",
- value: "开超滤",
- backgroundColor: "#E6A23C",
- promptTone: kclbaojing,
- },
- {
- label: "给药",
- value: "给药",
- backgroundColor: "#E6A23C",
- promptTone: gybaojing,
- },
- {
- label: "调电导度",
- value: "调电导度",
- backgroundColor: "#E6A23C",
- promptTone: tdddbaojing,
- },
- {
- label: "调血流量",
- value: "调血流量",
- backgroundColor: "#E6A23C",
- promptTone: tzxllbaojing,
- },
- {
- label: "冲管",
- value: "冲管",
- backgroundColor: "#E6A23C",
- promptTone: cgbaojing,
- },
-]);
const dateOptions = ref<DateItem[]>([
{ label: "15分钟", value: 15 },
@@ -166,14 +123,97 @@
{ label: "60分钟", value: 60 },
]);
-const taskItemCheck = computed(() => {
- return taskOptions.value.find((e) => e.value === taskName.value)?.value || "";
+let timer: ReturnType<typeof setInterval> | null = null;
+const countdown = ref(null); // 定时任务的倒计时
+
+const formattedCountdown = computed(() => {
+ if (countdown.value == null || countdown.value <= 0) return "0s";
+
+ const minutes = Math.floor(countdown.value / 60);
+ const seconds = countdown.value % 60;
+
+ if (minutes > 0) {
+ return `${minutes}m ${seconds}s`;
+ } else {
+ return `${seconds}s`;
+ }
});
+
+const title = computed(() => {
+ return type.value ? "查看定时任务" : "创建定时任务";
+});
+
+const taskItemCheck = computed(() => {
+ return taskOptions.find((e) => e.value === taskName.value)?.value || "";
+});
+
+watch(
+ () => bedsideAuxiliaryScreenStore.taskData?.[0]?.countdown,
+ (val) => {
+ if (typeof val === "number") {
+ startCountdown(val);
+ } else {
+ clearTimer();
+ }
+ },
+ { immediate: true }
+);
+
+watch(countdown, (newVal) => {
+ if (newVal <= 0) {
+ loading.value = false;
+ handleCancel();
+ // ElMessage.warning('当前任务发生变化,请重新设置');
+ }
+});
+
+// 清除定时器函数
+function clearTimer() {
+ if (timer) {
+ clearInterval(timer);
+ timer = null;
+ }
+}
+
+// 启动新的倒计时
+function startCountdown(seconds: number) {
+ clearTimer();
+ countdown.value = seconds;
+
+ timer = setInterval(() => {
+ if (countdown.value > 0) {
+ countdown.value -= 1;
+ } else {
+ clearTimer();
+ }
+ }, 1000);
+}
const openDialog = () => {
isShow.value = true;
- const time = dayjs();
- timeValue.value = time.format("HH:mm");
+ if (
+ !bedsideAuxiliaryScreenStore.taskData ||
+ bedsideAuxiliaryScreenStore.taskData.length <= 0
+ ) {
+ const time = dayjs();
+ timeValue.value = time.format("HH:mm");
+ detaCheck.value = null;
+ isInpDisabled.value = false;
+ taskName.value = "";
+ type.value = 0;
+ } else {
+ const taskDataItem = bedsideAuxiliaryScreenStore.taskData[0];
+ timeValue.value = dayjs(taskDataItem.taskDate).format("HH:mm");
+ // 查是否是定型文的内容
+ const writing = taskOptions.find((e) => e.value === taskDataItem.taskName);
+ if (writing) {
+ taskName.value = writing.value;
+ isInpDisabled.value = true;
+ } else {
+ taskName.value = taskDataItem.taskName;
+ }
+ type.value = 1;
+ }
};
const onStereotypedWritingClick = (item: TaskItem) => {
@@ -187,14 +227,8 @@
};
const onAddMinutesClick = (item: DateItem) => {
- // if (detaCheck.value === item.value) {
- // detaCheck.value = null;
- // timeValue.value = addMinutes(timeValue.value, -item.value)
- // } else {
detaCheck.value = item.value;
timeValue.value = addMinutes(timeValue.value, item.value);
- // console.log('addMinutes(timeValue.value, item.value): ', addMinutes(timeValue.value, item.value))
- // }
};
const addMinutes = (time: string, delta: number): string => {
@@ -246,12 +280,53 @@
taskDate: dayjs(fullDateTime).format("YYYY-MM-DD HH:mm"),
taskName: params.alertText,
overdue: false,
+ sync: false,
+ countdown: diffMinutes * 60,
});
+ // 这里得先把loading关了
+ loading.value = false;
handleCancel();
+ } catch (error) {
+ console.log(error);
} finally {
loading.value = false;
}
};
+
+/** 停止任务 */
+const stopTask = () => {
+ ElMessageBox.confirm(
+ '是否确认停止当前任务?',
+ '提示',
+ {
+ confirmButtonText: '确认',
+ cancelButtonText: '取消',
+ type: 'warning',
+ }
+ )
+ .then(async () => {
+ loading.value = true;
+ try {
+ await stopTimeoutAlert(bedsideAuxiliaryScreenStore.deviceData.deviceCode);
+ bedsideAuxiliaryScreenStore.clearTask();
+ clearTimer();
+ loading.value = false;
+ handleCancel();
+ ElMessage.success('已停止')
+ } catch(error) {
+ ElMessage.error('操作失败:' + error)
+ } finally {
+ loading.value = false;
+ }
+ })
+ .catch(() => {
+
+ })
+};
+
+onUnmounted(() => {
+ clearTimer();
+});
defineExpose({
openDialog,
@@ -316,7 +391,7 @@
}
}
.scheduled-task-content {
- padding: 0 12px 0px;
+ padding: 0 12px 0px 12px;
margin-bottom: 4px;
border-bottom: 1px solid #d8d8d8;
display: flex;
@@ -345,6 +420,27 @@
text-align: center;
font-size: 11px;
background-color: #769aff;
+ }
+ }
+ .countdown {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-left: 5px;
+ .countdown-btn {
+ padding: 0 8px;
+ background: #769aff;
+ box-shadow: 1px 1 0px 0px rgba(130, 126, 126, 0.5);
+ border-radius: 2px;
+ font-family: PingFangSC, PingFang SC;
+ font-weight: 600;
+ font-size: 11px;
+ line-height: 23px;
+ color: #ffffff;
+ text-shadow: 1px 1px 0px rgba(130, 126, 126, 0.5);
+ text-align: left;
+ font-style: normal;
}
}
}
@@ -405,6 +501,19 @@
}
.content-right {
width: 59px;
+ padding: 0 3px;
+ .stop-btn {
+ width: 100%;
+ background: #ff7472;
+ border-radius: 2px;
+ font-family: PingFangSC, PingFang SC;
+ font-weight: 600;
+ font-size: 6px;
+ color: #ffffff;
+ line-height: 18px;
+ text-align: center;
+ font-style: normal;
+ }
}
}
.my-button {
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/TaskAlart.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/TaskAlart.vue
new file mode 100644
index 0000000..cff6899
--- /dev/null
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/TaskAlart.vue
@@ -0,0 +1,184 @@
+<template>
+ <div class="task-alert-container">
+ <el-dialog
+ v-model="show"
+ title="任务提醒"
+ width="60%"
+ :show-close="false"
+ class="task-alert-dialog"
+ :destroy-on-close="true"
+ :close-on-click-modal="false"
+ center
+ >
+ <template #header>
+ <div class="task-alert-header">
+ <span class="header-title">任务提醒</span>
+ <img
+ :src="closeImg"
+ class="header-close"
+ @click="handleCancel"
+ alt=""
+ />
+ </div>
+ </template>
+ <div class="task-alert-content">
+ <span>{{ taskName }}</span>
+ </div>
+ <template #footer>
+ <div class="my-button cancel" @click="handleCancel">关闭</div>
+ <div class="my-button confirm" @click="handleCancel">确认</div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from "vue";
+import closeImg from "@/img/close.png";
+import { useAudioPlayer } from "@/composables/useAudioPlayer";
+import { taskOptions } from "@/store/type/task.type";
+import alertbaojin from "@/assets/alert.wav";
+
+const { play, stop } = useAudioPlayer();
+
+const emit = defineEmits<{
+ (e: "close"): void;
+}>();
+
+const show = ref(false);
+const taskName = ref("");
+
+const openDialog = (name: string) => {
+ // 这里使用传值是为了防止sse任务结束后推送过来的数据没有
+ taskName.value = name;
+ show.value = true;
+ const item = taskOptions.find((e) => e.value === name);
+ if (item) {
+ play(item.promptTone);
+ } else {
+ play(alertbaojin);
+ }
+};
+
+const handleCancel = () => {
+ show.value = false;
+ stop();
+ emit("close");
+};
+
+defineExpose({
+ openDialog,
+});
+</script>
+
+<style lang="less" scoped>
+* {
+ box-sizing: border-box;
+}
+.task-alert-container {
+ ::v-deep(.el-dialog) {
+ padding: 0;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+ ::v-deep(.el-dialog__footer) {
+ padding: 4px;
+ }
+ ::v-deep(.el-upload-dragger) {
+ height: 65px;
+ padding: 0 !important;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ ::v-deep(.el-upload-dragger .el-icon--upload) {
+ display: none;
+ }
+ ::v-deep(.el-dialog__header) {
+ padding-bottom: 6px;
+ }
+ .task-alert-header {
+ position: relative;
+ height: 16px;
+ background: #ff7472;
+ .header-title {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ font-family: AlibabaPuHuiTi, AlibabaPuHuiTi;
+ font-weight: 500;
+ font-size: 8px;
+ color: #ffffff;
+ line-height: 11px;
+ text-align: center;
+ }
+ .header-close {
+ position: absolute;
+ top: 50%;
+ transform: translateY(-50%);
+ right: 6px;
+ width: 15px;
+ height: 15px;
+ transition: transform 0.2s;
+
+ &:active {
+ opacity: 0.6;
+ transform: translateY(-50%) scale(0.95);
+ }
+ }
+ }
+
+ .task-alert-content {
+ height: 50px;
+ max-height: 80px;
+ font-size: 14px;
+ color: #333;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ overflow-y: auto;
+ }
+ .my-button {
+ display: inline-block;
+ border-radius: 2px;
+ padding: 0px 10px;
+ font-family: PingFangSC, PingFang SC;
+ font-weight: 500;
+ font-size: 7px;
+ color: #ffffff;
+ line-height: 16px;
+ letter-spacing: 1px;
+ text-align: center;
+ font-style: normal;
+ transition: transform 0.1s ease, opacity 0.1s ease;
+ cursor: pointer;
+ &:active {
+ transform: scale(0.95);
+ opacity: 0.8;
+ }
+
+ &:not(:first-child) {
+ margin-left: 6px;
+ }
+
+ &.confirm {
+ background: #769aff;
+ }
+ &.cancel {
+ background: #bbc6dd;
+ }
+ &.refresh {
+ background: #e6a23c;
+ }
+ }
+}
+</style>
+<style>
+.task-alert-dialog {
+ margin: 0 auto;
+ top: 50% !important;
+ transform: translateY(-50%) !important;
+}
+</style>
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/pages/SignedIn.vue b/src/views/mobile/bedsideAuxiliaryScreen/pages/SignedIn.vue
index 9e6984d..13d4fd7 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/pages/SignedIn.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/pages/SignedIn.vue
@@ -90,7 +90,7 @@
<span class="item-left"
>平均脱水量:{{ pageData.averageDehydrationRate }} L</span
>
- <span class="item-right">(最近3周9次)</span>
+ <span class="item-right">(最近9次)</span>
</div>
<div class="dehydrated-level-item">
<span class="item-left"
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue b/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue
index f9c8129..765447a 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/pages/UnderTreatment.vue
@@ -208,7 +208,7 @@
<span class="item-left"
>平均脱水量:{{ pageData.averageDehydrationRate }} L</span
>
- <span class="item-right">(最近3周9次)</span>
+ <span class="item-right">(最近9次)</span>
</div>
<div class="dehydrated-level-item">
<div class="item-left">
@@ -243,7 +243,7 @@
<div class="progress-box">
<div class="item-num">
{{ jgTime4(pageData.dialysisDuration) }}/{{
- pageData.prescriptionDialysisDuration
+ pageData.prescriptionDialysisDurationHour
}}:{{ pageData.prescriptionDialysisDurationMin }}
</div>
<ProgressBar
--
Gitblit v1.8.0