From fbb37cbba51cf4fff14cafad214935516434ac92 Mon Sep 17 00:00:00 2001
From: zhangchen <1652267879@qq.com>
Date: 星期五, 25 七月 2025 01:43:50 +0800
Subject: [PATCH] ID1625-暂存

---
 src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue        |   73 ++++++++++++++
 src/store/type/bedsideAuxiliaryScreen.type.ts                        |   51 +++++++---
 src/store/type/task.type.ts                                          |   12 ++
 src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue |   48 +++++++++
 src/store/bedsideAuxiliaryScreen.ts                                  |   69 +++++++++++++
 5 files changed, 229 insertions(+), 24 deletions(-)

diff --git a/src/store/bedsideAuxiliaryScreen.ts b/src/store/bedsideAuxiliaryScreen.ts
index 4f07588..11ff7fa 100644
--- a/src/store/bedsideAuxiliaryScreen.ts
+++ b/src/store/bedsideAuxiliaryScreen.ts
@@ -1,8 +1,10 @@
 import { defineStore } from "pinia";
 import { ref } from "vue";
+import dayjs from "dayjs";
 import cache from "../utils/cache";
 import { EventSourcePolyfill } from "event-source-polyfill";
-import type { BedsideAuxiliaryScreen } from "./type/bedsideAuxiliaryScreen.type";
+import type { BedsideAuxiliaryScreen, SseMsgData } from "./type/bedsideAuxiliaryScreen.type";
+import type { Task } from "./type/task.type";
 import {
   defaultDeviceData,
   defaultconsumablesCollection,
@@ -19,6 +21,9 @@
     /** 设备信息数据 */
     const deviceData = ref<BedsideAuxiliaryScreen>(defaultDeviceData());
 
+    /** 任务列表 */
+    const taskData = ref<Task[]>([]);
+
     /**
      * 设置设备编号
      * @param code
@@ -26,6 +31,47 @@
     const setDeviceCode = (code: string) => {
       deviceCode.value = code;
       cache.set("devcieCode", code);
+    };
+
+    /**
+     * 清除设备信息
+     */
+    const clearDevice = () => {
+      deviceData.value = defaultDeviceData();
+    };
+
+    /**
+     * 追加定时任务
+     * @param taskItem
+     */
+    const pushTask = (taskItem: Task) => {
+      taskData.value.push(taskItem);
+    };
+
+    /**
+     * 是否将当前任务设置为已过期
+     * @param i
+     */
+    // const deleteTask = (i: number) => {
+    //   const task = taskData.value[i];
+    //   if (task) {
+    //     // 二次判断,判断任务时间是否早于或等于当前时间
+    //     const taskTime = dayjs(task.taskDate).second(0).millisecond(0);
+    //     const now = dayjs().second(0).millisecond(0); // 秒和毫秒都去掉
+    //     if (!taskTime.isAfter(now)) {
+    //       taskData.value[i].overdue = true
+    //     }
+    //   }
+    // };
+
+    /** 设置当前定时任务 */
+    const setSyncTask = (taskItem: Task) => {
+      taskData.value = [taskItem];
+    };
+
+    /** 清除当前定时任务 */
+    const clearTask = () => {
+      taskData.value = [];
     };
 
     // SSE 相关状态
@@ -85,10 +131,21 @@
         let end = msg.length - 1;
         if (beng !== -1 && end !== -1 && dif !== -1) {
           const datax = msg.slice(beng, end + 1);
-          const dataBody = JSON.parse(datax);
+          const dataBody = JSON.parse(datax) as SseMsgData;
           console.log("dataBody: ", dataBody);
           // 倒计时提示文本
-          if (dataBody.倒计时?.提示文本) {
+          if (dataBody.倒计时?.提醒文本) {
+            const taskTime = dayjs(dataBody.倒计时?.当前服务器时间).add(dataBody.倒计时?.设定提醒倒计时, 'minute')
+            setSyncTask({
+              deviceCode: dataBody.IOT信息.设备唯一编号,
+              recordCode: dataBody.透析状态?.透析单编号,
+              taskDate: taskTime.format('YYYY-MM-DD HH:mm'),
+              taskName: dataBody.倒计时?.提醒文本,
+              overdue: false,
+              countdown: dataBody.倒计时?.设定提醒倒计时
+            })
+          } else {
+            clearTask();
           }
 
           deviceData.value = formatDeviceData(dataBody);
@@ -104,6 +161,8 @@
         source.value.close();
         source.value = null;
         isConnected.value = false;
+        clearDevice();
+        clearTask();
         console.log("[SSE] 连接已关闭");
       }
     };
@@ -125,6 +184,10 @@
       connect,
       close,
       refresh,
+      taskData,
+      pushTask,
+      setSyncTask,
+      clearTask,
     };
   }
 );
diff --git a/src/store/type/bedsideAuxiliaryScreen.type.ts b/src/store/type/bedsideAuxiliaryScreen.type.ts
index 14fabbc..a5526ef 100644
--- a/src/store/type/bedsideAuxiliaryScreen.type.ts
+++ b/src/store/type/bedsideAuxiliaryScreen.type.ts
@@ -57,7 +57,10 @@
   分区编号: string;
   处方脱水量: number | null;
   实时ktv: string;
-  实时ktv计算结果列表: null | { realTimeKtvCalcDetailResultInfo: KtvItem[], 透析单编号: string };
+  实时ktv计算结果列表: null | {
+    realTimeKtvCalcDetailResultInfo: KtvItem[];
+    透析单编号: string;
+  };
   实时脱水量: number | null;
   干体重: number | null;
   年龄: number | null;
@@ -117,7 +120,7 @@
   透析状态: string; // '0.0'这种格式的,得格式化一下
   透析结束时间: number | null;
   透析处方备注: string;
-  最近最大脱水量透析时长: string
+  最近最大脱水量透析时长: string;
 }
 
 export interface VascularAccess {
@@ -156,15 +159,23 @@
   项目结果: string;
 }
 
+export interface Countdown {
+  当前服务器时间?: string;
+  提醒文本?: string;
+  提醒文本字典?: any[];
+  设定提醒倒计时?: number;
+}
+
 export interface SseMsgData {
   IOT信息: IotInfo | null;
   使用耗材字典: ConsumablesCollection | null; // 当透析状态为治疗中时该字段为null
-  倒计时: "";
+  倒计时: Countdown | null;
   推送类型: PushType;
   透析状态: DialysisStatus | null;
 }
 
 export interface BedsideAuxiliaryScreen {
+  deviceCode: string;
   devicdeNo: string | number;
   recordCode: string;
   patientCode: string;
@@ -294,7 +305,7 @@
     dryWeight: null, // 干体重
     preDialysisWeight: null, // 透前称重
     weightAfterLastDialysis: null, // 上次透后称重
-    weightIncrease: null, // 体重增加  
+    weightIncrease: null, // 体重增加
     weightIncreaseRate: null, // 体重增长率
   };
 };
@@ -374,6 +385,7 @@
     ? EPageType.LOADING
     : EPatForm.OUTPATIENT_SERVICE;
   return {
+    deviceCode: "", // 设备code
     devicdeNo: "", // 设备号
     recordCode: "", // 透析单code
     patientCode: "", // 患者code
@@ -396,10 +408,12 @@
 export const formatDeviceData = (
   seeMsg: SseMsgData
 ): BedsideAuxiliaryScreen => {
+
   const result = defaultDeviceData();
 
   // 默认床号(设备号)
   result.devicdeNo = seeMsg.IOT信息?.床号;
+  result.deviceCode = seeMsg.IOT信息?.设备唯一编号;
 
   if (seeMsg.推送类型 === EPushType.SPHYGMOMANOMETR) {
     result.pageType = EPageType.SPHYGMOMANOMETER;
@@ -456,7 +470,8 @@
           seeMsg.透析状态?.最近最大脱水量日期 ?? "";
         signedIn.dryWeight = seeMsg.透析状态?.干体重 ?? null;
         signedIn.preDialysisWeight = seeMsg.透析状态?.透前称重 ?? null;
-        signedIn.weightAfterLastDialysis = seeMsg.透析状态?.上次透后称重 ?? null;
+        signedIn.weightAfterLastDialysis =
+          seeMsg.透析状态?.上次透后称重 ?? null;
         signedIn.weightIncrease = seeMsg.透析状态?.体重增加 ?? null;
         signedIn.weightIncreaseRate = seeMsg.透析状态?.体重增长率 ?? null;
 
@@ -475,8 +490,10 @@
           seeMsg.透析状态?.最近最大脱水量 ?? "";
         underTreatment.maximumDehydrationCapacityDate =
           seeMsg.透析状态?.最近最大脱水量日期 ?? "";
-        underTreatment.maximumDehydrationDuration = seeMsg.透析状态?.最近最大脱水量透析时长 ?? "";
-        underTreatment.prescriptionRemarks = seeMsg.透析状态?.透析处方备注 ?? "";
+        underTreatment.maximumDehydrationDuration =
+          seeMsg.透析状态?.最近最大脱水量透析时长 ?? "";
+        underTreatment.prescriptionRemarks =
+          seeMsg.透析状态?.透析处方备注 ?? "";
         underTreatment.abnormalItems = seeMsg.透析状态?.异常检验指标 ?? [];
         underTreatment.prescriptionDialysisDuration =
           seeMsg.透析状态?.透析处方的时长 ?? null;
@@ -503,9 +520,13 @@
         underTreatment.monitoringRecord = seeMsg.透析状态?.监测记录列表 ?? [];
         underTreatment.doctorAdvice = seeMsg.透析状态?.透析单医嘱列表 ?? [];
         underTreatment.bloodFlow = "";
-        underTreatment.dialysisFluidFlowRate = seeMsg.透析状态?.iot_血流量 ?? null;
-        underTreatment.bloodVolumeMonitoring = seeMsg.透析状态?.iot_透析液流速 ?? null;
-        underTreatment.ktvList = seeMsg.透析状态?.实时ktv计算结果列表?.realTimeKtvCalcDetailResultInfo ?? [];
+        underTreatment.dialysisFluidFlowRate =
+          seeMsg.透析状态?.iot_血流量 ?? null;
+        underTreatment.bloodVolumeMonitoring =
+          seeMsg.透析状态?.iot_透析液流速 ?? null;
+        underTreatment.ktvList =
+          seeMsg.透析状态?.实时ktv计算结果列表
+            ?.realTimeKtvCalcDetailResultInfo ?? [];
         result.underTreatment = underTreatment;
       }
     }
@@ -563,10 +584,10 @@
 
 export const formatSubstituteMode = (mode: string) => {
   let result = "";
-  if (mode === '前置换') {
-    result = '前'
-  } else if (mode === '后置换') {
-    result = '后'
+  if (mode === "前置换") {
+    result = "前";
+  } else if (mode === "后置换") {
+    result = "后";
   }
   return result;
-}
+};
diff --git a/src/store/type/task.type.ts b/src/store/type/task.type.ts
new file mode 100644
index 0000000..75b2189
--- /dev/null
+++ b/src/store/type/task.type.ts
@@ -0,0 +1,12 @@
+export interface Task {
+  /** 设备code */
+  deviceCode: string;
+  /** 透析单code */
+  recordCode?: string;
+  /** 任务提醒时间 */
+  taskDate: string;
+  /** 任务名称 */
+  taskName: string;
+  /** 是否过期 */
+  overdue: boolean;
+}
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
index f8d9a68..6efe7bc 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/Header.vue
@@ -23,10 +23,16 @@
             {{ patientInfo.patForm }}:{{ patientInfo.patFormNumber }}</span
           >
         </template>
+        {{ taskCountdown }}
       </template>
     </div>
     <div class="header-right">
-      <img :src="atRegularTimeImg" class="btn-img" alt="" @click="openScheduledTaskDialog" />
+      <img
+        :src="atRegularTimeImg"
+        class="btn-img"
+        alt=""
+        @click="openScheduledTaskDialog"
+      />
       <img
         :src="setUpImg"
         class="btn-img"
@@ -43,13 +49,22 @@
 </template>
 
 <script lang="ts" setup name="Header">
-import { ref, computed, defineAsyncComponent } from "vue";
+import {
+  ref,
+  computed,
+  defineAsyncComponent,
+  onMounted,
+  onUnmounted,
+  watch,
+} from "vue";
+import dayjs from "dayjs";
+import type { Task } from "@/store/type/task.type";
 const SettingDeviceDialog = defineAsyncComponent(
   () => import("./SettingDeviceDialog.vue")
 );
 const ScheduledTaskDialog = defineAsyncComponent(
   () => import("./ScheduledTask.vue")
-)
+);
 import atRegularTimeImg from "../../../../img/dingshi.png";
 import setUpImg from "../../../../img/shezhi.png";
 import userImg from "../../../../img/user.png";
@@ -60,8 +75,11 @@
 
 const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
 
+let timer: number;
+
 const settingDeviceDialogRef = ref<any>(null);
 const scheduledTaskDialogRef = ref<any>(null);
+const taskCountdown = ref(""); // 定时任务倒计时文本
 
 const pageType = computed(() => {
   return bedsideAuxiliaryScreenStore.deviceData.pageType;
@@ -82,6 +100,23 @@
   };
 });
 
+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 openSettingDeviceDialog = () => {
   settingDeviceDialogRef.value?.openDialog();
 };
@@ -96,6 +131,38 @@
     type: "warning",
   });
 };
+
+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);
+});
 </script>
 
 <style lang="less" scoped>
diff --git a/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue b/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
index 96a2c1a..9a4e12b 100644
--- a/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
+++ b/src/views/mobile/bedsideAuxiliaryScreen/components/ScheduledTask.vue
@@ -38,7 +38,7 @@
           <div class="content-left-stereotyped-writing">
             <div class="stereotyped-writing">
               <input
-                v-model="taskName"
+                v-model.trim="taskName"
                 type="text"
                 :disabled="isInpDisabled"
                 class="stereotyped-writing-input"
@@ -70,6 +70,10 @@
 
 <script lang="ts" setup>
 import { computed, ref } from "vue";
+import dayjs from "dayjs";
+import { setTimeoutAlert } from "@/utils/httpApi";
+import { useBedsideAuxiliaryScreenStore } from "@/store/bedsideAuxiliaryScreen";
+
 // @ts-ignore
 import TimePicker from "./TimePicker.vue";
 
@@ -81,6 +85,7 @@
 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;
@@ -94,14 +99,18 @@
   value: number;
 }
 
+const bedsideAuxiliaryScreenStore = useBedsideAuxiliaryScreenStore();
+
 const isShow = ref(false);
 
 const taskName = ref(""); // 任务名称
 const isInpDisabled = ref(false); // 输入框是否禁用
 
-const timeValue = ref("19:16");
+const timeValue = ref("");
 
 const detaCheck = ref<number | null>(); // 这个是判断时间按钮的
+
+const loading = ref(false);
 
 const taskOptions = ref<TaskItem[]>([
   {
@@ -155,6 +164,8 @@
 
 const openDialog = () => {
   isShow.value = true;
+  const time = dayjs();
+  timeValue.value = time.format("HH:mm");
 };
 
 const onStereotypedWritingClick = (item: TaskItem) => {
@@ -197,7 +208,38 @@
   isShow.value = false;
 };
 
-const handleConfirm = () => {};
+const handleConfirm = async () => {
+  const today = dayjs().format("YYYY-MM-DD");
+  const fullDateTime = dayjs(`${today} ${timeValue.value}`).second(0).millisecond(0); // 秒和毫秒都去掉,要不然间隔短了就是0分钟
+
+  const now = dayjs().second(0).millisecond(0);; // 秒和毫秒都去掉
+  if (!fullDateTime.isAfter(now))
+    return ElMessage.warning("任务提醒时间不能早于或等于当前时间");
+  if (!taskName.value) return ElMessage.warning("任务内容不能为空");
+  loading.value = true;
+  try {
+    const diffMinutes = fullDateTime.diff(now, "minute");
+    const params = {
+      deviceCode: bedsideAuxiliaryScreenStore.deviceData.deviceCode,
+      minutes: diffMinutes,
+      alertText: taskName.value,
+    }
+    const recordCode = bedsideAuxiliaryScreenStore.deviceData.recordCode;
+    const { data, message } = await setTimeoutAlert(params);
+    if (data !== "OK") return ElMessage.warning(message);
+    ElMessage.success('操作成功');
+    bedsideAuxiliaryScreenStore.setSyncTask({
+        deviceCode: params.deviceCode,
+        recordCode: recordCode,
+        taskDate: dayjs(fullDateTime).format("YYYY-MM-DD HH:mm"),
+        taskName: params.alertText,
+        overdue: false
+    });
+    handleCancel();
+  } finally {
+    loading.value = false;
+  }
+};
 
 defineExpose({
   openDialog,

--
Gitblit v1.8.0